@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solard/cli",
3
- "version": "0.2.31",
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.31",
23
- "@solard/sdk": "0.2.31",
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
  },
@@ -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(target.refs[index]!, plan, options);
135
- return { ...await slrd.simulatePlan(prepared.plan),
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 {
@@ -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(target.refs[index]!, plan, options);
173
- return { ...await slrd.simulatePlan(prepared.plan),
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(tradeFeeOptions(new Map([
6
- ["cu-limit", "150000"], ["priority-micro-lamports", "1000000"],
7
- ["trade-attempts", "4"], ["max-priority-fee-lamports", "500000"],
8
- ]))).toMatchObject({ priorityFee: { cuLimit: 150_000, microLamports: 1_000_000 },
9
- landing: { maxAttempts: 4, maxPriorityFeeLamports: 500_000 } });
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 [["cu-limit", "0"], ["priority-micro-lamports", "-1"], ["priority-micro-lamports", "true"]])
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 (cuLimit != null && (!Number.isInteger(cuLimit) || cuLimit < 1 || cuLimit > 1_400_000))
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 (microLamports != null && (!Number.isSafeInteger(microLamports) || microLamports < 0))
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); const payer = Keypair.generate();
7
- const prices: number[] = []; let samples = 0;
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
- getRecentPrioritizationFees: async () => { samples++; return [200_000, 400_000, 800_000, 1_000_000].map((prioritizationFee) => ({ prioritizationFee })); },
11
- getFeeForMessage: async (message: { price: number }) => ({ value: 5000 + Math.ceil(10_000 * message.price / 1_000_000) }),
12
- }) as any;
13
- core.compile = async (_payer, draft) => ({ draft, payer: payer.publicKey, transaction: { message: { price: draft.cuPriceMicroLamports ?? 100_000 } } }) as unknown as PlannedTransaction;
14
- core.submitPlan = async (plan, sender) => { prices.push(plan.draft.cuPriceMicroLamports!); return { signature: "test-signature", executionId: 1, sender, plan, feeEstimate: await estimatePlanFee(core.connection(), plan) }; };
15
- core.settleSubmission = async () => ({ signature: "test-signature", sender: "rpc", status, slot: status === "confirmed" ? 1 : null, ...(status === "confirmed" ? { feeLamports: 13000 } : {}) });
16
- Object.defineProperty(core, "executions", { value: { get: () => ({ metaJson: null }) } });
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]> = []) => new Map([["wallet", "bags"], ["sol", "2"], ["live", "true"], ...extra]);
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({ slrd: ctx.core, values: [Keypair.generate().publicKey.toBase58()], flags: flags() });
23
- expect(ctx.prices).toEqual([800_000]); expect(ctx.samples()).toBe(1);
24
- expect(result.status).toBe("confirmed"); expect(result.feeEstimate).toEqual({ cuLimit: 10_000, priorityMicroLamports: 800_000, priorityFeeLamports: 8000, estimatedBaseFeeLamports: 5000, estimatedNetworkFeeLamports: 13000 });
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({ slrd: ctx.core, values: [Keypair.generate().publicKey.toBase58()], flags: flags([["priority-micro-lamports", "0"]]) });
30
- expect(ctx.prices).toEqual([0]); expect(ctx.samples()).toBe(0);
31
- expect(result.status).toBe("unresolved"); expect(result.code).toBe("UNRESOLVED"); expect(result.feeLamports).toBeUndefined();
32
- expect(result.feeEstimate).toMatchObject({ priorityFeeLamports: 0, estimatedNetworkFeeLamports: 5000 });
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
  });
@@ -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(wallet, await composer.build(), executionOptions);
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(wallet, () => composer.build(), via, "transfer-token", executionOptions);
166
- const receipt = tradeResult(execution.receipt, execution.attempts, execution.submission.executionId);
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(wallet, await composer.build(), executionOptions);
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(wallet, () => composer.build(), via, "transfer-sol", executionOptions);
202
- const receipt = tradeResult(execution.receipt, execution.attempts, execution.submission.executionId);
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
  }