@solard/cli 0.2.13 → 0.2.15
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 +2 -2
- package/src/backtest-batch-command.ts +262 -0
- package/src/backtest-command.ts +533 -0
- package/src/commands/buy.ts +207 -0
- package/src/commands/jupiter-swap.test.ts +78 -0
- package/src/commands/jupiter-swap.ts +269 -0
- package/src/commands/sell.ts +239 -0
- package/src/commands/trade-result.ts +19 -0
- package/src/commands/trade-targets.ts +43 -0
- package/src/commands/trade-venue.test.ts +32 -0
- package/src/commands/trade-venue.ts +19 -0
- package/src/commands/transfer.ts +200 -0
- package/src/fairfun-commands.ts +441 -0
- package/src/index.ts +387 -290
- package/src/meteora-commands.ts +148 -6
- package/src/pump/external-deployment-cli.ts +136 -0
- package/src/pump/token-launch-cli.ts +82 -6
- package/src/raydium-commands.ts +398 -0
- package/src/refs.ts +56 -0
- package/src/token-history-command.ts +559 -0
- package/src/vault-onboarding.ts +242 -0
package/src/meteora-commands.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import {
|
|
2
|
+
executeRegistryMeteoraLiquidation,
|
|
3
|
+
planRegistryMeteoraLiquidation,
|
|
4
|
+
type MeteoraPreparedTransactions,
|
|
5
|
+
type MeteoraStrategy,
|
|
6
|
+
type MeteoraTimeframe,
|
|
7
|
+
type Solard,
|
|
6
8
|
} from "@solard/sdk";
|
|
7
9
|
|
|
8
10
|
const WSOL = "So11111111111111111111111111111111111111112";
|
|
@@ -24,6 +26,14 @@ function flag(flags: Flags, key: string): string | undefined {
|
|
|
24
26
|
return value && value !== "true" ? value : undefined;
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
function csv(value: string | undefined): string[] {
|
|
30
|
+
if (!value || value === "true") return [];
|
|
31
|
+
return value
|
|
32
|
+
.split(",")
|
|
33
|
+
.map((item) => item.trim())
|
|
34
|
+
.filter(Boolean);
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
function requiredFlag(flags: Flags, key: string): string {
|
|
28
38
|
const value = flag(flags, key);
|
|
29
39
|
if (!value) throw new Error(`Missing --${key} <value>`);
|
|
@@ -349,6 +359,7 @@ function positionsTable(result: AnyRow): string {
|
|
|
349
359
|
pad("RANGE", 14),
|
|
350
360
|
pad("ACTIVE", 7, "right"),
|
|
351
361
|
pad("IN", 3),
|
|
362
|
+
pad("FUNDED", 9, "right"),
|
|
352
363
|
pad("X", 16, "right"),
|
|
353
364
|
pad("Y", 14, "right"),
|
|
354
365
|
pad("FEE X", 12, "right"),
|
|
@@ -364,6 +375,19 @@ function positionsTable(result: AnyRow): string {
|
|
|
364
375
|
pad(`${row.lowerBin ?? "?"}..${row.upperBin ?? "?"}`, 14),
|
|
365
376
|
pad(row.activeBin ?? "-", 7, "right"),
|
|
366
377
|
pad(row.inRange ? "yes" : "no", 3),
|
|
378
|
+
pad(
|
|
379
|
+
row.liquidityCoverage?.expectedBinCount != null
|
|
380
|
+
? `${row.liquidityCoverage?.fundedBinIds?.length ?? 0}/${row.liquidityCoverage.expectedBinCount}${
|
|
381
|
+
row.liquidityCoverage.fullRangeFunded === false
|
|
382
|
+
? "!"
|
|
383
|
+
: row.liquidityCoverage.fullRangeFunded == null
|
|
384
|
+
? "?"
|
|
385
|
+
: ""
|
|
386
|
+
}`
|
|
387
|
+
: "?",
|
|
388
|
+
9,
|
|
389
|
+
"right",
|
|
390
|
+
),
|
|
367
391
|
pad(rawUiText(row.totalXRaw ?? row.xRaw, xd), 16, "right"),
|
|
368
392
|
pad(rawUiText(row.totalYRaw ?? row.yRaw, yd), 14, "right"),
|
|
369
393
|
pad(rawUiText(row.feeXRaw, xd), 12, "right"),
|
|
@@ -1517,6 +1541,53 @@ function closeAllHuman(result: AnyRow): string {
|
|
|
1517
1541
|
return lines.join("\n") + "\n";
|
|
1518
1542
|
}
|
|
1519
1543
|
|
|
1544
|
+
function registryMeteoraPlanHuman(plan: AnyRow, live = false): string {
|
|
1545
|
+
const positions = Array.isArray(plan.positions) ? plan.positions : [];
|
|
1546
|
+
const errors = Array.isArray(plan.scanErrors) ? plan.scanErrors : [];
|
|
1547
|
+
const pools = new Set(positions.map((row: AnyRow) => String(row.pool ?? "")))
|
|
1548
|
+
.size;
|
|
1549
|
+
const lines = [
|
|
1550
|
+
`METEORA ${live ? "CLOSE ALL" : "POSITIONS"}`,
|
|
1551
|
+
`Wallets scanned: ${Number(plan.walletsScanned ?? 0)}`,
|
|
1552
|
+
`Pools: ${pools}`,
|
|
1553
|
+
`Positions: ${positions.length}`,
|
|
1554
|
+
"",
|
|
1555
|
+
];
|
|
1556
|
+
if (positions.length) {
|
|
1557
|
+
lines.push(
|
|
1558
|
+
"WALLET POOL POSITION X RAW Y RAW",
|
|
1559
|
+
);
|
|
1560
|
+
for (const row of positions) {
|
|
1561
|
+
lines.push(
|
|
1562
|
+
`${String(row.walletName ?? "-")
|
|
1563
|
+
.slice(0, 16)
|
|
1564
|
+
.padEnd(17)} ` +
|
|
1565
|
+
`${String(row.pool ?? "-")
|
|
1566
|
+
.slice(0, 16)
|
|
1567
|
+
.padEnd(17)} ` +
|
|
1568
|
+
`${String(row.position ?? "-")
|
|
1569
|
+
.slice(0, 16)
|
|
1570
|
+
.padEnd(17)} ` +
|
|
1571
|
+
`${String(row.totalXRaw ?? "0").padEnd(15)} ${String(row.totalYRaw ?? "0")}`,
|
|
1572
|
+
);
|
|
1573
|
+
}
|
|
1574
|
+
} else {
|
|
1575
|
+
lines.push("No open Meteora positions found.");
|
|
1576
|
+
}
|
|
1577
|
+
if (errors.length) {
|
|
1578
|
+
lines.push("", `Scan errors: ${errors.length}`);
|
|
1579
|
+
for (const row of errors) {
|
|
1580
|
+
lines.push(
|
|
1581
|
+
` @${String(row.walletName ?? "-")}: ${String(row.error ?? "unknown error")}`,
|
|
1582
|
+
);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
if (!live && positions.length) {
|
|
1586
|
+
lines.push("", "Preview only. Add --live to close every listed position.");
|
|
1587
|
+
}
|
|
1588
|
+
return lines.join("\n") + "\n";
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1520
1591
|
export async function handleMeteoraCommand(args: {
|
|
1521
1592
|
slrd: Solard;
|
|
1522
1593
|
values: string[];
|
|
@@ -1538,6 +1609,7 @@ export async function handleMeteoraCommand(args: {
|
|
|
1538
1609
|
` slrd meteora candles <pool> [--timeframe 5m] [--start-time unix] [--end-time unix]\n` +
|
|
1539
1610
|
` slrd meteora active-bin <pool>\n` +
|
|
1540
1611
|
` slrd meteora positions --wallet <wallet|address> [--pool <pool>]\n` +
|
|
1612
|
+
` slrd meteora positions --all-wallets\n` +
|
|
1541
1613
|
` slrd meteora position <position> (--wallet <wallet|address> | --pool <pool>)\n` +
|
|
1542
1614
|
` slrd meteora portfolio --wallet <wallet|address> [--open]\n` +
|
|
1543
1615
|
` slrd meteora history <position>\n` +
|
|
@@ -1549,6 +1621,8 @@ export async function handleMeteoraCommand(args: {
|
|
|
1549
1621
|
` slrd meteora remove <position> --wallet <wallet> [--bps 10000] [--pool <pool>] [--live]\n` +
|
|
1550
1622
|
` slrd meteora close <position> --wallet <wallet> [--pool <pool>] [--live]\n` +
|
|
1551
1623
|
` slrd meteora close-all <pool> --wallet <wallet> [--live]\n` +
|
|
1624
|
+
` slrd meteora close-all --wallet <wallet> --all-pools [--live]\n` +
|
|
1625
|
+
` slrd meteora close-all --all-wallets --all-pools [--live]\n` +
|
|
1552
1626
|
` slrd meteora move <position> --wallet <wallet> [--pool <pool>] [--bins N] [--haircut-bps 100] [--live]\n` +
|
|
1553
1627
|
` slrd meteora migrate <position> --wallet <wallet> --to-pool <pool> [--from-pool <source-pool>] [--bins N] [--haircut-bps 100] [--live]\n` +
|
|
1554
1628
|
` slrd meteora claim <position> --wallet <wallet> [--kind fees|rewards|all] [--pool <pool>] [--live]\n` +
|
|
@@ -2009,6 +2083,23 @@ export async function handleMeteoraCommand(args: {
|
|
|
2009
2083
|
}
|
|
2010
2084
|
|
|
2011
2085
|
if (action === "positions") {
|
|
2086
|
+
if (flags.has("all-wallets")) {
|
|
2087
|
+
if (flag(flags, "wallet") || flag(flags, "pool")) {
|
|
2088
|
+
throw new Error(
|
|
2089
|
+
"--all-wallets cannot be combined with --wallet or --pool",
|
|
2090
|
+
);
|
|
2091
|
+
}
|
|
2092
|
+
const result = await planRegistryMeteoraLiquidation(slrd, {
|
|
2093
|
+
delayMs: Math.max(0, integerFlag(flags, "delay-ms", 100)!),
|
|
2094
|
+
});
|
|
2095
|
+
emit(
|
|
2096
|
+
flags.has("json")
|
|
2097
|
+
? json(result) + "\n"
|
|
2098
|
+
: registryMeteoraPlanHuman(result as AnyRow),
|
|
2099
|
+
);
|
|
2100
|
+
return;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2012
2103
|
const walletRef = requiredFlag(flags, "wallet");
|
|
2013
2104
|
const wallet = publicWalletAddress(slrd, walletRef);
|
|
2014
2105
|
const pool = flag(flags, "pool");
|
|
@@ -2196,10 +2287,61 @@ export async function handleMeteoraCommand(args: {
|
|
|
2196
2287
|
}
|
|
2197
2288
|
|
|
2198
2289
|
if (action === "close-all") {
|
|
2290
|
+
if (flags.has("all-pools")) {
|
|
2291
|
+
const allWallets = flags.has("all-wallets");
|
|
2292
|
+
const wallet = flag(flags, "wallet");
|
|
2293
|
+
const walletList = csv(flag(flags, "wallets"));
|
|
2294
|
+
if (allWallets && (wallet || walletList.length)) {
|
|
2295
|
+
throw new Error(
|
|
2296
|
+
"--all-wallets cannot be combined with --wallet or --wallets",
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2299
|
+
if (!allWallets && !wallet && !walletList.length) {
|
|
2300
|
+
throw new Error(
|
|
2301
|
+
"Use --wallet <wallet>, --wallets <w1,w2>, or --all-wallets with --all-pools",
|
|
2302
|
+
);
|
|
2303
|
+
}
|
|
2304
|
+
const walletRefs = allWallets
|
|
2305
|
+
? undefined
|
|
2306
|
+
: wallet
|
|
2307
|
+
? [wallet]
|
|
2308
|
+
: walletList;
|
|
2309
|
+
const options = {
|
|
2310
|
+
walletRefs,
|
|
2311
|
+
delayMs: Math.max(0, integerFlag(flags, "delay-ms", 100)!),
|
|
2312
|
+
continueOnError: flags.has("continue-on-error"),
|
|
2313
|
+
};
|
|
2314
|
+
const plan = await planRegistryMeteoraLiquidation(slrd, options);
|
|
2315
|
+
if (!flags.has("live")) {
|
|
2316
|
+
emit(
|
|
2317
|
+
flags.has("json")
|
|
2318
|
+
? json({ live: false, ...plan }) + "\n"
|
|
2319
|
+
: registryMeteoraPlanHuman(plan as AnyRow),
|
|
2320
|
+
);
|
|
2321
|
+
return;
|
|
2322
|
+
}
|
|
2323
|
+
const results = await executeRegistryMeteoraLiquidation(
|
|
2324
|
+
slrd,
|
|
2325
|
+
plan,
|
|
2326
|
+
options,
|
|
2327
|
+
);
|
|
2328
|
+
const output = { live: true, ...plan, results };
|
|
2329
|
+
emit(
|
|
2330
|
+
flags.has("json")
|
|
2331
|
+
? json(output) + "\n"
|
|
2332
|
+
: registryMeteoraPlanHuman(plan as AnyRow, true) +
|
|
2333
|
+
`Closed: ${results.length}/${plan.positions.length}\n`,
|
|
2334
|
+
);
|
|
2335
|
+
return;
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
if (flags.has("all-wallets")) {
|
|
2339
|
+
throw new Error("--all-wallets requires --all-pools");
|
|
2340
|
+
}
|
|
2199
2341
|
const pool = values[1] ?? flag(flags, "pool");
|
|
2200
2342
|
if (!pool)
|
|
2201
2343
|
throw new Error(
|
|
2202
|
-
"Usage: slrd meteora close-all <pool> --wallet <wallet> [--live]",
|
|
2344
|
+
"Usage: slrd meteora close-all <pool> --wallet <wallet> [--live] or slrd meteora close-all --all-wallets --all-pools [--live]",
|
|
2203
2345
|
);
|
|
2204
2346
|
const walletRef = requiredFlag(flags, "wallet");
|
|
2205
2347
|
const walletAddress = publicWalletAddress(slrd, walletRef);
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
buildPumpExternalDeployment,
|
|
6
|
+
createTraderSolard,
|
|
7
|
+
type PumpExternalDeploymentBuild,
|
|
8
|
+
} from "@solard/sdk";
|
|
9
|
+
|
|
10
|
+
export type ExternalPumpFlags = Map<string, string>;
|
|
11
|
+
|
|
12
|
+
function parse(argv: string[]): ExternalPumpFlags {
|
|
13
|
+
const flags = new Map<string, string>();
|
|
14
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
15
|
+
const item = argv[index]!;
|
|
16
|
+
if (!item.startsWith("--")) continue;
|
|
17
|
+
const [key, inline] = item.slice(2).split("=", 2);
|
|
18
|
+
if (inline != null) flags.set(key!, inline);
|
|
19
|
+
else if (argv[index + 1] && !argv[index + 1]!.startsWith("--"))
|
|
20
|
+
flags.set(key!, argv[++index]!);
|
|
21
|
+
else flags.set(key!, "true");
|
|
22
|
+
}
|
|
23
|
+
return flags;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function value(flags: ExternalPumpFlags, key: string): string | undefined {
|
|
27
|
+
const result = flags.get(key);
|
|
28
|
+
return result && result !== "true" ? result : undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function required(flags: ExternalPumpFlags, key: string): string {
|
|
32
|
+
const result = value(flags, key);
|
|
33
|
+
if (!result) throw new Error(`Missing --${key} <value>`);
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function integer(
|
|
38
|
+
flags: ExternalPumpFlags,
|
|
39
|
+
key: string,
|
|
40
|
+
fallback: number,
|
|
41
|
+
): number {
|
|
42
|
+
const raw = value(flags, key);
|
|
43
|
+
if (raw == null) return fallback;
|
|
44
|
+
const parsed = Number(raw);
|
|
45
|
+
if (!Number.isFinite(parsed) || parsed < 0)
|
|
46
|
+
throw new Error(`Invalid --${key}: ${raw}`);
|
|
47
|
+
return Math.trunc(parsed);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function printable(build: PumpExternalDeploymentBuild) {
|
|
51
|
+
return {
|
|
52
|
+
version: build.version,
|
|
53
|
+
launchpad: build.launchpad,
|
|
54
|
+
transactionBase64: build.transactionBase64,
|
|
55
|
+
payer: build.payer,
|
|
56
|
+
mint: build.mint,
|
|
57
|
+
beneficiary: build.beneficiary,
|
|
58
|
+
pair: build.quoteKind === "native-sol" ? "SOL" : build.quoteMint,
|
|
59
|
+
quoteMint: build.quoteMint,
|
|
60
|
+
quoteKind: build.quoteKind,
|
|
61
|
+
quoteDecimals: build.quoteDecimals,
|
|
62
|
+
quoteTokenProgram: build.quoteTokenProgram,
|
|
63
|
+
requiredSignerPubkeys: build.requiredSignerPubkeys,
|
|
64
|
+
partialSignerPubkeys: build.partialSignerPubkeys,
|
|
65
|
+
missingSignerPubkeys: build.missingSignerPubkeys,
|
|
66
|
+
blockhash: build.blockhash,
|
|
67
|
+
lastValidBlockHeight: build.lastValidBlockHeight,
|
|
68
|
+
serializedSize: build.serializedSize,
|
|
69
|
+
token: build.token,
|
|
70
|
+
broadcast: false,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Prepare a Pump create_v2 transaction for Phantom or another external wallet.
|
|
76
|
+
* No persisted Solard signing wallet is opened or decrypted, and nothing is sent.
|
|
77
|
+
*/
|
|
78
|
+
export async function runPumpExternalDeploymentFromArgs(
|
|
79
|
+
argv: string[],
|
|
80
|
+
): Promise<ReturnType<typeof printable>> {
|
|
81
|
+
const flags = parse(argv);
|
|
82
|
+
if (flags.has("live")) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
"External-wallet preparation never broadcasts. Remove --live, sign transactionBase64 with Phantom, then broadcast from the wallet/frontend.",
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const payer = required(flags, "payer");
|
|
89
|
+
const name = required(flags, "name");
|
|
90
|
+
const symbol = required(flags, "symbol");
|
|
91
|
+
const uri = required(flags, "uri");
|
|
92
|
+
const pair = value(flags, "pair") ?? value(flags, "quote-mint") ?? "SOL";
|
|
93
|
+
const beneficiary = value(flags, "beneficiary") ?? payer;
|
|
94
|
+
|
|
95
|
+
const slrd = createTraderSolard();
|
|
96
|
+
try {
|
|
97
|
+
const build = await buildPumpExternalDeployment({
|
|
98
|
+
connection: slrd.connection(),
|
|
99
|
+
payer,
|
|
100
|
+
name,
|
|
101
|
+
symbol,
|
|
102
|
+
uri,
|
|
103
|
+
pair,
|
|
104
|
+
beneficiary,
|
|
105
|
+
mayhemMode: flags.has("mayhem"),
|
|
106
|
+
cashback: flags.has("cashback"),
|
|
107
|
+
cuLimit: integer(flags, "cu-limit", 600_000),
|
|
108
|
+
priorityMicroLamports: integer(flags, "priority-micro-lamports", 0),
|
|
109
|
+
});
|
|
110
|
+
const output = printable(build);
|
|
111
|
+
const encoded = `${JSON.stringify(output, null, 2)}\n`;
|
|
112
|
+
const out = value(flags, "out");
|
|
113
|
+
if (out) {
|
|
114
|
+
const path = resolve(out);
|
|
115
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
116
|
+
writeFileSync(path, encoded, { flag: "w" });
|
|
117
|
+
process.stdout.write(
|
|
118
|
+
`🦉 prepared Pump deployment\n` +
|
|
119
|
+
` mint ${build.mint}\n` +
|
|
120
|
+
` payer ${build.payer} (Phantom signature required)\n` +
|
|
121
|
+
` beneficiary ${build.beneficiary}\n` +
|
|
122
|
+
` pair ${build.quoteKind === "native-sol" ? "SOL" : build.quoteMint}\n` +
|
|
123
|
+
` mint signer signed\n` +
|
|
124
|
+
` broadcast NO\n` +
|
|
125
|
+
` output ${path}\n`,
|
|
126
|
+
);
|
|
127
|
+
} else {
|
|
128
|
+
// The transaction is the product of this command, so stdout is machine-ready
|
|
129
|
+
// JSON by default when no explicit output file is supplied.
|
|
130
|
+
process.stdout.write(encoded);
|
|
131
|
+
}
|
|
132
|
+
return output;
|
|
133
|
+
} finally {
|
|
134
|
+
slrd.close();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
cleanVanitySuffix,
|
|
11
11
|
defaultVanityMaxAttempts,
|
|
12
12
|
executePumpTokenLaunch,
|
|
13
|
+
findExternalContact,
|
|
13
14
|
generateMintKeypairWithSuffix,
|
|
14
15
|
installPumpLaunchSenders,
|
|
15
16
|
loadExplicitBuyerAllocations,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
parseArmedBuyerEndpoint,
|
|
19
20
|
PUMP_PROGRAM_ID,
|
|
20
21
|
preparePumpTokenLaunch,
|
|
22
|
+
resolvePumpQuoteAsset,
|
|
21
23
|
pumpLaunchEnvironment,
|
|
22
24
|
releaseArmedBuyerEndpoints,
|
|
23
25
|
releaseVanityMintReservation,
|
|
@@ -35,6 +37,7 @@ import {
|
|
|
35
37
|
type PumpLaunchEnvironment,
|
|
36
38
|
type PumpTokenLaunchPlan,
|
|
37
39
|
type PumpTokenLaunchResult,
|
|
40
|
+
type QuoteAsset,
|
|
38
41
|
type SendReceipt,
|
|
39
42
|
type SimulationResult,
|
|
40
43
|
type Solard,
|
|
@@ -73,7 +76,10 @@ export type PumpTokenLaunchCliOptions = {
|
|
|
73
76
|
export type PumpTokenLaunchCliResult = {
|
|
74
77
|
createdAt: string;
|
|
75
78
|
live: boolean;
|
|
79
|
+
/** Transaction payer / local signing wallet. */
|
|
76
80
|
creator: string;
|
|
81
|
+
/** On-chain Pump creator fee/reward beneficiary. */
|
|
82
|
+
beneficiary: string;
|
|
77
83
|
buyerGroup: string | null;
|
|
78
84
|
buyPlan?: string | null;
|
|
79
85
|
transport: Record<string, unknown>;
|
|
@@ -82,6 +88,10 @@ export type PumpTokenLaunchCliResult = {
|
|
|
82
88
|
metadataUri: string;
|
|
83
89
|
mint: string;
|
|
84
90
|
feeMode: "creator-fees";
|
|
91
|
+
pair: "SOL" | "USDC" | "mint";
|
|
92
|
+
quoteMint: string;
|
|
93
|
+
quoteDecimals: number;
|
|
94
|
+
beneficiary: string;
|
|
85
95
|
cashback: boolean;
|
|
86
96
|
mayhemMode: boolean;
|
|
87
97
|
vanityMintSuffix?: string | null;
|
|
@@ -1125,6 +1135,8 @@ export async function preparePumpTokenLaunchFromFlags(args: {
|
|
|
1125
1135
|
flags: Flags;
|
|
1126
1136
|
token: TokenMetadata;
|
|
1127
1137
|
creator: string;
|
|
1138
|
+
creatorBeneficiary?: PublicKey;
|
|
1139
|
+
quoteAsset?: QuoteAsset;
|
|
1128
1140
|
env?: PumpLaunchEnvironment;
|
|
1129
1141
|
options?: PumpTokenLaunchCliOptions;
|
|
1130
1142
|
mint?: Keypair;
|
|
@@ -1226,6 +1238,8 @@ export async function preparePumpTokenLaunchFromFlags(args: {
|
|
|
1226
1238
|
),
|
|
1227
1239
|
senderPolicy: env.policy,
|
|
1228
1240
|
mint: args.mint,
|
|
1241
|
+
creatorBeneficiary: args.creatorBeneficiary,
|
|
1242
|
+
quoteAsset: args.quoteAsset,
|
|
1229
1243
|
cashback: args.cashback ?? args.token.cashback ?? false,
|
|
1230
1244
|
mayhemMode: args.mayhemMode ?? args.token.mayhemMode ?? false,
|
|
1231
1245
|
});
|
|
@@ -1238,6 +1252,37 @@ function vanitySuffixFromFlags(flags: Flags): string | null {
|
|
|
1238
1252
|
return null;
|
|
1239
1253
|
}
|
|
1240
1254
|
|
|
1255
|
+
function resolvePublicAddress(
|
|
1256
|
+
slrd: Solard,
|
|
1257
|
+
value: string | undefined,
|
|
1258
|
+
fallback: PublicKey,
|
|
1259
|
+
label: string,
|
|
1260
|
+
): PublicKey {
|
|
1261
|
+
if (!value || value === "true") return fallback;
|
|
1262
|
+
try {
|
|
1263
|
+
return slrd.resolveWallet(value).address;
|
|
1264
|
+
} catch {
|
|
1265
|
+
// Stored wallet refs are convenient but not required for a beneficiary.
|
|
1266
|
+
}
|
|
1267
|
+
const contact = findExternalContact(value);
|
|
1268
|
+
if (contact) return new PublicKey(contact.address);
|
|
1269
|
+
try {
|
|
1270
|
+
return new PublicKey(value);
|
|
1271
|
+
} catch {
|
|
1272
|
+
throw new Error(
|
|
1273
|
+
`Invalid ${label} ${JSON.stringify(value)}. Use a stored wallet, contact, or Solana address.`,
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
function pairLabel(quoteAsset: QuoteAsset): "SOL" | "USDC" | "mint" {
|
|
1279
|
+
if (quoteAsset.kind === "native-sol") return "SOL";
|
|
1280
|
+
return quoteAsset.mint.toBase58() ===
|
|
1281
|
+
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
|
|
1282
|
+
? "USDC"
|
|
1283
|
+
: "mint";
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1241
1286
|
function envNumber(name: string, fallback: number): number {
|
|
1242
1287
|
const raw = process.env[name]?.trim();
|
|
1243
1288
|
if (!raw) return fallback;
|
|
@@ -1479,6 +1524,31 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1479
1524
|
const slrd = createTraderSolard({ rpcUrl: env.rpcUrl });
|
|
1480
1525
|
installPumpLaunchSenders(slrd, env);
|
|
1481
1526
|
|
|
1527
|
+
const payerAddress = slrd.resolveWallet(creator).address;
|
|
1528
|
+
const beneficiary = resolvePublicAddress(
|
|
1529
|
+
slrd,
|
|
1530
|
+
first(flags, "beneficiary"),
|
|
1531
|
+
payerAddress,
|
|
1532
|
+
"--beneficiary",
|
|
1533
|
+
);
|
|
1534
|
+
const pairInput = first(flags, "pair") ?? first(flags, "quote-mint") ?? "SOL";
|
|
1535
|
+
const quoteAsset = await resolvePumpQuoteAsset(slrd.connection(), pairInput);
|
|
1536
|
+
const creatorBuyLamports = optionalSol(
|
|
1537
|
+
flags,
|
|
1538
|
+
"creator-buy-sol",
|
|
1539
|
+
"creator-buy-lamports",
|
|
1540
|
+
0n,
|
|
1541
|
+
);
|
|
1542
|
+
if (
|
|
1543
|
+
quoteAsset.kind !== "native-sol" &&
|
|
1544
|
+
(hasBuyers || creatorBuyLamports > 0n)
|
|
1545
|
+
) {
|
|
1546
|
+
throw new Error(
|
|
1547
|
+
`Pump ${pairLabel(quoteAsset)}-paired launches currently support deploy-only creation. ` +
|
|
1548
|
+
"Buyer plans and --creator-buy-sol are SOL-denominated; Solard will not reinterpret them as quote-token amounts.",
|
|
1549
|
+
);
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1482
1552
|
if (vanityMint) {
|
|
1483
1553
|
await assertPumpMintIsUnused({
|
|
1484
1554
|
slrd,
|
|
@@ -1519,6 +1589,8 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1519
1589
|
flags,
|
|
1520
1590
|
token,
|
|
1521
1591
|
creator,
|
|
1592
|
+
creatorBeneficiary: beneficiary,
|
|
1593
|
+
quoteAsset,
|
|
1522
1594
|
env,
|
|
1523
1595
|
options,
|
|
1524
1596
|
mint: vanityMint,
|
|
@@ -1534,6 +1606,10 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1534
1606
|
name: input.name,
|
|
1535
1607
|
symbol: input.symbol,
|
|
1536
1608
|
mint,
|
|
1609
|
+
beneficiary: beneficiary.toBase58(),
|
|
1610
|
+
pair: pairLabel(quoteAsset),
|
|
1611
|
+
quoteMint: quoteAsset.mint.toBase58(),
|
|
1612
|
+
quoteDecimals: quoteAsset.decimals,
|
|
1537
1613
|
metadataUri: uri,
|
|
1538
1614
|
website: input.website ?? null,
|
|
1539
1615
|
twitter: input.twitter ?? null,
|
|
@@ -1559,12 +1635,7 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1559
1635
|
vanityMintSuffix,
|
|
1560
1636
|
vanityMintAttempts,
|
|
1561
1637
|
vanityMintElapsedMs,
|
|
1562
|
-
creatorBuyLamports
|
|
1563
|
-
flags,
|
|
1564
|
-
"creator-buy-sol",
|
|
1565
|
-
"creator-buy-lamports",
|
|
1566
|
-
0n,
|
|
1567
|
-
),
|
|
1638
|
+
creatorBuyLamports,
|
|
1568
1639
|
buyerGroup: group ?? null,
|
|
1569
1640
|
buyPlan:
|
|
1570
1641
|
first(flags, "buy-plan") ??
|
|
@@ -1674,6 +1745,7 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1674
1745
|
createdAt: new Date().toISOString(),
|
|
1675
1746
|
live,
|
|
1676
1747
|
creator,
|
|
1748
|
+
beneficiary: beneficiary.toBase58(),
|
|
1677
1749
|
buyerGroup: group ?? null,
|
|
1678
1750
|
buyPlan:
|
|
1679
1751
|
first(flags, "buy-plan") ??
|
|
@@ -1702,6 +1774,10 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1702
1774
|
metadataUri: uri,
|
|
1703
1775
|
mint,
|
|
1704
1776
|
feeMode: "creator-fees",
|
|
1777
|
+
pair: pairLabel(quoteAsset),
|
|
1778
|
+
quoteMint: quoteAsset.mint.toBase58(),
|
|
1779
|
+
quoteDecimals: quoteAsset.decimals,
|
|
1780
|
+
beneficiary: beneficiary.toBase58(),
|
|
1705
1781
|
cashback,
|
|
1706
1782
|
mayhemMode,
|
|
1707
1783
|
vanityMintSuffix,
|