@zoralabs/cli 0.3.1 → 1.0.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 +17 -16
- package/dist/index.js +456 -172
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ A command-line tool for interacting with the [Zora](https://zora.co) protocol. E
|
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
|
-
Requires **Node.js
|
|
9
|
+
Requires **Node.js 20+**.
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
npm install -g @zoralabs/cli
|
|
@@ -15,6 +15,9 @@ npm install -g @zoralabs/cli
|
|
|
15
15
|
## Quick start
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
+
# Guided first-time setup — wallet, API key, and deposit instructions
|
|
19
|
+
zora setup
|
|
20
|
+
|
|
18
21
|
# Browse trending coins
|
|
19
22
|
zora explore
|
|
20
23
|
|
|
@@ -31,41 +34,39 @@ All commands support `--json` for machine-readable output. Commands with live da
|
|
|
31
34
|
|
|
32
35
|
| Command | Description | Wallet required |
|
|
33
36
|
| --------------- | --------------------------------------------------------- | --------------- |
|
|
37
|
+
| `setup` | Guided first-time setup (wallet + API key + deposit info) | — |
|
|
34
38
|
| `explore` | Browse top, new, and highest volume coins | No |
|
|
35
39
|
| `get` | Look up a coin by address or name | No |
|
|
36
40
|
| `price-history` | Display price history for a coin | No |
|
|
37
41
|
| `auth` | Configure or check API key status | No |
|
|
38
42
|
| `profile` | View creator or user profiles | No |
|
|
39
|
-
| `setup` | Set up a wallet (generate or import private key) | — |
|
|
40
43
|
| `buy` | Buy a coin | Yes |
|
|
41
44
|
| `sell` | Sell a coin | Yes |
|
|
42
45
|
| `balance` | Show wallet balances (ETH, USDC, ZORA) and coin positions | Yes |
|
|
43
|
-
| `wallet` | Show wallet address,
|
|
46
|
+
| `wallet` | Show wallet address, export key, or configure wallet | Yes |
|
|
44
47
|
| `send` | Send tokens to another address | Yes |
|
|
45
48
|
|
|
46
49
|
Run `zora --help` or `zora <command> --help` for detailed usage.
|
|
47
50
|
|
|
48
|
-
##
|
|
51
|
+
## Setup
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
`zora setup` walks through three steps: wallet configuration, API key (optional), and deposit instructions. It is re-runnable — existing configuration is detected and can be kept or overwritten.
|
|
51
54
|
|
|
52
55
|
```bash
|
|
53
|
-
zora setup # interactive
|
|
54
|
-
zora setup --create # generate a new key
|
|
56
|
+
zora setup # interactive 3-step flow
|
|
57
|
+
zora setup --create # skip wallet prompt, generate a new key
|
|
58
|
+
zora setup --yes # non-interactive, accept all defaults
|
|
59
|
+
zora setup --force # overwrite existing wallet and API key
|
|
55
60
|
```
|
|
56
61
|
|
|
57
|
-
The private key is stored locally at `~/.config/zora/wallet.json` with restricted permissions.
|
|
58
|
-
|
|
59
|
-
## API key (optional)
|
|
62
|
+
The private key is stored locally at `~/.config/zora/wallet.json` with restricted permissions. `ZORA_PRIVATE_KEY` and `ZORA_API_KEY` environment variables take precedence over saved config files.
|
|
60
63
|
|
|
61
|
-
|
|
64
|
+
### Advanced
|
|
62
65
|
|
|
63
|
-
|
|
64
|
-
zora auth configure # save the key
|
|
65
|
-
zora auth status # check current config
|
|
66
|
-
```
|
|
66
|
+
To configure wallet or API key individually (without running the full setup flow). All commands work without an API key but may be rate-limited:
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
- `zora wallet configure` — create or import a wallet (`--create`, `--force`)
|
|
69
|
+
- `zora auth configure` — save an API key; `zora auth status` — check current config
|
|
69
70
|
|
|
70
71
|
## Documentation
|
|
71
72
|
|
package/dist/index.js
CHANGED
|
@@ -285,6 +285,10 @@ var passwordOrFail = async (json, opts, nonInteractive) => {
|
|
|
285
285
|
}
|
|
286
286
|
return password(opts);
|
|
287
287
|
};
|
|
288
|
+
var passwordOrSkip = async (opts, nonInteractive) => {
|
|
289
|
+
if (nonInteractive) return "";
|
|
290
|
+
return password(opts);
|
|
291
|
+
};
|
|
288
292
|
|
|
289
293
|
// src/lib/analytics.ts
|
|
290
294
|
import { PostHog } from "posthog-node";
|
|
@@ -437,7 +441,7 @@ var getClient = () => {
|
|
|
437
441
|
return client;
|
|
438
442
|
};
|
|
439
443
|
var commonProperties = () => ({
|
|
440
|
-
cli_version: true ? "0.
|
|
444
|
+
cli_version: true ? "1.0.0" : "development",
|
|
441
445
|
os: process.platform,
|
|
442
446
|
arch: process.arch,
|
|
443
447
|
node_version: process.version
|
|
@@ -500,7 +504,9 @@ var shutdownAnalytics = async () => {
|
|
|
500
504
|
// src/commands/auth.ts
|
|
501
505
|
var authCommand = new Command("auth").description(
|
|
502
506
|
"Manage API key authentication.\nAPI key is optional \u2014 without one, requests are rate-limited.\nGet a key at https://zora.co/settings/developer"
|
|
503
|
-
)
|
|
507
|
+
).action(function() {
|
|
508
|
+
this.outputHelp();
|
|
509
|
+
});
|
|
504
510
|
authCommand.command("configure").description("Set your Zora API key").option("--yes", "Skip interactive prompt and execute directly").action(async function() {
|
|
505
511
|
const json = getJson(this);
|
|
506
512
|
const nonInteractive = getYes(this);
|
|
@@ -747,6 +753,13 @@ var formatAmountDisplay = (amount, decimals) => {
|
|
|
747
753
|
maximumFractionDigits: 2
|
|
748
754
|
}).format(Number(formatted));
|
|
749
755
|
};
|
|
756
|
+
function computeMarketCapChange24h(marketCap, marketCapDelta24h) {
|
|
757
|
+
if (marketCap === null || marketCapDelta24h === null || marketCap - marketCapDelta24h === 0)
|
|
758
|
+
return null;
|
|
759
|
+
return Number(
|
|
760
|
+
(marketCapDelta24h / (marketCap - marketCapDelta24h) * 100).toFixed(4)
|
|
761
|
+
);
|
|
762
|
+
}
|
|
750
763
|
var truncateAddress = (address) => `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
|
|
751
764
|
|
|
752
765
|
// src/lib/balance-format.ts
|
|
@@ -1166,11 +1179,10 @@ var formatBalanceJson = (balance, rank) => {
|
|
|
1166
1179
|
const totalVolume = balance.coin?.totalVolume ? Number(balance.coin.totalVolume) : null;
|
|
1167
1180
|
const priceUsdValue = priceUsd ? Number(priceUsd) : null;
|
|
1168
1181
|
const usdValue = priceUsdValue !== null ? Number((parseRawBalance(balance.balance) * priceUsdValue).toFixed(6)) : null;
|
|
1169
|
-
const marketCapChange24h =
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
) : null;
|
|
1182
|
+
const marketCapChange24h = computeMarketCapChange24h(
|
|
1183
|
+
marketCap,
|
|
1184
|
+
marketCapDelta24h
|
|
1185
|
+
);
|
|
1174
1186
|
return {
|
|
1175
1187
|
rank,
|
|
1176
1188
|
name: balance.coin?.name ?? null,
|
|
@@ -1193,13 +1205,9 @@ var formatBalanceJson = (balance, rank) => {
|
|
|
1193
1205
|
function resolveContext(json) {
|
|
1194
1206
|
const account = resolveAccount(json);
|
|
1195
1207
|
const apiKey = getApiKey();
|
|
1196
|
-
if (
|
|
1197
|
-
|
|
1198
|
-
json,
|
|
1199
|
-
"Not authenticated. Run 'zora auth configure' to set your API key."
|
|
1200
|
-
);
|
|
1208
|
+
if (apiKey) {
|
|
1209
|
+
setApiKey(apiKey);
|
|
1201
1210
|
}
|
|
1202
|
-
setApiKey(apiKey);
|
|
1203
1211
|
return account;
|
|
1204
1212
|
}
|
|
1205
1213
|
function renderWallet(json, walletResult) {
|
|
@@ -1674,7 +1682,9 @@ var printQuote = (json, info) => {
|
|
|
1674
1682
|
Buy \x1B[1m${info.coinName}\x1B[0m`);
|
|
1675
1683
|
console.log(` ${info.coinType} \xB7 ${info.address}
|
|
1676
1684
|
`);
|
|
1677
|
-
console.log(
|
|
1685
|
+
console.log(
|
|
1686
|
+
` Amount ${spendFormatted} ${info.inputTokenSymbol}${info.amountUsd ? ` (${info.amountUsd})` : ""}`
|
|
1687
|
+
);
|
|
1678
1688
|
console.log(` You get ~${coinsFormatted} ${info.coinSymbol}`);
|
|
1679
1689
|
console.log(` Slippage ${info.slippagePct}%
|
|
1680
1690
|
`);
|
|
@@ -1708,7 +1718,9 @@ var printTradeResult = (json, info) => {
|
|
|
1708
1718
|
Bought \x1B[1m${info.coinName}\x1B[0m`);
|
|
1709
1719
|
console.log(` ${info.coinType} \xB7 ${info.address}
|
|
1710
1720
|
`);
|
|
1711
|
-
console.log(
|
|
1721
|
+
console.log(
|
|
1722
|
+
` Spent ${spentFormatted} ${info.inputTokenSymbol}${info.amountUsd ? ` (${info.amountUsd})` : ""}`
|
|
1723
|
+
);
|
|
1712
1724
|
console.log(` Received ${receivedFormatted} ${info.coinSymbol}`);
|
|
1713
1725
|
console.log(` Tx ${info.txHash}
|
|
1714
1726
|
`);
|
|
@@ -2150,8 +2162,9 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
|
|
|
2150
2162
|
amountOut,
|
|
2151
2163
|
slippagePct
|
|
2152
2164
|
};
|
|
2165
|
+
const amountUsd = swapAmountUsd != null && inputToken.fixedPriceUsd == null ? `${amountMode === "usd" ? "" : "~"}${formatUsd(swapAmountUsd)}` : void 0;
|
|
2153
2166
|
if (opts.quote) {
|
|
2154
|
-
printQuote(json, quoteInfo);
|
|
2167
|
+
printQuote(json, { ...quoteInfo, amountUsd });
|
|
2155
2168
|
track("cli_buy", {
|
|
2156
2169
|
action: "quote",
|
|
2157
2170
|
coin_address: coinAddress,
|
|
@@ -2167,7 +2180,7 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
|
|
|
2167
2180
|
return;
|
|
2168
2181
|
}
|
|
2169
2182
|
if (!opts.yes) {
|
|
2170
|
-
printQuote(false, quoteInfo);
|
|
2183
|
+
printQuote(false, { ...quoteInfo, amountUsd });
|
|
2171
2184
|
const ok = await confirm2({
|
|
2172
2185
|
message: "Confirm?",
|
|
2173
2186
|
default: false
|
|
@@ -2226,6 +2239,7 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
|
|
|
2226
2239
|
coinSymbol,
|
|
2227
2240
|
coinType,
|
|
2228
2241
|
address: coinAddress,
|
|
2242
|
+
amountUsd,
|
|
2229
2243
|
amountIn,
|
|
2230
2244
|
inputTokenSymbol: inputToken.symbol,
|
|
2231
2245
|
inputTokenDecimals: inputToken.decimals,
|
|
@@ -2548,6 +2562,47 @@ var ExploreView = ({
|
|
|
2548
2562
|
|
|
2549
2563
|
// src/commands/explore.tsx
|
|
2550
2564
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
2565
|
+
var formatExploreCoinJson = (node) => {
|
|
2566
|
+
const marketCap = node.marketCap ? Number(node.marketCap) : null;
|
|
2567
|
+
const marketCapDelta24h = node.marketCapDelta24h ? Number(node.marketCapDelta24h) : null;
|
|
2568
|
+
const marketCapChange24h = computeMarketCapChange24h(
|
|
2569
|
+
marketCap,
|
|
2570
|
+
marketCapDelta24h
|
|
2571
|
+
);
|
|
2572
|
+
const priceUsd = node.tokenPrice?.priceInUsdc ? Number(node.tokenPrice.priceInUsdc) : null;
|
|
2573
|
+
const coinType = node.coinType ? COIN_TYPE_DISPLAY[node.coinType] ?? node.coinType : null;
|
|
2574
|
+
const socials = node.creatorProfile?.socialAccounts;
|
|
2575
|
+
const socialAccounts = socials ? {
|
|
2576
|
+
instagram: socials.instagram ?? null,
|
|
2577
|
+
tiktok: socials.tiktok ?? null,
|
|
2578
|
+
twitter: socials.twitter ?? null,
|
|
2579
|
+
farcaster: socials.farcaster ?? null
|
|
2580
|
+
} : null;
|
|
2581
|
+
return {
|
|
2582
|
+
name: node.name ?? null,
|
|
2583
|
+
description: node.description ?? null,
|
|
2584
|
+
symbol: node.symbol ?? null,
|
|
2585
|
+
coinType,
|
|
2586
|
+
chainId: node.chainId ?? null,
|
|
2587
|
+
address: node.address ?? null,
|
|
2588
|
+
platformBlocked: node.platformBlocked ?? false,
|
|
2589
|
+
totalSupply: node.totalSupply ?? null,
|
|
2590
|
+
creatorAddress: node.creatorAddress ?? null,
|
|
2591
|
+
creatorHandle: node.creatorProfile?.handle ?? null,
|
|
2592
|
+
socialAccounts,
|
|
2593
|
+
mediaContentMimeType: node.mediaContent?.mimeType ?? null,
|
|
2594
|
+
mediaContentOriginalUri: node.mediaContent?.originalUri ?? null,
|
|
2595
|
+
previewImage: node.mediaContent?.previewImage?.medium ?? null,
|
|
2596
|
+
priceUsd,
|
|
2597
|
+
marketCap,
|
|
2598
|
+
marketCapDelta24h,
|
|
2599
|
+
marketCapChange24h,
|
|
2600
|
+
volume24h: node.volume24h ? Number(node.volume24h) : null,
|
|
2601
|
+
totalVolume: node.totalVolume ? Number(node.totalVolume) : null,
|
|
2602
|
+
uniqueHolders: node.uniqueHolders ?? null,
|
|
2603
|
+
createdAt: node.createdAt ?? null
|
|
2604
|
+
};
|
|
2605
|
+
};
|
|
2551
2606
|
var QUERY_MAP = {
|
|
2552
2607
|
mcap: {
|
|
2553
2608
|
all: getMostValuableAll,
|
|
@@ -2659,7 +2714,10 @@ var exploreCommand = new Command4("explore").description("Browse top, new, and h
|
|
|
2659
2714
|
outputErrorAndExit(json, `API error: ${msg}`);
|
|
2660
2715
|
}
|
|
2661
2716
|
const edges = response.data?.exploreList?.edges ?? [];
|
|
2662
|
-
const
|
|
2717
|
+
const rawNodes = edges.map((e) => e.node);
|
|
2718
|
+
const coins = rawNodes.map(
|
|
2719
|
+
(node, i) => formatExploreCoinJson(node)
|
|
2720
|
+
);
|
|
2663
2721
|
const pageInfo = response.data?.exploreList?.pageInfo;
|
|
2664
2722
|
outputJson({ coins, pageInfo: pageInfo ?? null });
|
|
2665
2723
|
track("cli_explore", {
|
|
@@ -3243,7 +3301,7 @@ function printSellQuote(output, info) {
|
|
|
3243
3301
|
`);
|
|
3244
3302
|
console.log(` Amount ${info.soldFormatted} ${info.coinSymbol}`);
|
|
3245
3303
|
console.log(
|
|
3246
|
-
` You get ~${info.receivedFormatted} ${info.outputSymbol}`
|
|
3304
|
+
` You get ~${info.receivedFormatted} ${info.outputSymbol}${info.receivedUsd ? ` (${info.receivedUsd})` : ""}`
|
|
3247
3305
|
);
|
|
3248
3306
|
console.log(` Slippage ${info.slippagePct}%
|
|
3249
3307
|
`);
|
|
@@ -3283,7 +3341,7 @@ function printSellResult(output, info) {
|
|
|
3283
3341
|
`);
|
|
3284
3342
|
console.log(` Sold ${info.soldFormatted} ${info.coinSymbol}`);
|
|
3285
3343
|
console.log(
|
|
3286
|
-
` Received ${info.receivedSource === "quote" ? "~" : ""}${receivedFormatted} ${info.outputSymbol}`
|
|
3344
|
+
` Received ${info.receivedSource === "quote" ? "~" : ""}${receivedFormatted} ${info.outputSymbol}${info.receivedUsd ? ` (${info.receivedUsd})` : ""}`
|
|
3287
3345
|
);
|
|
3288
3346
|
if (info.receivedSource === "quote") {
|
|
3289
3347
|
console.log(" Note based on quote");
|
|
@@ -3409,22 +3467,22 @@ var sellCommand = new Command7("sell").description("Sell a coin").argument(
|
|
|
3409
3467
|
);
|
|
3410
3468
|
return;
|
|
3411
3469
|
}
|
|
3412
|
-
const
|
|
3413
|
-
if (
|
|
3470
|
+
const coinPriceUsd2 = await fetchTokenPriceUsd(coinAddress);
|
|
3471
|
+
if (coinPriceUsd2 === null || coinPriceUsd2 <= 0) {
|
|
3414
3472
|
outputErrorAndExit(
|
|
3415
3473
|
json,
|
|
3416
3474
|
`Failed to fetch ${coinSymbol} price for USD conversion.`
|
|
3417
3475
|
);
|
|
3418
3476
|
return;
|
|
3419
3477
|
}
|
|
3420
|
-
const coinAmount = usdVal /
|
|
3478
|
+
const coinAmount = usdVal / coinPriceUsd2;
|
|
3421
3479
|
amountIn = parseUnits2(coinAmount.toFixed(coinDecimals), coinDecimals);
|
|
3422
3480
|
if (amountIn === 0n) {
|
|
3423
3481
|
outputErrorAndExit(json, "Calculated amount is zero. USD too small.");
|
|
3424
3482
|
}
|
|
3425
3483
|
if (debug) {
|
|
3426
3484
|
console.error(
|
|
3427
|
-
`[debug] $${usdVal} USD = ${formatUnits5(amountIn, coinDecimals)} ${coinSymbol} (coin price: $${
|
|
3485
|
+
`[debug] $${usdVal} USD = ${formatUnits5(amountIn, coinDecimals)} ${coinSymbol} (coin price: $${coinPriceUsd2})`
|
|
3428
3486
|
);
|
|
3429
3487
|
}
|
|
3430
3488
|
} else if (amountMode === "amount") {
|
|
@@ -3472,18 +3530,19 @@ var sellCommand = new Command7("sell").description("Sell a coin").argument(
|
|
|
3472
3530
|
}
|
|
3473
3531
|
}
|
|
3474
3532
|
}
|
|
3533
|
+
const needsCoinPrice = amountMode !== "usd";
|
|
3534
|
+
const needsOutputPrice = outputToken.fixedPriceUsd == null;
|
|
3535
|
+
const [coinPriceUsd, outputPriceUsd] = await Promise.all([
|
|
3536
|
+
needsCoinPrice ? fetchTokenPriceUsd(coinAddress) : Promise.resolve(null),
|
|
3537
|
+
needsOutputPrice ? fetchTokenPriceUsd(outputToken.priceAddress) : Promise.resolve(null)
|
|
3538
|
+
]);
|
|
3475
3539
|
let swapAmountUsd;
|
|
3476
3540
|
if (amountMode === "usd") {
|
|
3477
3541
|
swapAmountUsd = parsePercentageLikeValue(opts.usd);
|
|
3478
|
-
} else {
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
(Number(formatUnits5(amountIn, coinDecimals)) * coinPriceUsd).toFixed(
|
|
3483
|
-
2
|
|
3484
|
-
)
|
|
3485
|
-
);
|
|
3486
|
-
}
|
|
3542
|
+
} else if (coinPriceUsd !== null && coinPriceUsd > 0) {
|
|
3543
|
+
swapAmountUsd = Number(
|
|
3544
|
+
(Number(formatUnits5(amountIn, coinDecimals)) * coinPriceUsd).toFixed(2)
|
|
3545
|
+
);
|
|
3487
3546
|
}
|
|
3488
3547
|
const tradeParameters = {
|
|
3489
3548
|
sell: { type: "erc20", address: coinAddress },
|
|
@@ -3541,6 +3600,13 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
|
|
|
3541
3600
|
BigInt(quoteAmountOut),
|
|
3542
3601
|
outputToken.decimals
|
|
3543
3602
|
);
|
|
3603
|
+
let receivedUsd;
|
|
3604
|
+
if (outputPriceUsd != null) {
|
|
3605
|
+
const outAmount = Number(
|
|
3606
|
+
formatUnits5(BigInt(quoteAmountOut), outputToken.decimals)
|
|
3607
|
+
);
|
|
3608
|
+
receivedUsd = `~${formatUsd(outAmount * outputPriceUsd)}`;
|
|
3609
|
+
}
|
|
3544
3610
|
if (opts.quote) {
|
|
3545
3611
|
printSellQuote(output, {
|
|
3546
3612
|
coinName,
|
|
@@ -3554,7 +3620,8 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
|
|
|
3554
3620
|
quoteAmountOut,
|
|
3555
3621
|
outputSymbol: outputToken.symbol,
|
|
3556
3622
|
outputDecimals: outputToken.decimals,
|
|
3557
|
-
slippagePct
|
|
3623
|
+
slippagePct,
|
|
3624
|
+
receivedUsd
|
|
3558
3625
|
});
|
|
3559
3626
|
track("cli_sell", {
|
|
3560
3627
|
action: "quote",
|
|
@@ -3584,7 +3651,8 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
|
|
|
3584
3651
|
quoteAmountOut,
|
|
3585
3652
|
outputSymbol: outputToken.symbol,
|
|
3586
3653
|
outputDecimals: outputToken.decimals,
|
|
3587
|
-
slippagePct
|
|
3654
|
+
slippagePct,
|
|
3655
|
+
receivedUsd
|
|
3588
3656
|
});
|
|
3589
3657
|
const ok = await confirm3({
|
|
3590
3658
|
message: "Confirm?",
|
|
@@ -3641,6 +3709,12 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
|
|
|
3641
3709
|
} catch {
|
|
3642
3710
|
}
|
|
3643
3711
|
}
|
|
3712
|
+
if (outputPriceUsd != null) {
|
|
3713
|
+
const actualAmount = Number(
|
|
3714
|
+
formatUnits5(receivedAmountOut, outputToken.decimals)
|
|
3715
|
+
);
|
|
3716
|
+
receivedUsd = `~${formatUsd(actualAmount * outputPriceUsd)}`;
|
|
3717
|
+
}
|
|
3644
3718
|
printSellResult(output, {
|
|
3645
3719
|
coinName,
|
|
3646
3720
|
coinSymbol,
|
|
@@ -3653,7 +3727,8 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
|
|
|
3653
3727
|
outputSymbol: outputToken.symbol,
|
|
3654
3728
|
outputDecimals: outputToken.decimals,
|
|
3655
3729
|
receivedSource,
|
|
3656
|
-
txHash
|
|
3730
|
+
txHash,
|
|
3731
|
+
receivedUsd
|
|
3657
3732
|
});
|
|
3658
3733
|
track("cli_sell", {
|
|
3659
3734
|
action: "trade",
|
|
@@ -3867,15 +3942,11 @@ var extractErrorMessage2 = (error) => {
|
|
|
3867
3942
|
}
|
|
3868
3943
|
return JSON.stringify(error);
|
|
3869
3944
|
};
|
|
3870
|
-
var resolveApiKey = (
|
|
3945
|
+
var resolveApiKey = () => {
|
|
3871
3946
|
const apiKey = getApiKey();
|
|
3872
|
-
if (
|
|
3873
|
-
|
|
3874
|
-
json,
|
|
3875
|
-
"Not authenticated. Run 'zora auth configure' to set your API key."
|
|
3876
|
-
);
|
|
3947
|
+
if (apiKey) {
|
|
3948
|
+
setApiKey7(apiKey);
|
|
3877
3949
|
}
|
|
3878
|
-
setApiKey7(apiKey);
|
|
3879
3950
|
};
|
|
3880
3951
|
var formatPostJson = (post, rank) => ({
|
|
3881
3952
|
rank,
|
|
@@ -3951,7 +4022,7 @@ var profileCommand = new Command8("profile").description("View profile activity
|
|
|
3951
4022
|
).action(async function(identifierArg) {
|
|
3952
4023
|
const output = getOutputMode(this, "live");
|
|
3953
4024
|
const json = output === "json";
|
|
3954
|
-
resolveApiKey(
|
|
4025
|
+
resolveApiKey();
|
|
3955
4026
|
const { live, intervalSeconds } = getLiveConfig(this, output);
|
|
3956
4027
|
let identifier = identifierArg;
|
|
3957
4028
|
if (!identifier) {
|
|
@@ -4520,32 +4591,33 @@ var sendCommand = new Command9("send").description("Send coins or ETH to an addr
|
|
|
4520
4591
|
}
|
|
4521
4592
|
});
|
|
4522
4593
|
|
|
4523
|
-
// src/commands/setup.
|
|
4594
|
+
// src/commands/setup.tsx
|
|
4524
4595
|
import { Command as Command10 } from "commander";
|
|
4525
|
-
import {
|
|
4596
|
+
import { Text as Text9, Box as Box9 } from "ink";
|
|
4526
4597
|
|
|
4527
4598
|
// src/lib/strings.ts
|
|
4528
|
-
var
|
|
4599
|
+
var DEPOSIT_SOURCES = "Deposit from:\n- Coinbase \u2014 withdraw directly to Base\n- Another wallet (MetaMask, Rainbow, etc.) \u2014 send on Base network\n- Bridge from other chains \u2014 use https://superbridge.app/base";
|
|
4529
4600
|
var NO_WALLET_CONFIGURED = "No wallet configured.";
|
|
4530
4601
|
var NO_WALLET_SUGGESTION = "Run 'zora setup' to create or import one.";
|
|
4531
4602
|
var SAVE_ERROR_HINT = "Check that the directory exists and is writable.";
|
|
4532
|
-
var BACKUP_WARNING = "Back up this file \u2014 it's the only copy of your key.";
|
|
4603
|
+
var BACKUP_WARNING = "Back up this file \u2014 it's the only copy of your key. Zora is not responsible for any loss of funds.";
|
|
4533
4604
|
|
|
4534
|
-
// src/
|
|
4605
|
+
// src/lib/wallet-setup.ts
|
|
4606
|
+
import { generatePrivateKey, privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
|
|
4535
4607
|
var isValidPrivateKey = (key) => /^(0x)?[0-9a-fA-F]{64}$/.test(key);
|
|
4536
4608
|
var toAccount = (json, key, errorPrefix) => {
|
|
4537
4609
|
try {
|
|
4538
4610
|
return privateKeyToAccount4(normalizeKey(key));
|
|
4539
4611
|
} catch {
|
|
4540
|
-
outputErrorAndExit(
|
|
4612
|
+
return outputErrorAndExit(
|
|
4541
4613
|
json,
|
|
4542
4614
|
`\u2717 ${errorPrefix} isn't a valid private key.`
|
|
4543
4615
|
);
|
|
4544
4616
|
}
|
|
4545
4617
|
};
|
|
4546
|
-
var
|
|
4547
|
-
|
|
4548
|
-
const nonInteractive =
|
|
4618
|
+
var walletExistsWarning = (truncated) => `Wallet already configured: ${truncated}. Make sure your wallet is backed up \u2014 Zora is not responsible for any loss of funds.`;
|
|
4619
|
+
async function configureWallet(opts) {
|
|
4620
|
+
const { json, nonInteractive, promptOverwrite } = opts;
|
|
4549
4621
|
const envKey = process.env.ZORA_PRIVATE_KEY;
|
|
4550
4622
|
if (envKey !== void 0) {
|
|
4551
4623
|
if (!isValidPrivateKey(envKey)) {
|
|
@@ -4555,25 +4627,11 @@ var setupCommand = new Command10("setup").description("Set up your Zora wallet")
|
|
|
4555
4627
|
"Fix it and run zora setup again."
|
|
4556
4628
|
);
|
|
4557
4629
|
}
|
|
4558
|
-
const
|
|
4559
|
-
|
|
4560
|
-
json: { source: "env", address: account.address },
|
|
4561
|
-
render: () => {
|
|
4562
|
-
console.log(" Using wallet from ZORA_PRIVATE_KEY.\n");
|
|
4563
|
-
console.log(` Address: ${account.address}
|
|
4564
|
-
`);
|
|
4565
|
-
console.log(` ${DEPOSIT_INSTRUCTIONS}`);
|
|
4566
|
-
}
|
|
4567
|
-
});
|
|
4568
|
-
track("cli_setup", {
|
|
4569
|
-
action: "env_detected",
|
|
4570
|
-
source: "env",
|
|
4571
|
-
output_format: json ? "json" : "text"
|
|
4572
|
-
});
|
|
4573
|
-
return;
|
|
4630
|
+
const account2 = toAccount(json, envKey, "ZORA_PRIVATE_KEY");
|
|
4631
|
+
return { action: "env_detected", address: account2.address };
|
|
4574
4632
|
}
|
|
4575
4633
|
let existing;
|
|
4576
|
-
if (!
|
|
4634
|
+
if (!opts.force) {
|
|
4577
4635
|
try {
|
|
4578
4636
|
existing = getPrivateKey();
|
|
4579
4637
|
} catch (err) {
|
|
@@ -4585,20 +4643,33 @@ var setupCommand = new Command10("setup").description("Set up your Zora wallet")
|
|
|
4585
4643
|
}
|
|
4586
4644
|
}
|
|
4587
4645
|
if (existing) {
|
|
4588
|
-
const
|
|
4589
|
-
const truncated =
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
"
|
|
4646
|
+
const account2 = toAccount(json, existing, "Stored private key");
|
|
4647
|
+
const truncated = `${account2.address.slice(0, 6)}\u2026${account2.address.slice(-4)}`;
|
|
4648
|
+
const warning = walletExistsWarning(truncated);
|
|
4649
|
+
if (promptOverwrite) {
|
|
4650
|
+
if (nonInteractive) {
|
|
4651
|
+
return { action: "skipped", address: account2.address, warning };
|
|
4652
|
+
}
|
|
4653
|
+
const overwrite = await confirmOrDefault(
|
|
4654
|
+
{ message: "Overwrite wallet configuration?", default: false },
|
|
4655
|
+
false
|
|
4597
4656
|
);
|
|
4657
|
+
if (!overwrite) {
|
|
4658
|
+
return { action: "skipped", address: account2.address, warning };
|
|
4659
|
+
}
|
|
4660
|
+
} else {
|
|
4661
|
+
if (!opts.force) {
|
|
4662
|
+
outputErrorAndExit(
|
|
4663
|
+
json,
|
|
4664
|
+
`${warning}
|
|
4665
|
+
Wallet already exists.`,
|
|
4666
|
+
"Use --force to overwrite."
|
|
4667
|
+
);
|
|
4668
|
+
}
|
|
4598
4669
|
}
|
|
4599
4670
|
}
|
|
4600
4671
|
let choice;
|
|
4601
|
-
if (
|
|
4672
|
+
if (opts.create) {
|
|
4602
4673
|
choice = "create";
|
|
4603
4674
|
} else {
|
|
4604
4675
|
choice = await selectOrDefault(
|
|
@@ -4632,7 +4703,7 @@ var setupCommand = new Command10("setup").description("Set up your Zora wallet")
|
|
|
4632
4703
|
);
|
|
4633
4704
|
}
|
|
4634
4705
|
}
|
|
4635
|
-
const
|
|
4706
|
+
const account2 = toAccount(json, importedKey, "Imported key");
|
|
4636
4707
|
try {
|
|
4637
4708
|
savePrivateKey(importedKey);
|
|
4638
4709
|
} catch {
|
|
@@ -4642,64 +4713,201 @@ var setupCommand = new Command10("setup").description("Set up your Zora wallet")
|
|
|
4642
4713
|
SAVE_ERROR_HINT
|
|
4643
4714
|
);
|
|
4644
4715
|
}
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4716
|
+
return {
|
|
4717
|
+
action: "imported",
|
|
4718
|
+
address: account2.address,
|
|
4719
|
+
path: getWalletPath()
|
|
4720
|
+
};
|
|
4721
|
+
}
|
|
4722
|
+
const privateKey = generatePrivateKey();
|
|
4723
|
+
const account = toAccount(json, privateKey, "Generated key");
|
|
4724
|
+
try {
|
|
4725
|
+
savePrivateKey(privateKey);
|
|
4726
|
+
} catch {
|
|
4727
|
+
outputErrorAndExit(
|
|
4728
|
+
json,
|
|
4729
|
+
`\u2717 Couldn't save to ${getWalletPath()}.`,
|
|
4730
|
+
SAVE_ERROR_HINT
|
|
4731
|
+
);
|
|
4732
|
+
}
|
|
4733
|
+
return {
|
|
4734
|
+
action: "created",
|
|
4735
|
+
address: account.address,
|
|
4736
|
+
path: getWalletPath()
|
|
4737
|
+
};
|
|
4738
|
+
}
|
|
4739
|
+
|
|
4740
|
+
// src/lib/ansi.ts
|
|
4741
|
+
var DIM = "\x1B[2m";
|
|
4742
|
+
var BOLD = "\x1B[1m";
|
|
4743
|
+
var YELLOW = "\x1B[33m";
|
|
4744
|
+
var RESET = "\x1B[0m";
|
|
4745
|
+
var useAnsi = () => process.stdout.isTTY && !process.env.NO_COLOR;
|
|
4746
|
+
|
|
4747
|
+
// src/lib/warning-box.ts
|
|
4748
|
+
function warningBox(text) {
|
|
4749
|
+
if (!useAnsi()) {
|
|
4750
|
+
console.log(`\u26A0 ${text}
|
|
4655
4751
|
`);
|
|
4656
|
-
|
|
4752
|
+
return;
|
|
4753
|
+
}
|
|
4754
|
+
console.log(`${YELLOW}\u26A0 ${text}${RESET}
|
|
4755
|
+
`);
|
|
4756
|
+
}
|
|
4757
|
+
|
|
4758
|
+
// src/commands/setup.tsx
|
|
4759
|
+
import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
4760
|
+
function stepLine(step, total, title) {
|
|
4761
|
+
const cols = (process.stdout.columns || 80) - 4;
|
|
4762
|
+
if (!useAnsi()) {
|
|
4763
|
+
console.log(`
|
|
4764
|
+
[${step}/${total}] ${title}`);
|
|
4765
|
+
console.log(`${"\u2500".repeat(Math.max(cols, 20))}
|
|
4657
4766
|
`);
|
|
4658
|
-
console.log(` ${DEPOSIT_INSTRUCTIONS}`);
|
|
4659
|
-
}
|
|
4660
|
-
});
|
|
4661
|
-
track("cli_setup", {
|
|
4662
|
-
action: "imported",
|
|
4663
|
-
source: "file",
|
|
4664
|
-
output_format: json ? "json" : "text"
|
|
4665
|
-
});
|
|
4666
4767
|
return;
|
|
4667
4768
|
}
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
} catch {
|
|
4674
|
-
outputErrorAndExit(
|
|
4675
|
-
json,
|
|
4676
|
-
`\u2717 Couldn't save to ${getWalletPath()}.`,
|
|
4677
|
-
SAVE_ERROR_HINT
|
|
4678
|
-
);
|
|
4679
|
-
}
|
|
4680
|
-
outputData(json, {
|
|
4681
|
-
json: {
|
|
4682
|
-
action: "created",
|
|
4683
|
-
address: account.address,
|
|
4684
|
-
path: getWalletPath()
|
|
4685
|
-
},
|
|
4686
|
-
render: () => {
|
|
4687
|
-
console.log("\n\u2713 Wallet created\n");
|
|
4688
|
-
console.log(` Address: ${account.address}`);
|
|
4689
|
-
console.log(` Private key: saved to ${getWalletPath()}
|
|
4769
|
+
console.log(
|
|
4770
|
+
`
|
|
4771
|
+
${BOLD}${DIM}[${step}/${total}]${RESET} ${BOLD}${title}${RESET}`
|
|
4772
|
+
);
|
|
4773
|
+
console.log(`${DIM}${"\u2500".repeat(Math.max(cols, 20))}${RESET}
|
|
4690
4774
|
`);
|
|
4691
|
-
|
|
4775
|
+
}
|
|
4776
|
+
var setupCommand = new Command10("setup").description("Guided first-time setup").option("--create", "Create a new wallet without prompting").option("--force", "Overwrite existing wallet without prompting").option("--yes", "Skip interactive prompt and execute directly").action(async function(options) {
|
|
4777
|
+
const json = getJson(this);
|
|
4778
|
+
const nonInteractive = getYes(this);
|
|
4779
|
+
if (!json) stepLine(1, 3, "Set up wallet");
|
|
4780
|
+
const walletResult = await configureWallet({
|
|
4781
|
+
json,
|
|
4782
|
+
nonInteractive,
|
|
4783
|
+
create: options.create,
|
|
4784
|
+
force: options.force,
|
|
4785
|
+
promptOverwrite: true
|
|
4786
|
+
});
|
|
4787
|
+
if (!json) {
|
|
4788
|
+
if (walletResult.action === "env_detected") {
|
|
4789
|
+
console.log("Using wallet from ZORA_PRIVATE_KEY.");
|
|
4790
|
+
console.log(`Address: ${walletResult.address}
|
|
4692
4791
|
`);
|
|
4693
|
-
|
|
4792
|
+
} else if (walletResult.action === "skipped") {
|
|
4793
|
+
warningBox(walletResult.warning);
|
|
4794
|
+
console.log(`${DIM}Keeping existing wallet.${RESET}
|
|
4795
|
+
`);
|
|
4796
|
+
} else {
|
|
4797
|
+
const verb = walletResult.action === "created" ? "created" : "imported";
|
|
4798
|
+
console.log(`\u2713 Wallet ${verb}`);
|
|
4799
|
+
console.log(`Address: ${walletResult.address}`);
|
|
4800
|
+
console.log(`Private key: saved to ${walletResult.path}
|
|
4801
|
+
`);
|
|
4802
|
+
warningBox(BACKUP_WARNING);
|
|
4803
|
+
}
|
|
4804
|
+
}
|
|
4805
|
+
if (!json) stepLine(2, 3, "Set up API key (optional)");
|
|
4806
|
+
let apiKeyStatus;
|
|
4807
|
+
const envApiKey = getEnvApiKey();
|
|
4808
|
+
if (envApiKey) {
|
|
4809
|
+
apiKeyStatus = "env_override";
|
|
4810
|
+
if (!json) {
|
|
4811
|
+
console.log("API key is set via ZORA_API_KEY environment variable.\n");
|
|
4812
|
+
}
|
|
4813
|
+
} else {
|
|
4814
|
+
const existingKey = getApiKey();
|
|
4815
|
+
if (existingKey && !options.force) {
|
|
4816
|
+
if (nonInteractive) {
|
|
4817
|
+
apiKeyStatus = "already_set";
|
|
4818
|
+
if (!json) {
|
|
4819
|
+
console.log(
|
|
4820
|
+
`API key already configured: ${maskKey(existingKey)}
|
|
4821
|
+
`
|
|
4822
|
+
);
|
|
4823
|
+
}
|
|
4824
|
+
} else {
|
|
4825
|
+
if (!json) console.log(`Current key: ${maskKey(existingKey)}`);
|
|
4826
|
+
const overwrite = await confirmOrDefault(
|
|
4827
|
+
{ message: "Overwrite API key?", default: false },
|
|
4828
|
+
false
|
|
4829
|
+
);
|
|
4830
|
+
if (!overwrite) {
|
|
4831
|
+
apiKeyStatus = "already_set";
|
|
4832
|
+
if (!json) console.log("");
|
|
4833
|
+
} else {
|
|
4834
|
+
apiKeyStatus = await promptAndSaveApiKey(json);
|
|
4835
|
+
}
|
|
4694
4836
|
}
|
|
4695
|
-
}
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
source: "file",
|
|
4699
|
-
output_format: json ? "json" : "text"
|
|
4700
|
-
});
|
|
4837
|
+
} else {
|
|
4838
|
+
apiKeyStatus = await promptAndSaveApiKey(json, nonInteractive);
|
|
4839
|
+
}
|
|
4701
4840
|
}
|
|
4841
|
+
if (!json) stepLine(3, 3, "Deposit");
|
|
4842
|
+
if (!json) {
|
|
4843
|
+
renderOnce(
|
|
4844
|
+
/* @__PURE__ */ jsxs9(
|
|
4845
|
+
Box9,
|
|
4846
|
+
{
|
|
4847
|
+
flexDirection: "column",
|
|
4848
|
+
borderStyle: "single",
|
|
4849
|
+
borderDimColor: true,
|
|
4850
|
+
paddingX: 1,
|
|
4851
|
+
paddingY: 1,
|
|
4852
|
+
children: [
|
|
4853
|
+
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
4854
|
+
"Your address: ",
|
|
4855
|
+
/* @__PURE__ */ jsx12(Text9, { bold: true, children: walletResult.address })
|
|
4856
|
+
] }),
|
|
4857
|
+
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
4858
|
+
"Deposit",
|
|
4859
|
+
" ",
|
|
4860
|
+
/* @__PURE__ */ jsx12(Text9, { bold: true, color: "blue", children: "ETH or USDC on Base" }),
|
|
4861
|
+
" ",
|
|
4862
|
+
"to start trading."
|
|
4863
|
+
] })
|
|
4864
|
+
]
|
|
4865
|
+
}
|
|
4866
|
+
)
|
|
4867
|
+
);
|
|
4868
|
+
console.log(`
|
|
4869
|
+
${DEPOSIT_SOURCES}
|
|
4870
|
+
`);
|
|
4871
|
+
}
|
|
4872
|
+
outputData(json, {
|
|
4873
|
+
json: { wallet: walletResult, apiKey: apiKeyStatus },
|
|
4874
|
+
render: () => {
|
|
4875
|
+
}
|
|
4876
|
+
});
|
|
4877
|
+
track("cli_setup", {
|
|
4878
|
+
wallet_action: walletResult.action,
|
|
4879
|
+
api_key_status: apiKeyStatus,
|
|
4880
|
+
output_format: json ? "json" : "text"
|
|
4881
|
+
});
|
|
4702
4882
|
});
|
|
4883
|
+
async function promptAndSaveApiKey(json, nonInteractive = false) {
|
|
4884
|
+
if (!json && !nonInteractive) {
|
|
4885
|
+
console.log(
|
|
4886
|
+
"Optional. An API key unlocks higher rate limits for frequent trading."
|
|
4887
|
+
);
|
|
4888
|
+
console.log("Get your API key from: https://zora.co/settings/developer\n");
|
|
4889
|
+
}
|
|
4890
|
+
const apiKey = await passwordOrSkip(
|
|
4891
|
+
{ message: "Paste your API key (Enter to skip):" },
|
|
4892
|
+
nonInteractive
|
|
4893
|
+
);
|
|
4894
|
+
const trimmed = apiKey.trim();
|
|
4895
|
+
if (!trimmed) {
|
|
4896
|
+
if (!json) console.log("Skipped API key configuration.\n");
|
|
4897
|
+
return "skipped";
|
|
4898
|
+
}
|
|
4899
|
+
try {
|
|
4900
|
+
saveApiKey(trimmed);
|
|
4901
|
+
if (!json) console.log(`API key saved to ${getConfigPath()}
|
|
4902
|
+
`);
|
|
4903
|
+
return "saved";
|
|
4904
|
+
} catch (err) {
|
|
4905
|
+
outputErrorAndExit(
|
|
4906
|
+
json,
|
|
4907
|
+
`Failed to save API key: ${fsErrorMessage(err, getConfigPath())}`
|
|
4908
|
+
);
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4703
4911
|
|
|
4704
4912
|
// src/commands/wallet.ts
|
|
4705
4913
|
import { Command as Command11 } from "commander";
|
|
@@ -4715,9 +4923,9 @@ var resolvePrivateKey = () => {
|
|
|
4715
4923
|
}
|
|
4716
4924
|
return void 0;
|
|
4717
4925
|
};
|
|
4718
|
-
var walletCommand = new Command11("wallet").description(
|
|
4719
|
-
|
|
4720
|
-
);
|
|
4926
|
+
var walletCommand = new Command11("wallet").description("Manage your Zora wallet").action(function() {
|
|
4927
|
+
this.outputHelp();
|
|
4928
|
+
});
|
|
4721
4929
|
walletCommand.command("info").description("Show wallet address and storage location").action(function() {
|
|
4722
4930
|
const json = getJson(this);
|
|
4723
4931
|
const resolved = resolvePrivateKey();
|
|
@@ -4773,21 +4981,69 @@ walletCommand.command("export").description("Print the raw private key to stdout
|
|
|
4773
4981
|
output_format: json ? "json" : "text"
|
|
4774
4982
|
});
|
|
4775
4983
|
});
|
|
4984
|
+
walletCommand.command("configure").description("Create or import a wallet").option("--create", "Create a new wallet without prompting").option("--force", "Overwrite existing wallet without prompting").option("--yes", "Skip interactive prompt and execute directly").action(async function(options) {
|
|
4985
|
+
const json = getJson(this);
|
|
4986
|
+
const nonInteractive = getYes(this);
|
|
4987
|
+
const result = await configureWallet({
|
|
4988
|
+
json,
|
|
4989
|
+
nonInteractive,
|
|
4990
|
+
create: options.create,
|
|
4991
|
+
force: options.force,
|
|
4992
|
+
promptOverwrite: false
|
|
4993
|
+
});
|
|
4994
|
+
outputData(json, {
|
|
4995
|
+
json: result,
|
|
4996
|
+
render: () => {
|
|
4997
|
+
if (result.action === "env_detected") {
|
|
4998
|
+
console.log(" Using wallet from ZORA_PRIVATE_KEY.\n");
|
|
4999
|
+
console.log(` Address: ${result.address}
|
|
5000
|
+
`);
|
|
5001
|
+
console.log(
|
|
5002
|
+
` Deposit ETH or USDC on Base to start trading.
|
|
5003
|
+
|
|
5004
|
+
${DEPOSIT_SOURCES}`
|
|
5005
|
+
);
|
|
5006
|
+
} else if (result.action === "created" || result.action === "imported") {
|
|
5007
|
+
const verb = result.action === "created" ? "created" : "imported";
|
|
5008
|
+
console.log(`
|
|
5009
|
+
\u2713 Wallet ${verb}
|
|
5010
|
+
`);
|
|
5011
|
+
console.log(` Address: ${result.address}`);
|
|
5012
|
+
console.log(` Private key: saved to ${result.path}
|
|
5013
|
+
`);
|
|
5014
|
+
console.log(` ${BACKUP_WARNING}
|
|
5015
|
+
`);
|
|
5016
|
+
console.log(
|
|
5017
|
+
` Deposit ETH or USDC on Base to start trading.
|
|
5018
|
+
|
|
5019
|
+
${DEPOSIT_SOURCES}`
|
|
5020
|
+
);
|
|
5021
|
+
} else if (result.action === "skipped") {
|
|
5022
|
+
console.log(` Wallet already configured: ${result.address}
|
|
5023
|
+
`);
|
|
5024
|
+
}
|
|
5025
|
+
}
|
|
5026
|
+
});
|
|
5027
|
+
track("cli_wallet_config", {
|
|
5028
|
+
action: result.action,
|
|
5029
|
+
output_format: json ? "json" : "text"
|
|
5030
|
+
});
|
|
5031
|
+
});
|
|
4776
5032
|
|
|
4777
5033
|
// src/components/StyledHelp.tsx
|
|
4778
|
-
import { Text as
|
|
5034
|
+
import { Text as Text11, Box as Box11 } from "ink";
|
|
4779
5035
|
|
|
4780
5036
|
// src/components/KeyValueTable.tsx
|
|
4781
|
-
import { Text as
|
|
4782
|
-
import { jsx as
|
|
5037
|
+
import { Text as Text10, Box as Box10 } from "ink";
|
|
5038
|
+
import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
4783
5039
|
function KeyValueTable({
|
|
4784
5040
|
rows,
|
|
4785
5041
|
labelWidth
|
|
4786
5042
|
}) {
|
|
4787
5043
|
const pad = labelWidth ?? Math.max(0, ...rows.map((r) => r.label.length)) + 2;
|
|
4788
|
-
return /* @__PURE__ */
|
|
4789
|
-
/* @__PURE__ */
|
|
4790
|
-
/* @__PURE__ */
|
|
5044
|
+
return /* @__PURE__ */ jsx13(Box10, { flexDirection: "column", children: rows.map((row, i) => /* @__PURE__ */ jsxs10(Text10, { children: [
|
|
5045
|
+
/* @__PURE__ */ jsx13(Text10, { bold: true, children: row.label.padEnd(pad) }),
|
|
5046
|
+
/* @__PURE__ */ jsx13(Text10, { dimColor: true, children: row.value })
|
|
4791
5047
|
] }, i)) });
|
|
4792
5048
|
}
|
|
4793
5049
|
|
|
@@ -4828,14 +5084,18 @@ function parseHelpSections(text) {
|
|
|
4828
5084
|
}
|
|
4829
5085
|
|
|
4830
5086
|
// src/components/StyledHelp.tsx
|
|
4831
|
-
import { jsx as
|
|
5087
|
+
import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4832
5088
|
function StyledHelp({
|
|
4833
5089
|
sections,
|
|
4834
5090
|
header
|
|
4835
5091
|
}) {
|
|
4836
5092
|
const descriptionColumnOffset = getDescriptionColumnOffset(sections);
|
|
4837
|
-
return /* @__PURE__ */
|
|
5093
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", gap: 1, children: [
|
|
4838
5094
|
header,
|
|
5095
|
+
/* @__PURE__ */ jsxs11(Box11, { paddingX: 1, children: [
|
|
5096
|
+
/* @__PURE__ */ jsx14(Text11, { color: "yellow", children: "\u26A0 Beta:" }),
|
|
5097
|
+
/* @__PURE__ */ jsx14(Text11, { children: " This CLI is in beta and should be used with caution." })
|
|
5098
|
+
] }),
|
|
4839
5099
|
sections.map((section, i) => {
|
|
4840
5100
|
const hasTwoColumns = TWO_COLUMN_REGEX.test(section.content);
|
|
4841
5101
|
const rows = hasTwoColumns ? section.content.split("\n").map((line) => {
|
|
@@ -4847,8 +5107,8 @@ function StyledHelp({
|
|
|
4847
5107
|
};
|
|
4848
5108
|
return { label: "", value: line.trimStart() };
|
|
4849
5109
|
}) : null;
|
|
4850
|
-
return /* @__PURE__ */
|
|
4851
|
-
|
|
5110
|
+
return /* @__PURE__ */ jsxs11(
|
|
5111
|
+
Box11,
|
|
4852
5112
|
{
|
|
4853
5113
|
flexDirection: "column",
|
|
4854
5114
|
borderStyle: "single",
|
|
@@ -4856,8 +5116,8 @@ function StyledHelp({
|
|
|
4856
5116
|
paddingX: 1,
|
|
4857
5117
|
paddingY: 1,
|
|
4858
5118
|
children: [
|
|
4859
|
-
/* @__PURE__ */
|
|
4860
|
-
rows ? /* @__PURE__ */
|
|
5119
|
+
/* @__PURE__ */ jsx14(Text11, { bold: true, children: section.title }),
|
|
5120
|
+
rows ? /* @__PURE__ */ jsx14(KeyValueTable, { rows, labelWidth: descriptionColumnOffset }) : /* @__PURE__ */ jsx14(Text11, { children: section.content })
|
|
4861
5121
|
]
|
|
4862
5122
|
},
|
|
4863
5123
|
i
|
|
@@ -4867,10 +5127,10 @@ function StyledHelp({
|
|
|
4867
5127
|
}
|
|
4868
5128
|
|
|
4869
5129
|
// src/components/StyledHelpHeader.tsx
|
|
4870
|
-
import { Text as
|
|
5130
|
+
import { Text as Text13, Box as Box13 } from "ink";
|
|
4871
5131
|
|
|
4872
5132
|
// src/components/Zorb.tsx
|
|
4873
|
-
import { Text as
|
|
5133
|
+
import { Text as Text12, Box as Box12 } from "ink";
|
|
4874
5134
|
|
|
4875
5135
|
// src/lib/zorb-pixels.ts
|
|
4876
5136
|
function supportsTruecolor() {
|
|
@@ -5015,7 +5275,7 @@ function generateZorbPixels(size) {
|
|
|
5015
5275
|
}
|
|
5016
5276
|
|
|
5017
5277
|
// src/components/Zorb.tsx
|
|
5018
|
-
import { jsx as
|
|
5278
|
+
import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
5019
5279
|
var LOWER_HALF_BLOCK = "\u2584";
|
|
5020
5280
|
var UPPER_HALF_BLOCK = "\u2580";
|
|
5021
5281
|
function rgbString([r, g, b]) {
|
|
@@ -5038,19 +5298,19 @@ function Zorb({ size = 20 }) {
|
|
|
5038
5298
|
const topIsBlack = isBlack(top);
|
|
5039
5299
|
const bottomIsBlack = isBlack(bottom);
|
|
5040
5300
|
if (topIsBlack && bottomIsBlack) {
|
|
5041
|
-
cells.push(/* @__PURE__ */
|
|
5301
|
+
cells.push(/* @__PURE__ */ jsx15(Text12, { children: " " }, x));
|
|
5042
5302
|
} else if (topIsBlack) {
|
|
5043
5303
|
cells.push(
|
|
5044
|
-
/* @__PURE__ */
|
|
5304
|
+
/* @__PURE__ */ jsx15(Text12, { color: rgbString(bottom), children: LOWER_HALF_BLOCK }, x)
|
|
5045
5305
|
);
|
|
5046
5306
|
} else if (bottomIsBlack) {
|
|
5047
5307
|
cells.push(
|
|
5048
|
-
/* @__PURE__ */
|
|
5308
|
+
/* @__PURE__ */ jsx15(Text12, { color: rgbString(top), children: UPPER_HALF_BLOCK }, x)
|
|
5049
5309
|
);
|
|
5050
5310
|
} else {
|
|
5051
5311
|
cells.push(
|
|
5052
|
-
/* @__PURE__ */
|
|
5053
|
-
|
|
5312
|
+
/* @__PURE__ */ jsx15(
|
|
5313
|
+
Text12,
|
|
5054
5314
|
{
|
|
5055
5315
|
backgroundColor: rgbString(top),
|
|
5056
5316
|
color: rgbString(bottom),
|
|
@@ -5061,23 +5321,23 @@ function Zorb({ size = 20 }) {
|
|
|
5061
5321
|
);
|
|
5062
5322
|
}
|
|
5063
5323
|
}
|
|
5064
|
-
rows.push(/* @__PURE__ */
|
|
5324
|
+
rows.push(/* @__PURE__ */ jsx15(Text12, { children: cells }, y));
|
|
5065
5325
|
}
|
|
5066
|
-
return /* @__PURE__ */
|
|
5067
|
-
/* @__PURE__ */
|
|
5326
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
|
|
5327
|
+
/* @__PURE__ */ jsx15(Text12, { children: " " }),
|
|
5068
5328
|
rows,
|
|
5069
|
-
/* @__PURE__ */
|
|
5329
|
+
/* @__PURE__ */ jsx15(Text12, { children: " " })
|
|
5070
5330
|
] });
|
|
5071
5331
|
}
|
|
5072
5332
|
|
|
5073
5333
|
// src/components/StyledHelpHeader.tsx
|
|
5074
|
-
import { jsx as
|
|
5334
|
+
import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
5075
5335
|
function StyledHelpHeader({
|
|
5076
5336
|
sections
|
|
5077
5337
|
}) {
|
|
5078
5338
|
const descriptionColumnOffset = getDescriptionColumnOffset(sections);
|
|
5079
|
-
return /* @__PURE__ */
|
|
5080
|
-
|
|
5339
|
+
return /* @__PURE__ */ jsxs13(
|
|
5340
|
+
Box13,
|
|
5081
5341
|
{
|
|
5082
5342
|
flexDirection: "row",
|
|
5083
5343
|
borderStyle: "single",
|
|
@@ -5085,19 +5345,36 @@ function StyledHelpHeader({
|
|
|
5085
5345
|
paddingX: 1,
|
|
5086
5346
|
paddingY: 1,
|
|
5087
5347
|
children: [
|
|
5088
|
-
/* @__PURE__ */
|
|
5089
|
-
/* @__PURE__ */
|
|
5348
|
+
/* @__PURE__ */ jsx16(Box13, { flexShrink: 0, width: descriptionColumnOffset, children: /* @__PURE__ */ jsx16(Zorb, { size: 20 }) }),
|
|
5349
|
+
/* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexGrow: 1, justifyContent: "center", children: [
|
|
5350
|
+
/* @__PURE__ */ jsx16(Text13, { bold: true, children: /* @__PURE__ */ jsxs13(Text13, { backgroundColor: "#3fff00", color: "black", children: [
|
|
5351
|
+
" ",
|
|
5352
|
+
"Zora CLI",
|
|
5353
|
+
" "
|
|
5354
|
+
] }) }),
|
|
5355
|
+
/* @__PURE__ */ jsxs13(Text13, { children: [
|
|
5356
|
+
/* @__PURE__ */ jsx16(Text13, { dimColor: true, children: "Trade what's trending. Run" }),
|
|
5357
|
+
" ",
|
|
5358
|
+
/* @__PURE__ */ jsxs13(Text13, { backgroundColor: "#3fff00", color: "black", children: [
|
|
5359
|
+
" ",
|
|
5360
|
+
"zora setup",
|
|
5361
|
+
" "
|
|
5362
|
+
] }),
|
|
5363
|
+
" ",
|
|
5364
|
+
/* @__PURE__ */ jsx16(Text13, { dimColor: true, children: "to get started." })
|
|
5365
|
+
] })
|
|
5366
|
+
] })
|
|
5090
5367
|
]
|
|
5091
5368
|
}
|
|
5092
5369
|
);
|
|
5093
5370
|
}
|
|
5094
5371
|
|
|
5095
5372
|
// src/index.tsx
|
|
5096
|
-
import { jsx as
|
|
5373
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
5097
5374
|
if (process.env.ZORA_API_TARGET) {
|
|
5098
5375
|
setApiBaseUrl(process.env.ZORA_API_TARGET);
|
|
5099
5376
|
}
|
|
5100
|
-
var version = true ? "0.
|
|
5377
|
+
var version = true ? "1.0.0" : JSON.parse(
|
|
5101
5378
|
readFileSync2(new URL("../package.json", import.meta.url), "utf-8")
|
|
5102
5379
|
).version;
|
|
5103
5380
|
function styledHelpWriteOut(showHeader) {
|
|
@@ -5105,18 +5382,27 @@ function styledHelpWriteOut(showHeader) {
|
|
|
5105
5382
|
if (supportsTruecolor()) {
|
|
5106
5383
|
const sections = parseHelpSections(str);
|
|
5107
5384
|
if (sections.length > 0) {
|
|
5108
|
-
const header = showHeader ? /* @__PURE__ */
|
|
5109
|
-
renderOnce(/* @__PURE__ */
|
|
5385
|
+
const header = showHeader ? /* @__PURE__ */ jsx17(StyledHelpHeader, { sections }) : void 0;
|
|
5386
|
+
renderOnce(/* @__PURE__ */ jsx17(StyledHelp, { sections, header }));
|
|
5110
5387
|
return;
|
|
5111
5388
|
}
|
|
5112
5389
|
}
|
|
5113
5390
|
process.stdout.write(str);
|
|
5391
|
+
process.stdout.write(
|
|
5392
|
+
"\n\x1B[33m\u26A0 Beta:\x1B[0m This CLI is in beta and should be used with caution.\n"
|
|
5393
|
+
);
|
|
5114
5394
|
};
|
|
5115
5395
|
}
|
|
5116
5396
|
var buildProgram = () => {
|
|
5117
|
-
const program2 = new Command12().name("zora").description("
|
|
5397
|
+
const program2 = new Command12().name("zora").description("Trade what's trending. Run `zora setup` to get started.").version(version).option("--json", "Output as JSON (for scripts and automation)", false);
|
|
5118
5398
|
const helpWidth = (process.stdout.columns || 80) - 4;
|
|
5119
|
-
program2.configureHelp({
|
|
5399
|
+
program2.configureHelp({
|
|
5400
|
+
helpWidth,
|
|
5401
|
+
commandDescription: (cmd) => {
|
|
5402
|
+
if (!cmd.parent && supportsTruecolor()) return "";
|
|
5403
|
+
return cmd.description();
|
|
5404
|
+
}
|
|
5405
|
+
});
|
|
5120
5406
|
program2.configureOutput({ writeOut: styledHelpWriteOut(true) });
|
|
5121
5407
|
program2.action(() => {
|
|
5122
5408
|
program2.outputHelp();
|
|
@@ -5140,9 +5426,10 @@ var buildProgram = () => {
|
|
|
5140
5426
|
}
|
|
5141
5427
|
};
|
|
5142
5428
|
applyToSubcommands(program2);
|
|
5429
|
+
const argOptionalCommands = /* @__PURE__ */ new Set(["profile"]);
|
|
5143
5430
|
program2.hook("preAction", (_thisCommand, actionCommand) => {
|
|
5144
5431
|
const expected = actionCommand.registeredArguments.length;
|
|
5145
|
-
if (expected > 0 && actionCommand.args.length === 0) {
|
|
5432
|
+
if (expected > 0 && actionCommand.args.length === 0 && !argOptionalCommands.has(actionCommand.name())) {
|
|
5146
5433
|
actionCommand.outputHelp();
|
|
5147
5434
|
process.exit(1);
|
|
5148
5435
|
}
|
|
@@ -5151,9 +5438,6 @@ var buildProgram = () => {
|
|
|
5151
5438
|
};
|
|
5152
5439
|
var program = buildProgram();
|
|
5153
5440
|
if (!process.env.VITEST) {
|
|
5154
|
-
console.warn(
|
|
5155
|
-
"\x1B[33m\u26A0 Beta:\x1B[0m This CLI is in beta and should be used with caution."
|
|
5156
|
-
);
|
|
5157
5441
|
identify();
|
|
5158
5442
|
try {
|
|
5159
5443
|
await program.parseAsync();
|