@solard/cli 0.2.6 → 0.2.7
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 +13 -13
- package/package.json +2 -2
- package/src/index.ts +2515 -926
- package/src/meteora-commands.ts +2356 -0
- package/src/pump/token-launch-cli.ts +118 -18
- package/src/pump/vamp-cli.ts +363 -0
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
assertArmedBuyerEndpointsReady,
|
|
8
8
|
bondingCurvePda,
|
|
9
9
|
createTraderSolard,
|
|
10
|
+
cleanVanitySuffix,
|
|
11
|
+
defaultVanityMaxAttempts,
|
|
10
12
|
executePumpTokenLaunch,
|
|
11
13
|
generateMintKeypairWithSuffix,
|
|
12
14
|
installPumpLaunchSenders,
|
|
@@ -18,6 +20,9 @@ import {
|
|
|
18
20
|
preparePumpTokenLaunch,
|
|
19
21
|
pumpLaunchEnvironment,
|
|
20
22
|
releaseArmedBuyerEndpoints,
|
|
23
|
+
releaseVanityMintReservation,
|
|
24
|
+
reserveVanityMintFromPool,
|
|
25
|
+
markVanityMintUsed,
|
|
21
26
|
sol,
|
|
22
27
|
TOKEN_2022_ID,
|
|
23
28
|
uploadPumpMetadata,
|
|
@@ -35,6 +40,7 @@ import {
|
|
|
35
40
|
type Solard,
|
|
36
41
|
type TokenMetadata,
|
|
37
42
|
type TraderSubmitMode,
|
|
43
|
+
type VanityMintPoolReservation,
|
|
38
44
|
} from "@solard/sdk";
|
|
39
45
|
|
|
40
46
|
export type Flags = Map<string, string[]>;
|
|
@@ -1027,30 +1033,61 @@ function parseBuyPlanRows(flags: Flags): ExplicitBuyerPlanRow[] | null {
|
|
|
1027
1033
|
stringValue(row, "address");
|
|
1028
1034
|
if (!wallet) throw new Error(`Buy plan row ${index + 1} is missing wallet`);
|
|
1029
1035
|
|
|
1036
|
+
const exactSol =
|
|
1037
|
+
stringValue(row, "exactSol") ??
|
|
1038
|
+
stringValue(row, "sol") ??
|
|
1039
|
+
stringValue(row, "amountSol");
|
|
1040
|
+
const exactLamports =
|
|
1041
|
+
bigintValue(row, "exactLamports") ??
|
|
1042
|
+
bigintValue(row, "lamports") ??
|
|
1043
|
+
bigintValue(row, "amountLamports");
|
|
1044
|
+
|
|
1045
|
+
if (exactSol != null && exactLamports != null) {
|
|
1046
|
+
throw new Error(
|
|
1047
|
+
`Buy plan row ${index + 1} supplies both SOL and lamport exact amounts`,
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
const configuredMode =
|
|
1052
|
+
stringValue(row, "amountMode") ?? stringValue(row, "mode");
|
|
1030
1053
|
const amountMode =
|
|
1031
|
-
|
|
1054
|
+
configuredMode ??
|
|
1055
|
+
(exactSol != null
|
|
1056
|
+
? "exact-sol"
|
|
1057
|
+
: exactLamports != null
|
|
1058
|
+
? "exact-lamports"
|
|
1059
|
+
: "range-bps");
|
|
1060
|
+
|
|
1061
|
+
const exactReserveLamports =
|
|
1062
|
+
solValue(row, "reserveSol", "reserveLamports") ?? 0n;
|
|
1063
|
+
|
|
1032
1064
|
let amount: ExplicitBuyerPlanRow["amount"];
|
|
1033
1065
|
if (amountMode === "exact-sol" || amountMode === "exact") {
|
|
1034
|
-
const exactSol =
|
|
1035
|
-
stringValue(row, "exactSol") ??
|
|
1036
|
-
stringValue(row, "sol") ??
|
|
1037
|
-
stringValue(row, "amountSol");
|
|
1038
1066
|
if (!exactSol)
|
|
1039
1067
|
throw new Error(
|
|
1040
|
-
`Buy plan row ${index + 1} exact-sol mode requires exactSol`,
|
|
1068
|
+
`Buy plan row ${index + 1} exact-sol mode requires exactSol/amountSol`,
|
|
1041
1069
|
);
|
|
1042
|
-
amount = {
|
|
1070
|
+
amount = {
|
|
1071
|
+
kind: "exact-sol",
|
|
1072
|
+
sol: exactSol,
|
|
1073
|
+
reserveLamports: exactReserveLamports,
|
|
1074
|
+
};
|
|
1043
1075
|
} else if (amountMode === "exact-lamports" || amountMode === "lamports") {
|
|
1044
|
-
|
|
1045
|
-
bigintValue(row, "exactLamports") ??
|
|
1046
|
-
bigintValue(row, "lamports") ??
|
|
1047
|
-
bigintValue(row, "amountLamports");
|
|
1048
|
-
if (lamports == null)
|
|
1076
|
+
if (exactLamports == null)
|
|
1049
1077
|
throw new Error(
|
|
1050
|
-
`Buy plan row ${index + 1} exact-lamports mode requires exactLamports`,
|
|
1078
|
+
`Buy plan row ${index + 1} exact-lamports mode requires exactLamports/amountLamports`,
|
|
1051
1079
|
);
|
|
1052
|
-
amount = {
|
|
1080
|
+
amount = {
|
|
1081
|
+
kind: "exact-lamports",
|
|
1082
|
+
lamports: exactLamports,
|
|
1083
|
+
reserveLamports: exactReserveLamports,
|
|
1084
|
+
};
|
|
1053
1085
|
} else {
|
|
1086
|
+
if (exactSol != null || exactLamports != null) {
|
|
1087
|
+
throw new Error(
|
|
1088
|
+
`Buy plan row ${index + 1} exact amount conflicts with amountMode ${amountMode}`,
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1054
1091
|
amount = {
|
|
1055
1092
|
kind: "balance-bps",
|
|
1056
1093
|
minBps:
|
|
@@ -1140,7 +1177,7 @@ export async function preparePumpTokenLaunchFromFlags(args: {
|
|
|
1140
1177
|
10_000n;
|
|
1141
1178
|
if (
|
|
1142
1179
|
spendLamports <= 0n ||
|
|
1143
|
-
finalTrader.balanceLamports
|
|
1180
|
+
finalTrader.balanceLamports < spendLamports + reserveLamports
|
|
1144
1181
|
) {
|
|
1145
1182
|
throw new Error(
|
|
1146
1183
|
`Final Jito buyer ${finalTrader.address} cannot cover buy, reserve, and tip: balance=${finalTrader.balanceLamports} spend=${spendLamports} reserve=${finalTrader.reserveLamports} jitoTip=${jitoTipLamports}`,
|
|
@@ -1287,8 +1324,32 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1287
1324
|
const { uri, uploaded } = await resolveMetadataUri(flags, input);
|
|
1288
1325
|
const cashback = enabled(flags, "cashback", "SOLARD_LAUNCH_CASHBACK");
|
|
1289
1326
|
const mayhemMode = enabled(flags, "mayhem", "SOLARD_LAUNCH_MAYHEM");
|
|
1290
|
-
const
|
|
1327
|
+
const vanityPoolSuffixRaw = nonEmpty(first(flags, "mint-pool"));
|
|
1328
|
+
const vanityPoolAddress = nonEmpty(first(flags, "mint-pool-address"));
|
|
1329
|
+
if (vanityPoolAddress && !vanityPoolSuffixRaw) {
|
|
1330
|
+
throw new Error("--mint-pool-address requires --mint-pool <suffix>.");
|
|
1331
|
+
}
|
|
1332
|
+
if (vanityPoolSuffixRaw && first(flags, "mint-keypair")) {
|
|
1333
|
+
throw new Error("Use either --mint-pool or --mint-keypair, not both.");
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
const vanityPoolSuffix = vanityPoolSuffixRaw
|
|
1337
|
+
? cleanVanitySuffix(vanityPoolSuffixRaw)
|
|
1338
|
+
: null;
|
|
1339
|
+
const configuredVanitySuffix = vanitySuffixFromFlags(flags);
|
|
1340
|
+
if (
|
|
1341
|
+
vanityPoolSuffix &&
|
|
1342
|
+
configuredVanitySuffix &&
|
|
1343
|
+
vanityPoolSuffix !== configuredVanitySuffix
|
|
1344
|
+
) {
|
|
1345
|
+
throw new Error(
|
|
1346
|
+
`--mint-pool suffix ${vanityPoolSuffix} conflicts with configured mint suffix ${configuredVanitySuffix}.`,
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
const vanityMintSuffix = vanityPoolSuffix ?? configuredVanitySuffix;
|
|
1291
1351
|
const pregeneratedMint = loadMintKeypairFromFlags(flags, vanityMintSuffix);
|
|
1352
|
+
let poolReservation: VanityMintPoolReservation | null = null;
|
|
1292
1353
|
let vanityMint: Keypair | undefined = pregeneratedMint?.mint;
|
|
1293
1354
|
let vanityMintAttempts: number | null = pregeneratedMint ? 0 : null;
|
|
1294
1355
|
let vanityMintElapsedMs: number | null = pregeneratedMint ? 0 : null;
|
|
@@ -1301,11 +1362,14 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1301
1362
|
attempts: 0,
|
|
1302
1363
|
elapsedMs: 0,
|
|
1303
1364
|
});
|
|
1304
|
-
} else if (vanityMintSuffix) {
|
|
1365
|
+
} else if (vanityMintSuffix && !vanityPoolSuffix) {
|
|
1305
1366
|
const maxAttempts = numberFlag(
|
|
1306
1367
|
flags,
|
|
1307
1368
|
"vanity-max-attempts",
|
|
1308
|
-
envNumber(
|
|
1369
|
+
envNumber(
|
|
1370
|
+
"SOLARD_VANITY_MINT_MAX_ATTEMPTS",
|
|
1371
|
+
defaultVanityMaxAttempts(vanityMintSuffix),
|
|
1372
|
+
),
|
|
1309
1373
|
);
|
|
1310
1374
|
const timeoutMs = numberFlag(
|
|
1311
1375
|
flags,
|
|
@@ -1396,6 +1460,22 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1396
1460
|
});
|
|
1397
1461
|
}
|
|
1398
1462
|
|
|
1463
|
+
if (!vanityMint && vanityPoolSuffix) {
|
|
1464
|
+
poolReservation = reserveVanityMintFromPool(vanityPoolSuffix, {
|
|
1465
|
+
address: vanityPoolAddress,
|
|
1466
|
+
reason: live ? "pump-launch-live" : "pump-launch-dry-run",
|
|
1467
|
+
});
|
|
1468
|
+
vanityMint = poolReservation.mint;
|
|
1469
|
+
vanityMintAttempts = 0;
|
|
1470
|
+
vanityMintElapsedMs = 0;
|
|
1471
|
+
report("vanity mint pool reserved", {
|
|
1472
|
+
mint: poolReservation.address,
|
|
1473
|
+
suffix: poolReservation.suffix,
|
|
1474
|
+
status: poolReservation.status,
|
|
1475
|
+
live,
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1399
1479
|
const slrd = createTraderSolard({ rpcUrl: env.rpcUrl });
|
|
1400
1480
|
installPumpLaunchSenders(slrd, env);
|
|
1401
1481
|
|
|
@@ -1572,6 +1652,15 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1572
1652
|
: undefined,
|
|
1573
1653
|
});
|
|
1574
1654
|
|
|
1655
|
+
if (poolReservation && live) {
|
|
1656
|
+
const used = markVanityMintUsed(poolReservation.address);
|
|
1657
|
+
report("vanity mint pool used", {
|
|
1658
|
+
mint: used.address,
|
|
1659
|
+
suffix: used.suffix,
|
|
1660
|
+
status: used.status,
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1575
1664
|
if (live && persistOnLive && prepared) {
|
|
1576
1665
|
try {
|
|
1577
1666
|
slrd.persistPreparedDeployment(prepared.deployment, input.alias);
|
|
@@ -1639,6 +1728,17 @@ export async function runPumpTokenLaunchFromArgs(
|
|
|
1639
1728
|
|
|
1640
1729
|
return output;
|
|
1641
1730
|
} finally {
|
|
1731
|
+
// Dry runs never consume a pooled mint. Live failures intentionally leave
|
|
1732
|
+
// it RESERVED because a bundle can be ambiguous even when local tracking
|
|
1733
|
+
// fails. Release it manually only after on-chain preflight confirms unused.
|
|
1734
|
+
if (poolReservation && !live) {
|
|
1735
|
+
try {
|
|
1736
|
+
releaseVanityMintReservation(poolReservation.address);
|
|
1737
|
+
} catch {
|
|
1738
|
+
// Preserve the primary launch/simulation result.
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1642
1742
|
// Never persist from finally: preflight, simulation, and bundle submission
|
|
1643
1743
|
// failures must leave the token registry untouched.
|
|
1644
1744
|
slrd.close();
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { extname, join, resolve } from "node:path";
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
createTraderSolard,
|
|
7
|
+
fetchPumpVampSourceMetadata,
|
|
8
|
+
publicPumpMetadataUrl,
|
|
9
|
+
uploadPumpMetadata,
|
|
10
|
+
type MetadataUploaderId,
|
|
11
|
+
type PumpVampSourceMetadata,
|
|
12
|
+
} from "@solard/sdk";
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
first,
|
|
16
|
+
parseArgs,
|
|
17
|
+
runPumpTokenLaunchFromArgs,
|
|
18
|
+
type PumpTokenLaunchCliOptions,
|
|
19
|
+
type PumpTokenLaunchCliResult,
|
|
20
|
+
} from "./token-launch-cli.ts";
|
|
21
|
+
|
|
22
|
+
export type PumpVampCliResult = {
|
|
23
|
+
source: PumpVampSourceMetadata;
|
|
24
|
+
resolved: {
|
|
25
|
+
alias: string;
|
|
26
|
+
name: string;
|
|
27
|
+
symbol: string;
|
|
28
|
+
uri: string;
|
|
29
|
+
metadataMode: "source-uri" | "override-uri" | "merged-upload";
|
|
30
|
+
overrides: string[];
|
|
31
|
+
};
|
|
32
|
+
launch: PumpTokenLaunchCliResult;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function clean(value: string | undefined): string | undefined {
|
|
36
|
+
const text = value?.trim();
|
|
37
|
+
return text && text !== "true" ? text : undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function safeAlias(symbol: string, sourceMint: string): string {
|
|
41
|
+
const stem =
|
|
42
|
+
symbol
|
|
43
|
+
.toLowerCase()
|
|
44
|
+
.replace(/[^a-z0-9_-]+/g, "-")
|
|
45
|
+
.replace(/^-+|-+$/g, "") || "token";
|
|
46
|
+
return `vamp-${stem}-${sourceMint.slice(0, 6).toLowerCase()}-${Date.now()
|
|
47
|
+
.toString(36)
|
|
48
|
+
.slice(-5)}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isRemote(value: string): boolean {
|
|
52
|
+
return /^(?:https?:\/\/|ipfs:\/\/|ar:\/\/)/i.test(value.trim());
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function imageExtension(value: string): string {
|
|
56
|
+
try {
|
|
57
|
+
const pathname = new URL(publicPumpMetadataUrl(value)).pathname;
|
|
58
|
+
const extension = extname(pathname);
|
|
59
|
+
return extension && extension.length <= 8 ? extension : ".img";
|
|
60
|
+
} catch {
|
|
61
|
+
const extension = extname(value);
|
|
62
|
+
return extension && extension.length <= 8 ? extension : ".img";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function downloadToTemp(
|
|
67
|
+
value: string,
|
|
68
|
+
): Promise<{ path: string; cleanup: () => void }> {
|
|
69
|
+
const directory = mkdtempSync(join(tmpdir(), "solard-vamp-"));
|
|
70
|
+
const url = publicPumpMetadataUrl(value);
|
|
71
|
+
const controller = new AbortController();
|
|
72
|
+
const timeout = setTimeout(() => controller.abort(), 20_000);
|
|
73
|
+
try {
|
|
74
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Could not download vamp image (${response.status}) from ${url}`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const bytes = Buffer.from(await response.arrayBuffer());
|
|
81
|
+
if (!bytes.length)
|
|
82
|
+
throw new Error(`Downloaded vamp image is empty: ${url}`);
|
|
83
|
+
const path = join(directory, `image${imageExtension(value)}`);
|
|
84
|
+
writeFileSync(path, bytes);
|
|
85
|
+
return {
|
|
86
|
+
path,
|
|
87
|
+
cleanup: () => rmSync(directory, { recursive: true, force: true }),
|
|
88
|
+
};
|
|
89
|
+
} catch (error) {
|
|
90
|
+
rmSync(directory, { recursive: true, force: true });
|
|
91
|
+
throw error;
|
|
92
|
+
} finally {
|
|
93
|
+
clearTimeout(timeout);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function resolveImagePath(
|
|
98
|
+
configured: string | undefined,
|
|
99
|
+
sourceImage: string | null,
|
|
100
|
+
): Promise<{ path: string; cleanup: () => void }> {
|
|
101
|
+
const selected = configured ?? sourceImage ?? undefined;
|
|
102
|
+
if (!selected) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
"Vamp metadata override requires an image. Source metadata has no image; provide --image <path-or-url>.",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (isRemote(selected)) return await downloadToTemp(selected);
|
|
109
|
+
|
|
110
|
+
const path = resolve(selected);
|
|
111
|
+
if (!existsSync(path)) {
|
|
112
|
+
throw new Error(`Vamp image file not found: ${path}`);
|
|
113
|
+
}
|
|
114
|
+
return { path, cleanup: () => {} };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function stripVampArgs(argv: string[]): string[] {
|
|
118
|
+
const handled = new Set([
|
|
119
|
+
"source-authority", // legacy v1 flag: intentionally ignored now
|
|
120
|
+
"alias",
|
|
121
|
+
"name",
|
|
122
|
+
"symbol",
|
|
123
|
+
"uri",
|
|
124
|
+
"metadata",
|
|
125
|
+
"image",
|
|
126
|
+
"description",
|
|
127
|
+
"website",
|
|
128
|
+
"twitter",
|
|
129
|
+
"telegram",
|
|
130
|
+
"video",
|
|
131
|
+
"show-name",
|
|
132
|
+
"hide-name",
|
|
133
|
+
"cashback",
|
|
134
|
+
]);
|
|
135
|
+
|
|
136
|
+
const result: string[] = [];
|
|
137
|
+
let sourceMintRemoved = false;
|
|
138
|
+
|
|
139
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
140
|
+
const item = argv[index]!;
|
|
141
|
+
if (!item.startsWith("--")) {
|
|
142
|
+
if (!sourceMintRemoved) {
|
|
143
|
+
sourceMintRemoved = true;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
result.push(item);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const [key, inline] = item.slice(2).split("=", 2);
|
|
151
|
+
if (!handled.has(key!)) {
|
|
152
|
+
result.push(item);
|
|
153
|
+
if (
|
|
154
|
+
inline == null &&
|
|
155
|
+
argv[index + 1] &&
|
|
156
|
+
!argv[index + 1]!.startsWith("--")
|
|
157
|
+
) {
|
|
158
|
+
result.push(argv[++index]!);
|
|
159
|
+
}
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (
|
|
164
|
+
inline == null &&
|
|
165
|
+
argv[index + 1] &&
|
|
166
|
+
!argv[index + 1]!.startsWith("--")
|
|
167
|
+
) {
|
|
168
|
+
index += 1;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function metadataProvider(
|
|
176
|
+
flags: ReturnType<typeof parseArgs>["flags"],
|
|
177
|
+
): MetadataUploaderId {
|
|
178
|
+
return (clean(first(flags, "metadata-provider")) ??
|
|
179
|
+
clean(process.env.SLRD_METADATA_UPLOADER) ??
|
|
180
|
+
clean(process.env.PUMP_METADATA_PROVIDER) ??
|
|
181
|
+
"pump-frontend") as MetadataUploaderId;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export async function runPumpVampFromArgs(
|
|
185
|
+
argv: string[],
|
|
186
|
+
options: PumpTokenLaunchCliOptions = {},
|
|
187
|
+
): Promise<PumpVampCliResult> {
|
|
188
|
+
const { flags, positionals } = parseArgs(argv);
|
|
189
|
+
if (positionals.length !== 1) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
"Usage: slrd vamp <source-mint> --creator <wallet> [metadata overrides] [launch flags]",
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
if (first(flags, "metadata")) {
|
|
195
|
+
throw new Error(
|
|
196
|
+
"vamp does not accept --metadata <file>; override individual fields or provide --uri <metadata-uri>.",
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const sourceMint = positionals[0]!;
|
|
201
|
+
const report = options.report ?? (() => {});
|
|
202
|
+
const sourceSlrd = createTraderSolard();
|
|
203
|
+
let source: PumpVampSourceMetadata;
|
|
204
|
+
try {
|
|
205
|
+
source = await fetchPumpVampSourceMetadata(
|
|
206
|
+
sourceSlrd.connection(),
|
|
207
|
+
sourceMint,
|
|
208
|
+
);
|
|
209
|
+
} finally {
|
|
210
|
+
sourceSlrd.close();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const alias =
|
|
214
|
+
clean(first(flags, "alias")) ?? safeAlias(source.symbol, source.mint);
|
|
215
|
+
const name = clean(first(flags, "name")) ?? source.name;
|
|
216
|
+
const symbol = clean(first(flags, "symbol")) ?? source.symbol;
|
|
217
|
+
const explicitUri = clean(first(flags, "uri"));
|
|
218
|
+
const image = clean(first(flags, "image"));
|
|
219
|
+
const description = clean(first(flags, "description"));
|
|
220
|
+
const website = clean(first(flags, "website"));
|
|
221
|
+
const twitter = clean(first(flags, "twitter"));
|
|
222
|
+
const telegram = clean(first(flags, "telegram"));
|
|
223
|
+
const video = clean(first(flags, "video"));
|
|
224
|
+
const showName = flags.has("hide-name")
|
|
225
|
+
? false
|
|
226
|
+
: flags.has("show-name")
|
|
227
|
+
? first(flags, "show-name") !== "false"
|
|
228
|
+
: (source.showName ?? true);
|
|
229
|
+
|
|
230
|
+
const overrides = [
|
|
231
|
+
["alias", clean(first(flags, "alias"))],
|
|
232
|
+
["name", clean(first(flags, "name"))],
|
|
233
|
+
["symbol", clean(first(flags, "symbol"))],
|
|
234
|
+
["uri", explicitUri],
|
|
235
|
+
["image", image],
|
|
236
|
+
["description", description],
|
|
237
|
+
["website", website],
|
|
238
|
+
["twitter", twitter],
|
|
239
|
+
["telegram", telegram],
|
|
240
|
+
["video", video],
|
|
241
|
+
[
|
|
242
|
+
"showName",
|
|
243
|
+
flags.has("show-name") || flags.has("hide-name") ? "set" : undefined,
|
|
244
|
+
],
|
|
245
|
+
]
|
|
246
|
+
.filter(([, value]) => value != null)
|
|
247
|
+
.map(([key]) => key!);
|
|
248
|
+
|
|
249
|
+
const hasJsonFieldOverrides = Boolean(
|
|
250
|
+
image ||
|
|
251
|
+
description ||
|
|
252
|
+
website ||
|
|
253
|
+
twitter ||
|
|
254
|
+
telegram ||
|
|
255
|
+
video ||
|
|
256
|
+
flags.has("show-name") ||
|
|
257
|
+
flags.has("hide-name"),
|
|
258
|
+
);
|
|
259
|
+
const shouldMergeUpload =
|
|
260
|
+
!explicitUri &&
|
|
261
|
+
Boolean(
|
|
262
|
+
clean(first(flags, "name")) ||
|
|
263
|
+
clean(first(flags, "symbol")) ||
|
|
264
|
+
hasJsonFieldOverrides,
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
if (explicitUri && hasJsonFieldOverrides) {
|
|
268
|
+
throw new Error(
|
|
269
|
+
"--uri already defines metadata JSON. Do not combine it with --image/--description/--website/--twitter/--telegram/--video/--show-name/--hide-name; put those fields in the supplied URI instead.",
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
let uri = explicitUri ?? source.uri;
|
|
274
|
+
let metadataMode: PumpVampCliResult["resolved"]["metadataMode"] = explicitUri
|
|
275
|
+
? "override-uri"
|
|
276
|
+
: "source-uri";
|
|
277
|
+
|
|
278
|
+
if (shouldMergeUpload) {
|
|
279
|
+
const imageFile = await resolveImagePath(image, source.image);
|
|
280
|
+
try {
|
|
281
|
+
const uploaded = await uploadPumpMetadata(
|
|
282
|
+
{
|
|
283
|
+
imagePath: imageFile.path,
|
|
284
|
+
name,
|
|
285
|
+
symbol,
|
|
286
|
+
description:
|
|
287
|
+
description ?? source.description ?? `${name} (${symbol})`,
|
|
288
|
+
website: website ?? source.website ?? undefined,
|
|
289
|
+
twitter: twitter ?? source.twitter ?? undefined,
|
|
290
|
+
telegram: telegram ?? source.telegram ?? undefined,
|
|
291
|
+
video: video ?? source.video ?? undefined,
|
|
292
|
+
showName,
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
provider: metadataProvider(flags),
|
|
296
|
+
},
|
|
297
|
+
);
|
|
298
|
+
uri = uploaded.metadataUri;
|
|
299
|
+
metadataMode = "merged-upload";
|
|
300
|
+
report("pump vamp metadata uploaded", {
|
|
301
|
+
provider: uploaded.provider,
|
|
302
|
+
metadataUri: uploaded.metadataUri,
|
|
303
|
+
imageUri: uploaded.imageUri ?? null,
|
|
304
|
+
});
|
|
305
|
+
} finally {
|
|
306
|
+
imageFile.cleanup();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
report("pump vamp source", {
|
|
311
|
+
mint: source.mint,
|
|
312
|
+
metadataKind: source.metadataKind,
|
|
313
|
+
sourceName: source.name,
|
|
314
|
+
sourceSymbol: source.symbol,
|
|
315
|
+
sourceUri: source.uri,
|
|
316
|
+
metadataJsonFetched: source.json != null,
|
|
317
|
+
});
|
|
318
|
+
report("pump vamp resolved", {
|
|
319
|
+
alias,
|
|
320
|
+
name,
|
|
321
|
+
symbol,
|
|
322
|
+
uri,
|
|
323
|
+
metadataMode,
|
|
324
|
+
overrides,
|
|
325
|
+
cashback: true,
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
const launchArgv = [
|
|
329
|
+
...stripVampArgs(argv),
|
|
330
|
+
"--alias",
|
|
331
|
+
alias,
|
|
332
|
+
"--name",
|
|
333
|
+
name,
|
|
334
|
+
"--symbol",
|
|
335
|
+
symbol,
|
|
336
|
+
"--uri",
|
|
337
|
+
uri,
|
|
338
|
+
"--cashback",
|
|
339
|
+
];
|
|
340
|
+
|
|
341
|
+
const launch = await runPumpTokenLaunchFromArgs(launchArgv, options);
|
|
342
|
+
|
|
343
|
+
report("pump vamp result", {
|
|
344
|
+
sourceMint: source.mint,
|
|
345
|
+
newMint: launch.token.mint,
|
|
346
|
+
alias,
|
|
347
|
+
cashback: true,
|
|
348
|
+
live: launch.live,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
source,
|
|
353
|
+
resolved: {
|
|
354
|
+
alias,
|
|
355
|
+
name,
|
|
356
|
+
symbol,
|
|
357
|
+
uri,
|
|
358
|
+
metadataMode,
|
|
359
|
+
overrides,
|
|
360
|
+
},
|
|
361
|
+
launch,
|
|
362
|
+
};
|
|
363
|
+
}
|