@solard/cli 0.2.29 → 0.2.31
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 +3 -3
- package/src/commands/buy.ts +216 -216
- package/src/commands/sell.ts +248 -248
- package/src/commands/trade-fees.test.ts +15 -15
- package/src/commands/trade-fees.ts +24 -24
- package/src/commands/transfer.test.ts +33 -0
- package/src/commands/transfer.ts +205 -200
- package/src/index.ts +3330 -3330
- package/src/launch-watch-command.ts +301 -301
- package/src/price-feed-client.ts +174 -174
- package/src/price-feed-protocol.ts +45 -45
- package/src/price-feed-server.architecture.test.ts +20 -20
- package/src/price-feed-server.ts +315 -315
- package/src/refs.ts +59 -56
- package/src/trade-strategy-command.ts +1219 -1219
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solard/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.31",
|
|
4
4
|
"description": "Command-line interface for the Solard SDK.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@solana/web3.js": "^1.98.4",
|
|
22
|
-
"@solard/core": "0.2.
|
|
23
|
-
"@solard/sdk": "0.2.
|
|
22
|
+
"@solard/core": "0.2.31",
|
|
23
|
+
"@solard/sdk": "0.2.31",
|
|
24
24
|
"bs58": "^6.0.0",
|
|
25
25
|
"measure-fn": "5.2.0"
|
|
26
26
|
},
|
package/src/commands/buy.ts
CHANGED
|
@@ -1,216 +1,216 @@
|
|
|
1
|
-
import {
|
|
2
|
-
executeJupiterSwap,
|
|
3
|
-
NATIVE_SOL_MINT,
|
|
4
|
-
nativePumpTradeAvailable,
|
|
5
|
-
quoteJupiterSwap,
|
|
6
|
-
resolveTradeRoute,
|
|
7
|
-
sol,
|
|
8
|
-
type SenderId,
|
|
9
|
-
type Solard,
|
|
10
|
-
} from "@solard/core";
|
|
11
|
-
|
|
12
|
-
import { resolveTradeTargets, type TradeTargets } from "./trade-targets.ts";
|
|
13
|
-
import { tradeFeeOptions } from "./trade-fees.ts";
|
|
14
|
-
import { summarizeTradeRoute, type TradeRouteSummary } from "./trade-result.ts";
|
|
15
|
-
import { parseVenuePreference, type TradeCommandFlags } from "./trade-venue.ts";
|
|
16
|
-
|
|
17
|
-
export type SmartBuyCommandResult =
|
|
18
|
-
| {
|
|
19
|
-
mode: "simulation";
|
|
20
|
-
route: "native";
|
|
21
|
-
target: TradeTargets;
|
|
22
|
-
routing: TradeRouteSummary;
|
|
23
|
-
results: unknown[];
|
|
24
|
-
}
|
|
25
|
-
| {
|
|
26
|
-
mode: "quote";
|
|
27
|
-
route: "jupiter";
|
|
28
|
-
target: TradeTargets;
|
|
29
|
-
routing: TradeRouteSummary;
|
|
30
|
-
amountSol: string;
|
|
31
|
-
quote: Awaited<ReturnType<typeof quoteJupiterSwap>>;
|
|
32
|
-
hint: string;
|
|
33
|
-
}
|
|
34
|
-
| {
|
|
35
|
-
mode: "live";
|
|
36
|
-
route: "native";
|
|
37
|
-
target: TradeTargets;
|
|
38
|
-
routing: TradeRouteSummary;
|
|
39
|
-
receipts: unknown;
|
|
40
|
-
}
|
|
41
|
-
| {
|
|
42
|
-
mode: "live";
|
|
43
|
-
route: "jupiter";
|
|
44
|
-
target: TradeTargets;
|
|
45
|
-
routing: TradeRouteSummary;
|
|
46
|
-
results: Array<{
|
|
47
|
-
wallet: string;
|
|
48
|
-
result: Awaited<ReturnType<typeof executeJupiterSwap>>;
|
|
49
|
-
}>;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
type RunSmartBuyCommandArgs = {
|
|
53
|
-
slrd: Solard;
|
|
54
|
-
values: string[];
|
|
55
|
-
flags: TradeCommandFlags;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
function intFlag(
|
|
59
|
-
flags: TradeCommandFlags,
|
|
60
|
-
key: string,
|
|
61
|
-
fallback: number,
|
|
62
|
-
): number {
|
|
63
|
-
const value = flags.get(key);
|
|
64
|
-
if (!value || value === "true") return fallback;
|
|
65
|
-
const parsed = Number(value);
|
|
66
|
-
if (!Number.isInteger(parsed)) throw new Error(`--${key} must be an integer`);
|
|
67
|
-
return parsed;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export async function runSmartBuyCommand({
|
|
71
|
-
slrd,
|
|
72
|
-
values,
|
|
73
|
-
flags,
|
|
74
|
-
}: RunSmartBuyCommandArgs): Promise<SmartBuyCommandResult> {
|
|
75
|
-
const tokenRef = values[0];
|
|
76
|
-
const usage =
|
|
77
|
-
"Usage: slrd buy <token|ca> (--wallet <wallet> | --wallets <w1,w2> | --group <group>) --sol <amount> [--venue auto|native|jupiter]";
|
|
78
|
-
if (!tokenRef) throw new Error(usage);
|
|
79
|
-
|
|
80
|
-
const amountSol = flags.get("sol");
|
|
81
|
-
if (!amountSol || amountSol === "true") {
|
|
82
|
-
throw new Error("Buy requires explicit --sol <amount>");
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const amount = sol(amountSol);
|
|
86
|
-
if (amount.raw <= 0n) throw new Error("--sol must be greater than zero");
|
|
87
|
-
|
|
88
|
-
const target = resolveTradeTargets(slrd, flags, usage);
|
|
89
|
-
const resolution = await resolveTradeRoute(
|
|
90
|
-
slrd,
|
|
91
|
-
tokenRef,
|
|
92
|
-
parseVenuePreference(flags),
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
if (resolution.asset.mint === NATIVE_SOL_MINT) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
"slrd buy expects an SPL token; SOL is already the input asset",
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (resolution.route === "native") {
|
|
102
|
-
if (!nativePumpTradeAvailable(resolution.token)) {
|
|
103
|
-
throw new Error(
|
|
104
|
-
"Native buy requires a registered Pump/PumpSwap token; use --venue jupiter for ordinary SPL assets",
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const options = {
|
|
109
|
-
...tradeFeeOptions(flags),
|
|
110
|
-
slippageBps: intFlag(flags, "slippage-bps", 1_500),
|
|
111
|
-
via: (flags.get("sender") ?? "rpc") as SenderId,
|
|
112
|
-
skipSimulation: flags.has("skip-simulation"),
|
|
113
|
-
skipPreflight:
|
|
114
|
-
flags.has("skip-preflight") || flags.has("skip-simulation"),
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
if (flags.has("simulate-only")) {
|
|
118
|
-
const plans =
|
|
119
|
-
target.refs.length === 1
|
|
120
|
-
? [
|
|
121
|
-
await slrd
|
|
122
|
-
.tx(target.refs[0]!)
|
|
123
|
-
.priorityFee(options.priorityFee)
|
|
124
|
-
.buy(resolution.token!.mint, amount, options)
|
|
125
|
-
.build(),
|
|
126
|
-
]
|
|
127
|
-
: await slrd
|
|
128
|
-
.composeMany(target.refs)
|
|
129
|
-
.priorityFee(options.priorityFee)
|
|
130
|
-
.buy(resolution.token!.mint, amount, options)
|
|
131
|
-
.build();
|
|
132
|
-
const results = await Promise.all(
|
|
133
|
-
plans.map(async (plan, index) => {
|
|
134
|
-
const prepared = await slrd.prepareTradePlan(target.refs[index]!, plan, options);
|
|
135
|
-
return { ...await slrd.simulatePlan(prepared.plan),
|
|
136
|
-
priorityMicroLamports: prepared.priorityMicroLamports,
|
|
137
|
-
cuLimit: prepared.plan.draft.cuLimit ?? 600_000 };
|
|
138
|
-
}),
|
|
139
|
-
);
|
|
140
|
-
return {
|
|
141
|
-
mode: "simulation",
|
|
142
|
-
route: "native",
|
|
143
|
-
target,
|
|
144
|
-
routing: summarizeTradeRoute(resolution),
|
|
145
|
-
results,
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const receipts =
|
|
150
|
-
target.refs.length === 1
|
|
151
|
-
? await slrd.buy(
|
|
152
|
-
resolution.token!.mint,
|
|
153
|
-
target.refs[0]!,
|
|
154
|
-
amount,
|
|
155
|
-
options,
|
|
156
|
-
)
|
|
157
|
-
: await slrd.buyMany(
|
|
158
|
-
resolution.token!.mint,
|
|
159
|
-
target.refs,
|
|
160
|
-
amount,
|
|
161
|
-
options,
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
mode: "live",
|
|
166
|
-
route: "native",
|
|
167
|
-
target,
|
|
168
|
-
routing: summarizeTradeRoute(resolution),
|
|
169
|
-
receipts,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (flags.has("simulate-only")) {
|
|
174
|
-
const quote = await quoteJupiterSwap({
|
|
175
|
-
inputMint: NATIVE_SOL_MINT,
|
|
176
|
-
outputMint: resolution.asset.mint,
|
|
177
|
-
amountRaw: amount.raw,
|
|
178
|
-
});
|
|
179
|
-
return {
|
|
180
|
-
mode: "quote",
|
|
181
|
-
route: "jupiter",
|
|
182
|
-
target,
|
|
183
|
-
routing: summarizeTradeRoute(resolution),
|
|
184
|
-
amountSol,
|
|
185
|
-
quote,
|
|
186
|
-
hint: "Remove --simulate-only to execute this Jupiter-routed buy.",
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Jupiter transport has its own measured, instance-scoped rate limiter. Keep
|
|
191
|
-
// multi-wallet execution sequential so a one-shot CLI command cannot create
|
|
192
|
-
// an avoidable burst against the API.
|
|
193
|
-
const results: Array<{
|
|
194
|
-
wallet: string;
|
|
195
|
-
result: Awaited<ReturnType<typeof executeJupiterSwap>>;
|
|
196
|
-
}> = [];
|
|
197
|
-
for (const wallet of target.refs) {
|
|
198
|
-
results.push({
|
|
199
|
-
wallet,
|
|
200
|
-
result: await executeJupiterSwap({
|
|
201
|
-
inputMint: NATIVE_SOL_MINT,
|
|
202
|
-
outputMint: resolution.asset.mint,
|
|
203
|
-
amountRaw: amount.raw,
|
|
204
|
-
signer: slrd.signer(wallet),
|
|
205
|
-
}),
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return {
|
|
210
|
-
mode: "live",
|
|
211
|
-
route: "jupiter",
|
|
212
|
-
target,
|
|
213
|
-
routing: summarizeTradeRoute(resolution),
|
|
214
|
-
results,
|
|
215
|
-
};
|
|
216
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
executeJupiterSwap,
|
|
3
|
+
NATIVE_SOL_MINT,
|
|
4
|
+
nativePumpTradeAvailable,
|
|
5
|
+
quoteJupiterSwap,
|
|
6
|
+
resolveTradeRoute,
|
|
7
|
+
sol,
|
|
8
|
+
type SenderId,
|
|
9
|
+
type Solard,
|
|
10
|
+
} from "@solard/core";
|
|
11
|
+
|
|
12
|
+
import { resolveTradeTargets, type TradeTargets } from "./trade-targets.ts";
|
|
13
|
+
import { tradeFeeOptions } from "./trade-fees.ts";
|
|
14
|
+
import { summarizeTradeRoute, type TradeRouteSummary } from "./trade-result.ts";
|
|
15
|
+
import { parseVenuePreference, type TradeCommandFlags } from "./trade-venue.ts";
|
|
16
|
+
|
|
17
|
+
export type SmartBuyCommandResult =
|
|
18
|
+
| {
|
|
19
|
+
mode: "simulation";
|
|
20
|
+
route: "native";
|
|
21
|
+
target: TradeTargets;
|
|
22
|
+
routing: TradeRouteSummary;
|
|
23
|
+
results: unknown[];
|
|
24
|
+
}
|
|
25
|
+
| {
|
|
26
|
+
mode: "quote";
|
|
27
|
+
route: "jupiter";
|
|
28
|
+
target: TradeTargets;
|
|
29
|
+
routing: TradeRouteSummary;
|
|
30
|
+
amountSol: string;
|
|
31
|
+
quote: Awaited<ReturnType<typeof quoteJupiterSwap>>;
|
|
32
|
+
hint: string;
|
|
33
|
+
}
|
|
34
|
+
| {
|
|
35
|
+
mode: "live";
|
|
36
|
+
route: "native";
|
|
37
|
+
target: TradeTargets;
|
|
38
|
+
routing: TradeRouteSummary;
|
|
39
|
+
receipts: unknown;
|
|
40
|
+
}
|
|
41
|
+
| {
|
|
42
|
+
mode: "live";
|
|
43
|
+
route: "jupiter";
|
|
44
|
+
target: TradeTargets;
|
|
45
|
+
routing: TradeRouteSummary;
|
|
46
|
+
results: Array<{
|
|
47
|
+
wallet: string;
|
|
48
|
+
result: Awaited<ReturnType<typeof executeJupiterSwap>>;
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
type RunSmartBuyCommandArgs = {
|
|
53
|
+
slrd: Solard;
|
|
54
|
+
values: string[];
|
|
55
|
+
flags: TradeCommandFlags;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
function intFlag(
|
|
59
|
+
flags: TradeCommandFlags,
|
|
60
|
+
key: string,
|
|
61
|
+
fallback: number,
|
|
62
|
+
): number {
|
|
63
|
+
const value = flags.get(key);
|
|
64
|
+
if (!value || value === "true") return fallback;
|
|
65
|
+
const parsed = Number(value);
|
|
66
|
+
if (!Number.isInteger(parsed)) throw new Error(`--${key} must be an integer`);
|
|
67
|
+
return parsed;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function runSmartBuyCommand({
|
|
71
|
+
slrd,
|
|
72
|
+
values,
|
|
73
|
+
flags,
|
|
74
|
+
}: RunSmartBuyCommandArgs): Promise<SmartBuyCommandResult> {
|
|
75
|
+
const tokenRef = values[0];
|
|
76
|
+
const usage =
|
|
77
|
+
"Usage: slrd buy <token|ca> (--wallet <wallet> | --wallets <w1,w2> | --group <group>) --sol <amount> [--venue auto|native|jupiter]";
|
|
78
|
+
if (!tokenRef) throw new Error(usage);
|
|
79
|
+
|
|
80
|
+
const amountSol = flags.get("sol");
|
|
81
|
+
if (!amountSol || amountSol === "true") {
|
|
82
|
+
throw new Error("Buy requires explicit --sol <amount>");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const amount = sol(amountSol);
|
|
86
|
+
if (amount.raw <= 0n) throw new Error("--sol must be greater than zero");
|
|
87
|
+
|
|
88
|
+
const target = resolveTradeTargets(slrd, flags, usage);
|
|
89
|
+
const resolution = await resolveTradeRoute(
|
|
90
|
+
slrd,
|
|
91
|
+
tokenRef,
|
|
92
|
+
parseVenuePreference(flags),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
if (resolution.asset.mint === NATIVE_SOL_MINT) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
"slrd buy expects an SPL token; SOL is already the input asset",
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (resolution.route === "native") {
|
|
102
|
+
if (!nativePumpTradeAvailable(resolution.token)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
"Native buy requires a registered Pump/PumpSwap token; use --venue jupiter for ordinary SPL assets",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const options = {
|
|
109
|
+
...tradeFeeOptions(flags),
|
|
110
|
+
slippageBps: intFlag(flags, "slippage-bps", 1_500),
|
|
111
|
+
via: (flags.get("sender") ?? "rpc") as SenderId,
|
|
112
|
+
skipSimulation: flags.has("skip-simulation"),
|
|
113
|
+
skipPreflight:
|
|
114
|
+
flags.has("skip-preflight") || flags.has("skip-simulation"),
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
if (flags.has("simulate-only")) {
|
|
118
|
+
const plans =
|
|
119
|
+
target.refs.length === 1
|
|
120
|
+
? [
|
|
121
|
+
await slrd
|
|
122
|
+
.tx(target.refs[0]!)
|
|
123
|
+
.priorityFee(options.priorityFee)
|
|
124
|
+
.buy(resolution.token!.mint, amount, options)
|
|
125
|
+
.build(),
|
|
126
|
+
]
|
|
127
|
+
: await slrd
|
|
128
|
+
.composeMany(target.refs)
|
|
129
|
+
.priorityFee(options.priorityFee)
|
|
130
|
+
.buy(resolution.token!.mint, amount, options)
|
|
131
|
+
.build();
|
|
132
|
+
const results = await Promise.all(
|
|
133
|
+
plans.map(async (plan, index) => {
|
|
134
|
+
const prepared = await slrd.prepareTradePlan(target.refs[index]!, plan, options);
|
|
135
|
+
return { ...await slrd.simulatePlan(prepared.plan),
|
|
136
|
+
priorityMicroLamports: prepared.priorityMicroLamports,
|
|
137
|
+
cuLimit: prepared.plan.draft.cuLimit ?? 600_000 };
|
|
138
|
+
}),
|
|
139
|
+
);
|
|
140
|
+
return {
|
|
141
|
+
mode: "simulation",
|
|
142
|
+
route: "native",
|
|
143
|
+
target,
|
|
144
|
+
routing: summarizeTradeRoute(resolution),
|
|
145
|
+
results,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const receipts =
|
|
150
|
+
target.refs.length === 1
|
|
151
|
+
? await slrd.buy(
|
|
152
|
+
resolution.token!.mint,
|
|
153
|
+
target.refs[0]!,
|
|
154
|
+
amount,
|
|
155
|
+
options,
|
|
156
|
+
)
|
|
157
|
+
: await slrd.buyMany(
|
|
158
|
+
resolution.token!.mint,
|
|
159
|
+
target.refs,
|
|
160
|
+
amount,
|
|
161
|
+
options,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
mode: "live",
|
|
166
|
+
route: "native",
|
|
167
|
+
target,
|
|
168
|
+
routing: summarizeTradeRoute(resolution),
|
|
169
|
+
receipts,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (flags.has("simulate-only")) {
|
|
174
|
+
const quote = await quoteJupiterSwap({
|
|
175
|
+
inputMint: NATIVE_SOL_MINT,
|
|
176
|
+
outputMint: resolution.asset.mint,
|
|
177
|
+
amountRaw: amount.raw,
|
|
178
|
+
});
|
|
179
|
+
return {
|
|
180
|
+
mode: "quote",
|
|
181
|
+
route: "jupiter",
|
|
182
|
+
target,
|
|
183
|
+
routing: summarizeTradeRoute(resolution),
|
|
184
|
+
amountSol,
|
|
185
|
+
quote,
|
|
186
|
+
hint: "Remove --simulate-only to execute this Jupiter-routed buy.",
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Jupiter transport has its own measured, instance-scoped rate limiter. Keep
|
|
191
|
+
// multi-wallet execution sequential so a one-shot CLI command cannot create
|
|
192
|
+
// an avoidable burst against the API.
|
|
193
|
+
const results: Array<{
|
|
194
|
+
wallet: string;
|
|
195
|
+
result: Awaited<ReturnType<typeof executeJupiterSwap>>;
|
|
196
|
+
}> = [];
|
|
197
|
+
for (const wallet of target.refs) {
|
|
198
|
+
results.push({
|
|
199
|
+
wallet,
|
|
200
|
+
result: await executeJupiterSwap({
|
|
201
|
+
inputMint: NATIVE_SOL_MINT,
|
|
202
|
+
outputMint: resolution.asset.mint,
|
|
203
|
+
amountRaw: amount.raw,
|
|
204
|
+
signer: slrd.signer(wallet),
|
|
205
|
+
}),
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
mode: "live",
|
|
211
|
+
route: "jupiter",
|
|
212
|
+
target,
|
|
213
|
+
routing: summarizeTradeRoute(resolution),
|
|
214
|
+
results,
|
|
215
|
+
};
|
|
216
|
+
}
|