@solard/cli 0.2.31 → 0.2.37
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 +9 -3
- package/src/commands/sell.ts +9 -3
- package/src/commands/trade-fees.test.ts +18 -6
- package/src/commands/trade-fees.ts +8 -2
- package/src/commands/transfer.test.ts +75 -18
- package/src/commands/transfer.ts +34 -6
- 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 +3 -1
- 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.37",
|
|
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.37",
|
|
23
|
+
"@solard/sdk": "0.2.37",
|
|
24
24
|
"bs58": "^6.0.0",
|
|
25
25
|
"measure-fn": "5.2.0"
|
|
26
26
|
},
|
package/src/commands/buy.ts
CHANGED
|
@@ -131,10 +131,16 @@ export async function runSmartBuyCommand({
|
|
|
131
131
|
.build();
|
|
132
132
|
const results = await Promise.all(
|
|
133
133
|
plans.map(async (plan, index) => {
|
|
134
|
-
const prepared = await slrd.prepareTradePlan(
|
|
135
|
-
|
|
134
|
+
const prepared = await slrd.prepareTradePlan(
|
|
135
|
+
target.refs[index]!,
|
|
136
|
+
plan,
|
|
137
|
+
options,
|
|
138
|
+
);
|
|
139
|
+
return {
|
|
140
|
+
...(await slrd.simulatePlan(prepared.plan)),
|
|
136
141
|
priorityMicroLamports: prepared.priorityMicroLamports,
|
|
137
|
-
cuLimit: prepared.plan.draft.cuLimit ?? 600_000
|
|
142
|
+
cuLimit: prepared.plan.draft.cuLimit ?? 600_000,
|
|
143
|
+
};
|
|
138
144
|
}),
|
|
139
145
|
);
|
|
140
146
|
return {
|
package/src/commands/sell.ts
CHANGED
|
@@ -169,10 +169,16 @@ export async function runSmartSellCommand({
|
|
|
169
169
|
.build();
|
|
170
170
|
const results = await Promise.all(
|
|
171
171
|
plans.map(async (plan, index) => {
|
|
172
|
-
const prepared = await slrd.prepareTradePlan(
|
|
173
|
-
|
|
172
|
+
const prepared = await slrd.prepareTradePlan(
|
|
173
|
+
target.refs[index]!,
|
|
174
|
+
plan,
|
|
175
|
+
options,
|
|
176
|
+
);
|
|
177
|
+
return {
|
|
178
|
+
...(await slrd.simulatePlan(prepared.plan)),
|
|
174
179
|
priorityMicroLamports: prepared.priorityMicroLamports,
|
|
175
|
-
cuLimit: prepared.plan.draft.cuLimit ?? 600_000
|
|
180
|
+
cuLimit: prepared.plan.draft.cuLimit ?? 600_000,
|
|
181
|
+
};
|
|
176
182
|
}),
|
|
177
183
|
);
|
|
178
184
|
return {
|
|
@@ -2,14 +2,26 @@ import { expect, test } from "bun:test";
|
|
|
2
2
|
import { tradeFeeOptions } from "./trade-fees.ts";
|
|
3
3
|
|
|
4
4
|
test("native buy/sell fee flags preserve custom compute limit and price", () => {
|
|
5
|
-
expect(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
expect(
|
|
6
|
+
tradeFeeOptions(
|
|
7
|
+
new Map([
|
|
8
|
+
["cu-limit", "150000"],
|
|
9
|
+
["priority-micro-lamports", "1000000"],
|
|
10
|
+
["trade-attempts", "4"],
|
|
11
|
+
["max-priority-fee-lamports", "500000"],
|
|
12
|
+
]),
|
|
13
|
+
),
|
|
14
|
+
).toMatchObject({
|
|
15
|
+
priorityFee: { cuLimit: 150_000, microLamports: 1_000_000 },
|
|
16
|
+
landing: { maxAttempts: 4, maxPriorityFeeLamports: 500_000 },
|
|
17
|
+
});
|
|
10
18
|
});
|
|
11
19
|
|
|
12
20
|
test("invalid fee flags reject instead of being ignored", () => {
|
|
13
|
-
for (const [name, value] of [
|
|
21
|
+
for (const [name, value] of [
|
|
22
|
+
["cu-limit", "0"],
|
|
23
|
+
["priority-micro-lamports", "-1"],
|
|
24
|
+
["priority-micro-lamports", "true"],
|
|
25
|
+
])
|
|
14
26
|
expect(() => tradeFeeOptions(new Map([[name!, value!]]))).toThrow();
|
|
15
27
|
});
|
|
@@ -10,9 +10,15 @@ export function tradeFeeOptions(flags: ReadonlyMap<string, string>) {
|
|
|
10
10
|
};
|
|
11
11
|
const cuLimit = number("cu-limit");
|
|
12
12
|
const microLamports = number("priority-micro-lamports");
|
|
13
|
-
if (
|
|
13
|
+
if (
|
|
14
|
+
cuLimit != null &&
|
|
15
|
+
(!Number.isInteger(cuLimit) || cuLimit < 1 || cuLimit > 1_400_000)
|
|
16
|
+
)
|
|
14
17
|
throw new Error("--cu-limit must be an integer between 1 and 1400000");
|
|
15
|
-
if (
|
|
18
|
+
if (
|
|
19
|
+
microLamports != null &&
|
|
20
|
+
(!Number.isSafeInteger(microLamports) || microLamports < 0)
|
|
21
|
+
)
|
|
16
22
|
throw new Error("--priority-micro-lamports must be a non-negative integer");
|
|
17
23
|
const landing: TradeLandingPolicy = {
|
|
18
24
|
maxAttempts: number("trade-attempts"),
|
|
@@ -3,31 +3,88 @@ import { Keypair } from "@solana/web3.js";
|
|
|
3
3
|
import { Solard, estimatePlanFee, type PlannedTransaction } from "@solard/core";
|
|
4
4
|
import { runTransferCommand } from "./transfer.ts";
|
|
5
5
|
function fixture(status: "confirmed" | "submitted" | "failed" = "confirmed") {
|
|
6
|
-
const core: Solard = Object.create(Solard.prototype);
|
|
7
|
-
const
|
|
6
|
+
const core: Solard = Object.create(Solard.prototype);
|
|
7
|
+
const payer = Keypair.generate();
|
|
8
|
+
const prices: number[] = [];
|
|
9
|
+
let samples = 0;
|
|
8
10
|
core.signer = () => payer;
|
|
9
|
-
core.connection = () =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
core.connection = () =>
|
|
12
|
+
({
|
|
13
|
+
getRecentPrioritizationFees: async () => {
|
|
14
|
+
samples++;
|
|
15
|
+
return [200_000, 400_000, 800_000, 1_000_000].map(
|
|
16
|
+
(prioritizationFee) => ({ prioritizationFee }),
|
|
17
|
+
);
|
|
18
|
+
},
|
|
19
|
+
getFeeForMessage: async (message: { price: number }) => ({
|
|
20
|
+
value: 5000 + Math.ceil((10_000 * message.price) / 1_000_000),
|
|
21
|
+
}),
|
|
22
|
+
}) as any;
|
|
23
|
+
core.compile = async (_payer, draft) =>
|
|
24
|
+
({
|
|
25
|
+
draft,
|
|
26
|
+
payer: payer.publicKey,
|
|
27
|
+
transaction: {
|
|
28
|
+
message: { price: draft.cuPriceMicroLamports ?? 100_000 },
|
|
29
|
+
},
|
|
30
|
+
}) as unknown as PlannedTransaction;
|
|
31
|
+
core.submitPlan = async (plan, sender) => {
|
|
32
|
+
prices.push(plan.draft.cuPriceMicroLamports!);
|
|
33
|
+
return {
|
|
34
|
+
signature: "test-signature",
|
|
35
|
+
executionId: 1,
|
|
36
|
+
sender,
|
|
37
|
+
plan,
|
|
38
|
+
feeEstimate: await estimatePlanFee(core.connection(), plan),
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
core.settleSubmission = async () => ({
|
|
42
|
+
signature: "test-signature",
|
|
43
|
+
sender: "rpc",
|
|
44
|
+
status,
|
|
45
|
+
slot: status === "confirmed" ? 1 : null,
|
|
46
|
+
...(status === "confirmed" ? { feeLamports: 13000 } : {}),
|
|
47
|
+
});
|
|
48
|
+
Object.defineProperty(core, "executions", {
|
|
49
|
+
value: { get: () => ({ metaJson: null }) },
|
|
50
|
+
});
|
|
17
51
|
return { core, prices, samples: () => samples };
|
|
18
52
|
}
|
|
19
|
-
const flags = (extra: Array<[string, string]> = []) =>
|
|
53
|
+
const flags = (extra: Array<[string, string]> = []) =>
|
|
54
|
+
new Map([["wallet", "bags"], ["sol", "2"], ["live", "true"], ...extra]);
|
|
20
55
|
test("SOL transfer uses writable market fees and reports selected versus actual network fees", async () => {
|
|
21
56
|
const ctx = fixture();
|
|
22
|
-
const result = await runTransferCommand({
|
|
23
|
-
|
|
24
|
-
|
|
57
|
+
const result = await runTransferCommand({
|
|
58
|
+
slrd: ctx.core,
|
|
59
|
+
values: [Keypair.generate().publicKey.toBase58()],
|
|
60
|
+
flags: flags(),
|
|
61
|
+
});
|
|
62
|
+
expect(ctx.prices).toEqual([800_000]);
|
|
63
|
+
expect(ctx.samples()).toBe(1);
|
|
64
|
+
expect(result.status).toBe("confirmed");
|
|
65
|
+
expect(result.feeEstimate).toEqual({
|
|
66
|
+
cuLimit: 10_000,
|
|
67
|
+
priorityMicroLamports: 800_000,
|
|
68
|
+
priorityFeeLamports: 8000,
|
|
69
|
+
estimatedBaseFeeLamports: 5000,
|
|
70
|
+
estimatedNetworkFeeLamports: 13000,
|
|
71
|
+
});
|
|
25
72
|
expect(result.feeLamports).toBe(13000);
|
|
26
73
|
});
|
|
27
74
|
test("explicit zero disables transfer fee estimation and pending outcome is never repeated blindly", async () => {
|
|
28
75
|
const ctx = fixture("submitted");
|
|
29
|
-
const result = await runTransferCommand({
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
76
|
+
const result = await runTransferCommand({
|
|
77
|
+
slrd: ctx.core,
|
|
78
|
+
values: [Keypair.generate().publicKey.toBase58()],
|
|
79
|
+
flags: flags([["priority-micro-lamports", "0"]]),
|
|
80
|
+
});
|
|
81
|
+
expect(ctx.prices).toEqual([0]);
|
|
82
|
+
expect(ctx.samples()).toBe(0);
|
|
83
|
+
expect(result.status).toBe("unresolved");
|
|
84
|
+
expect(result.code).toBe("UNRESOLVED");
|
|
85
|
+
expect(result.feeLamports).toBeUndefined();
|
|
86
|
+
expect(result.feeEstimate).toMatchObject({
|
|
87
|
+
priorityFeeLamports: 0,
|
|
88
|
+
estimatedNetworkFeeLamports: 5000,
|
|
89
|
+
});
|
|
33
90
|
});
|
package/src/commands/transfer.ts
CHANGED
|
@@ -144,7 +144,11 @@ export async function runTransferCommand({
|
|
|
144
144
|
.priorityFee({ cuLimit, microLamports: priorityMicroLamports });
|
|
145
145
|
|
|
146
146
|
if (flags.has("simulate-only")) {
|
|
147
|
-
const prepared = await slrd.prepareTradePlan(
|
|
147
|
+
const prepared = await slrd.prepareTradePlan(
|
|
148
|
+
wallet,
|
|
149
|
+
await composer.build(),
|
|
150
|
+
executionOptions,
|
|
151
|
+
);
|
|
148
152
|
const result = await slrd.simulatePlan(prepared.plan);
|
|
149
153
|
return {
|
|
150
154
|
mode: "simulation",
|
|
@@ -162,8 +166,18 @@ export async function runTransferCommand({
|
|
|
162
166
|
};
|
|
163
167
|
}
|
|
164
168
|
|
|
165
|
-
const execution = await slrd.executeTradePlan(
|
|
166
|
-
|
|
169
|
+
const execution = await slrd.executeTradePlan(
|
|
170
|
+
wallet,
|
|
171
|
+
() => composer.build(),
|
|
172
|
+
via,
|
|
173
|
+
"transfer-token",
|
|
174
|
+
executionOptions,
|
|
175
|
+
);
|
|
176
|
+
const receipt = tradeResult(
|
|
177
|
+
execution.receipt,
|
|
178
|
+
execution.attempts,
|
|
179
|
+
execution.submission.executionId,
|
|
180
|
+
);
|
|
167
181
|
|
|
168
182
|
return {
|
|
169
183
|
...receipt,
|
|
@@ -184,7 +198,11 @@ export async function runTransferCommand({
|
|
|
184
198
|
.priorityFee({ cuLimit, microLamports: priorityMicroLamports });
|
|
185
199
|
|
|
186
200
|
if (flags.has("simulate-only")) {
|
|
187
|
-
const prepared = await slrd.prepareTradePlan(
|
|
201
|
+
const prepared = await slrd.prepareTradePlan(
|
|
202
|
+
wallet,
|
|
203
|
+
await composer.build(),
|
|
204
|
+
executionOptions,
|
|
205
|
+
);
|
|
188
206
|
const result = await slrd.simulatePlan(prepared.plan);
|
|
189
207
|
return {
|
|
190
208
|
mode: "simulation",
|
|
@@ -198,8 +216,18 @@ export async function runTransferCommand({
|
|
|
198
216
|
};
|
|
199
217
|
}
|
|
200
218
|
|
|
201
|
-
const execution = await slrd.executeTradePlan(
|
|
202
|
-
|
|
219
|
+
const execution = await slrd.executeTradePlan(
|
|
220
|
+
wallet,
|
|
221
|
+
() => composer.build(),
|
|
222
|
+
via,
|
|
223
|
+
"transfer-sol",
|
|
224
|
+
executionOptions,
|
|
225
|
+
);
|
|
226
|
+
const receipt = tradeResult(
|
|
227
|
+
execution.receipt,
|
|
228
|
+
execution.attempts,
|
|
229
|
+
execution.submission.executionId,
|
|
230
|
+
);
|
|
203
231
|
|
|
204
232
|
return { ...receipt, recipient, wallet, sol: amount };
|
|
205
233
|
}
|