@solard/sdk 0.2.33 → 0.2.40
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 +34 -34
- package/dist/types/browser/client.d.ts +129 -0
- package/dist/types/browser/index.d.ts +19 -0
- package/dist/types/browser/pump.d.ts +20 -0
- package/dist/types/browser/storage.d.ts +34 -0
- package/dist/types/browser/types.d.ts +90 -0
- package/dist/types/browser/wallet.d.ts +37 -0
- package/dist/types/client.d.ts +117 -0
- package/dist/types/default.d.ts +10 -0
- package/dist/types/index.d.ts +16 -0
- package/dist/types/live.d.ts +60 -0
- package/dist/types/protocol.d.ts +2 -0
- package/package.json +14 -8
- package/src/client.exact-sell.test.ts +95 -45
- package/src/client.listen-trades.test.ts +64 -34
- package/src/client.trade-fees.test.ts +37 -15
- package/src/client.ts +135 -48
- package/src/default.ts +2 -5
- package/src/export-surface.test.ts +46 -17
- package/src/index.ts +11 -4
- package/src/live-recovery.test.ts +122 -0
- package/src/live.test.ts +236 -60
- package/src/live.ts +427 -133
- package/src/operator-api.architecture.test.ts +3 -1
package/package.json
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solard/sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.40",
|
|
4
4
|
"description": "Public Solard SDK for wallets, trading, history, live market subscriptions and token metadata.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
7
7
|
"module": "./src/index.ts",
|
|
8
|
-
"types": "./
|
|
8
|
+
"types": "./dist/types/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
|
-
".":
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/types/index.d.ts",
|
|
12
|
+
"import": "./src/index.ts",
|
|
13
|
+
"default": "./src/index.ts"
|
|
14
|
+
},
|
|
11
15
|
"./browser": {
|
|
12
|
-
"types": "./
|
|
16
|
+
"types": "./dist/types/browser/index.d.ts",
|
|
13
17
|
"import": "./src/browser/index.ts",
|
|
14
18
|
"default": "./src/browser/index.ts"
|
|
15
19
|
},
|
|
16
20
|
"./protocol": {
|
|
17
|
-
"types": "./
|
|
21
|
+
"types": "./dist/types/protocol.d.ts",
|
|
18
22
|
"import": "./src/protocol.ts",
|
|
19
23
|
"default": "./src/protocol.ts"
|
|
20
24
|
}
|
|
@@ -22,15 +26,17 @@
|
|
|
22
26
|
"files": [
|
|
23
27
|
"src",
|
|
24
28
|
"README.md",
|
|
25
|
-
"LICENSE"
|
|
29
|
+
"LICENSE",
|
|
30
|
+
"dist/types"
|
|
26
31
|
],
|
|
27
32
|
"license": "MIT",
|
|
28
33
|
"dependencies": {
|
|
29
34
|
"@solana/web3.js": "^1.98.4",
|
|
30
|
-
"@solard/core": "0.2.
|
|
35
|
+
"@solard/core": "0.2.40"
|
|
31
36
|
},
|
|
32
37
|
"scripts": {
|
|
33
38
|
"typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.browser.json",
|
|
34
|
-
"typecheck:browser": "tsc --noEmit -p tsconfig.browser.json"
|
|
39
|
+
"typecheck:browser": "tsc --noEmit -p tsconfig.browser.json",
|
|
40
|
+
"prepack": "bun run ../../scripts/build-declarations.mjs"
|
|
35
41
|
}
|
|
36
42
|
}
|
|
@@ -1,45 +1,95 @@
|
|
|
1
|
-
import { expect, spyOn, test } from "bun:test";
|
|
2
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import { Solard } from "../../core/src/core/solard.ts";
|
|
6
|
-
import { tradeResult } from "../../core/src/tx/trade-result.ts";
|
|
7
|
-
import { createSolard, type SolardSellInput } from "./client.ts";
|
|
8
|
-
import { isDefinitivePreSubmissionError } from "@solard/core";
|
|
9
|
-
|
|
10
|
-
test("SDK exact raw sell forwards an isolated position without inserting default bps", async () => {
|
|
11
|
-
const folder = mkdtempSync(join(tmpdir(), "solard-sdk-exact-"));
|
|
12
|
-
const calls: Array<Record<string, unknown>> = [];
|
|
13
|
-
const sell = spyOn(Solard.prototype, "sell").mockImplementation(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
1
|
+
import { expect, spyOn, test } from "bun:test";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { Solard } from "../../core/src/core/solard.ts";
|
|
6
|
+
import { tradeResult } from "../../core/src/tx/trade-result.ts";
|
|
7
|
+
import { createSolard, type SolardSellInput } from "./client.ts";
|
|
8
|
+
import { isDefinitivePreSubmissionError } from "@solard/core";
|
|
9
|
+
|
|
10
|
+
test("SDK exact raw sell forwards an isolated position without inserting default bps", async () => {
|
|
11
|
+
const folder = mkdtempSync(join(tmpdir(), "solard-sdk-exact-"));
|
|
12
|
+
const calls: Array<Record<string, unknown>> = [];
|
|
13
|
+
const sell = spyOn(Solard.prototype, "sell").mockImplementation(
|
|
14
|
+
async (_token, _wallet, options) => {
|
|
15
|
+
calls.push(options as unknown as Record<string, unknown>);
|
|
16
|
+
return tradeResult({
|
|
17
|
+
signature: "fixture",
|
|
18
|
+
sender: "rpc",
|
|
19
|
+
status: "confirmed",
|
|
20
|
+
slot: 1,
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
);
|
|
24
|
+
const sdk = createSolard({ dbPath: join(folder, "test.sqlite") });
|
|
25
|
+
try {
|
|
26
|
+
await sdk.sell(
|
|
27
|
+
{
|
|
28
|
+
token: "mint",
|
|
29
|
+
wallet: "wallet",
|
|
30
|
+
amountRaw: "284725",
|
|
31
|
+
slippageBps: 500,
|
|
32
|
+
minOutputLamports: 1n,
|
|
33
|
+
},
|
|
34
|
+
{ priorityFee: { microLamports: 20_000 } },
|
|
35
|
+
);
|
|
36
|
+
await sdk.sell({
|
|
37
|
+
token: "mint",
|
|
38
|
+
wallet: "wallet",
|
|
39
|
+
amount: { raw: 284725n },
|
|
40
|
+
});
|
|
41
|
+
await sdk.sell({ token: "mint", wallet: "wallet", amount: { bps: 1000 } });
|
|
42
|
+
await sdk.sell({ token: "mint", wallet: "wallet", amount: "all" });
|
|
43
|
+
expect(calls[0]).toMatchObject({
|
|
44
|
+
amountRaw: "284725",
|
|
45
|
+
slippageBps: 500,
|
|
46
|
+
minOutputLamports: 1n,
|
|
47
|
+
priorityFee: { microLamports: 20_000 },
|
|
48
|
+
});
|
|
49
|
+
expect(calls[0]?.bps).toBeUndefined();
|
|
50
|
+
expect(calls[1]?.amountRaw).toBe(284725n);
|
|
51
|
+
expect(calls[1]?.bps).toBeUndefined();
|
|
52
|
+
expect(calls[2]?.bps).toBe(1000);
|
|
53
|
+
expect(calls[3]?.bps).toBe(10000);
|
|
54
|
+
} finally {
|
|
55
|
+
sdk.close();
|
|
56
|
+
sell.mockRestore();
|
|
57
|
+
rmSync(folder, { recursive: true, force: true });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("SDK rejects ambiguous and invalid raw quantities before invoking core sell", async () => {
|
|
62
|
+
const folder = mkdtempSync(join(tmpdir(), "solard-sdk-exact-invalid-"));
|
|
63
|
+
const sell = spyOn(Solard.prototype, "sell").mockImplementation(async () => {
|
|
64
|
+
throw new Error("must not call core");
|
|
65
|
+
});
|
|
66
|
+
const sdk = createSolard({ dbPath: join(folder, "test.sqlite") });
|
|
67
|
+
try {
|
|
68
|
+
for (const size of [
|
|
69
|
+
{ amountRaw: "284725", amount: { bps: 1000 } },
|
|
70
|
+
{ amountRaw: 0n },
|
|
71
|
+
{ amountRaw: "1.5" },
|
|
72
|
+
{ amount: { raw: "-1" } },
|
|
73
|
+
{ amount: { bps: 1.5 } },
|
|
74
|
+
{ amount: { raw: "284725", bps: 1000 } },
|
|
75
|
+
]) {
|
|
76
|
+
await expect(
|
|
77
|
+
sdk.sell({
|
|
78
|
+
token: "mint",
|
|
79
|
+
wallet: "wallet",
|
|
80
|
+
...size,
|
|
81
|
+
} as SolardSellInput),
|
|
82
|
+
).rejects.toThrow();
|
|
83
|
+
}
|
|
84
|
+
expect(sell).not.toHaveBeenCalled();
|
|
85
|
+
try {
|
|
86
|
+
await sdk.sell({ token: "mint", wallet: "wallet", amountRaw: 0n });
|
|
87
|
+
} catch (error) {
|
|
88
|
+
expect(isDefinitivePreSubmissionError(error)).toBe(true);
|
|
89
|
+
}
|
|
90
|
+
} finally {
|
|
91
|
+
sdk.close();
|
|
92
|
+
sell.mockRestore();
|
|
93
|
+
rmSync(folder, { recursive: true, force: true });
|
|
94
|
+
}
|
|
95
|
+
});
|
|
@@ -1,34 +1,64 @@
|
|
|
1
|
-
import { expect, spyOn, test } from "bun:test";
|
|
2
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
-
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import * as live from "./live.ts";
|
|
6
|
-
import { createSolard } from "./client.ts";
|
|
7
|
-
|
|
8
|
-
test("client listener inherits its configured database and endpoint pool", async () => {
|
|
9
|
-
const folder = mkdtempSync(join(tmpdir(), "solard-sdk-listener-"));
|
|
10
|
-
const dbPath = join(folder, "test.sqlite");
|
|
11
|
-
const seen: Array<live.ListenTradesOptions> = [];
|
|
12
|
-
const fixture = {} as live.TradeListener;
|
|
13
|
-
const listen = spyOn(live, "listenTrades").mockImplementation(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
await
|
|
31
|
-
expect(seen[
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
import { expect, spyOn, test } from "bun:test";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import * as live from "./live.ts";
|
|
6
|
+
import { createSolard } from "./client.ts";
|
|
7
|
+
|
|
8
|
+
test("client listener inherits its configured database and endpoint pool", async () => {
|
|
9
|
+
const folder = mkdtempSync(join(tmpdir(), "solard-sdk-listener-"));
|
|
10
|
+
const dbPath = join(folder, "test.sqlite");
|
|
11
|
+
const seen: Array<live.ListenTradesOptions> = [];
|
|
12
|
+
const fixture = {} as live.TradeListener;
|
|
13
|
+
const listen = spyOn(live, "listenTrades").mockImplementation(
|
|
14
|
+
async (options) => {
|
|
15
|
+
seen.push(options);
|
|
16
|
+
return fixture;
|
|
17
|
+
},
|
|
18
|
+
);
|
|
19
|
+
const sdk = createSolard({
|
|
20
|
+
dbPath,
|
|
21
|
+
rpcUrls: ["https://first.example.com", "https://second.example.com"],
|
|
22
|
+
});
|
|
23
|
+
try {
|
|
24
|
+
expect(await sdk.listenTrades({ tokens: ["mint"] })).toBe(fixture);
|
|
25
|
+
expect(seen[0]).toMatchObject({
|
|
26
|
+
dbPath,
|
|
27
|
+
rpcUrls: ["https://first.example.com", "https://second.example.com"],
|
|
28
|
+
tokens: ["mint"],
|
|
29
|
+
});
|
|
30
|
+
await sdk.listenTrades();
|
|
31
|
+
expect(seen[1]?.tokens).toEqual([]);
|
|
32
|
+
} finally {
|
|
33
|
+
sdk.close();
|
|
34
|
+
listen.mockRestore();
|
|
35
|
+
rmSync(folder, { recursive: true, force: true });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("single RPC configuration is forwarded and absent URLs preserve live environment fallback", async () => {
|
|
40
|
+
const folder = mkdtempSync(join(tmpdir(), "solard-sdk-listener-url-"));
|
|
41
|
+
const seen: Array<live.ListenTradesOptions> = [];
|
|
42
|
+
const listen = spyOn(live, "listenTrades").mockImplementation(
|
|
43
|
+
async (options) => {
|
|
44
|
+
seen.push(options);
|
|
45
|
+
return {} as live.TradeListener;
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
const first = createSolard({
|
|
49
|
+
dbPath: join(folder, "first.sqlite"),
|
|
50
|
+
rpcUrl: "https://configured.example.com",
|
|
51
|
+
});
|
|
52
|
+
const second = createSolard({ dbPath: join(folder, "second.sqlite") });
|
|
53
|
+
try {
|
|
54
|
+
await first.listenTrades();
|
|
55
|
+
await second.listenTrades();
|
|
56
|
+
expect(seen[0]?.rpcUrls).toEqual(["https://configured.example.com"]);
|
|
57
|
+
expect(seen[1]?.rpcUrls).toBeUndefined();
|
|
58
|
+
} finally {
|
|
59
|
+
first.close();
|
|
60
|
+
second.close();
|
|
61
|
+
listen.mockRestore();
|
|
62
|
+
rmSync(folder, { recursive: true, force: true });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
@@ -5,7 +5,10 @@ import { join } from "node:path";
|
|
|
5
5
|
import { Keypair } from "@solana/web3.js";
|
|
6
6
|
import { Solard } from "../../core/src/core/solard.ts";
|
|
7
7
|
import { TransactionComposer } from "../../core/src/tx/composer.ts";
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
PlannedTransaction,
|
|
10
|
+
TransactionDraft,
|
|
11
|
+
} from "../../core/src/tx/types.ts";
|
|
9
12
|
import { createSolard } from "./client.ts";
|
|
10
13
|
|
|
11
14
|
test("SDK buy rebuild and sell preserve custom fees in immediate submitted results", async () => {
|
|
@@ -14,30 +17,49 @@ test("SDK buy rebuild and sell preserve custom fees in immediate submitted resul
|
|
|
14
17
|
// A sentinel plan is never compiled, signed, or broadcast in this test.
|
|
15
18
|
const payer = Keypair.generate();
|
|
16
19
|
const plan = { payer: payer.publicKey } as PlannedTransaction;
|
|
17
|
-
const build = spyOn(
|
|
20
|
+
const build = spyOn(
|
|
21
|
+
TransactionComposer.prototype,
|
|
22
|
+
"build",
|
|
23
|
+
).mockImplementation(async function (this: TransactionComposer) {
|
|
18
24
|
drafts.push(this.snapshot());
|
|
19
25
|
return { ...plan, draft: this.snapshot() };
|
|
20
26
|
});
|
|
21
|
-
const signer = spyOn(Solard.prototype, "signer").mockImplementation(
|
|
22
|
-
|
|
27
|
+
const signer = spyOn(Solard.prototype, "signer").mockImplementation(
|
|
28
|
+
() => payer,
|
|
29
|
+
);
|
|
30
|
+
const compile = spyOn(Solard.prototype, "compile").mockImplementation(
|
|
31
|
+
async (_payer, draft) => ({ ...plan, draft }),
|
|
32
|
+
);
|
|
23
33
|
let submissions = 0;
|
|
24
|
-
const submit = spyOn(Solard.prototype, "submitPlan").mockImplementation(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
const submit = spyOn(Solard.prototype, "submitPlan").mockImplementation(
|
|
35
|
+
async () => {
|
|
36
|
+
submissions += 1;
|
|
37
|
+
if (submissions === 1) {
|
|
38
|
+
throw new Error("Simulation failed: BuySlippageBelowMinBaseAmountOut");
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
signature: "test-signature",
|
|
42
|
+
sender: "rpc",
|
|
43
|
+
executionId: 42,
|
|
44
|
+
plan,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
const settle = spyOn(Solard.prototype, "settleSubmission").mockImplementation(
|
|
49
|
+
async () => {
|
|
50
|
+
throw new Error("Immediate submission must not wait for confirmation");
|
|
51
|
+
},
|
|
52
|
+
);
|
|
34
53
|
const sdk = createSolard({ dbPath: join(directory, "test.sqlite") });
|
|
35
54
|
try {
|
|
36
55
|
const options = {
|
|
37
56
|
priorityFee: { cuLimit: 300_000, microLamports: 0 },
|
|
38
57
|
waitForConfirmation: false,
|
|
39
58
|
};
|
|
40
|
-
const buy = await sdk.buy(
|
|
59
|
+
const buy = await sdk.buy(
|
|
60
|
+
{ token: "token", wallet: "wallet", amount: 0.1 },
|
|
61
|
+
options,
|
|
62
|
+
);
|
|
41
63
|
const sell = await sdk.sell({ token: "token", wallet: "wallet" }, options);
|
|
42
64
|
expect(drafts).toHaveLength(3);
|
|
43
65
|
for (const draft of drafts) {
|
package/src/client.ts
CHANGED
|
@@ -34,14 +34,20 @@ import {
|
|
|
34
34
|
type TokenRef,
|
|
35
35
|
type WalletRef,
|
|
36
36
|
type WalletPrivateKeyExport,
|
|
37
|
-
type WalletPrivateKeyFormat,
|
|
38
|
-
TradePreSubmissionError,
|
|
39
|
-
} from "@solard/core";
|
|
40
|
-
import {
|
|
37
|
+
type WalletPrivateKeyFormat,
|
|
38
|
+
TradePreSubmissionError,
|
|
39
|
+
} from "@solard/core";
|
|
40
|
+
import {
|
|
41
|
+
listenTrades as openTradeListener,
|
|
42
|
+
type ListenTradesOptions,
|
|
43
|
+
type TradeListener,
|
|
44
|
+
} from "./live.ts";
|
|
41
45
|
|
|
42
|
-
export type SolardOptions = {
|
|
46
|
+
export type SolardOptions = {
|
|
47
|
+
transactionVersion?: 0 | 1;
|
|
43
48
|
rpcUrl?: string;
|
|
44
49
|
rpcUrls?: readonly string[];
|
|
50
|
+
websocketUrls?: readonly string[];
|
|
45
51
|
dbPath?: string;
|
|
46
52
|
cacheTtlMs?: number;
|
|
47
53
|
};
|
|
@@ -81,9 +87,9 @@ export type SolardSellInput = {
|
|
|
81
87
|
minPriceSol?: string | number;
|
|
82
88
|
wallet: WalletRef;
|
|
83
89
|
token: TokenRef;
|
|
84
|
-
amount?: "all" | { bps: number } | { raw: bigint | string };
|
|
85
|
-
/** Exact raw token units; mutually exclusive with amount. */
|
|
86
|
-
amountRaw?: bigint | string;
|
|
90
|
+
amount?: "all" | { bps: number } | { raw: bigint | string };
|
|
91
|
+
/** Exact raw token units; mutually exclusive with amount. */
|
|
92
|
+
amountRaw?: bigint | string;
|
|
87
93
|
slippageBps?: number;
|
|
88
94
|
minOutputLamports?: bigint | string;
|
|
89
95
|
};
|
|
@@ -92,18 +98,49 @@ export type SolardTradeExecutionOptions = TradeExecutionOptions;
|
|
|
92
98
|
|
|
93
99
|
export type SolardTradeExecutionResult = TradeResult;
|
|
94
100
|
export type Solard = {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
tx:ReturnType<typeof createCoreSolard>['tx'];
|
|
102
|
+
compileGroups:ReturnType<typeof createCoreSolard>['compileGroups'];
|
|
103
|
+
simulatePlan:ReturnType<typeof createCoreSolard>['simulatePlan'];
|
|
104
|
+
sendBatchPlans:ReturnType<typeof createCoreSolard>['sendBatchPlans'];
|
|
105
|
+
prepareFastTrade: ReturnType<typeof createCoreSolard>["prepareFastTrade"];
|
|
106
|
+
listenTrades(
|
|
107
|
+
options?: Omit<ListenTradesOptions, "tokens"> & {
|
|
108
|
+
tokens?: readonly string[];
|
|
109
|
+
},
|
|
110
|
+
): Promise<TradeListener>;
|
|
111
|
+
prepareUnsignedBuy: ReturnType<typeof createCoreSolard>["prepareUnsignedBuy"];
|
|
112
|
+
prepareUnsignedTokenDeployment: ReturnType<typeof createCoreSolard>["prepareUnsignedTokenDeployment"];
|
|
113
|
+
resolvePumpLaunchQuote: ReturnType<typeof createCoreSolard>["resolvePumpLaunchQuote"];
|
|
114
|
+
simulateUnsignedTokenDeployment: ReturnType<typeof createCoreSolard>["simulateUnsignedTokenDeployment"];
|
|
115
|
+
simulateUnsignedBuy: ReturnType<typeof createCoreSolard>["simulateUnsignedBuy"];
|
|
116
|
+
prepareUnsignedSell: ReturnType<typeof createCoreSolard>["prepareUnsignedSell"];
|
|
117
|
+
simulateUnsignedSell: ReturnType<typeof createCoreSolard>["simulateUnsignedSell"];
|
|
118
|
+
proposeUnsignedBuyLookupTable: ReturnType<typeof createCoreSolard>["proposeUnsignedBuyLookupTable"];
|
|
119
|
+
resolveCurrentMarket: ReturnType<
|
|
120
|
+
typeof createCoreSolard
|
|
121
|
+
>["resolveCurrentMarket"];
|
|
122
|
+
getClaimableCreatorFees: ReturnType<
|
|
123
|
+
typeof createCoreSolard
|
|
124
|
+
>["getClaimableCreatorFees"];
|
|
125
|
+
claimAllCreatorFees: ReturnType<
|
|
126
|
+
typeof createCoreSolard
|
|
127
|
+
>["claimAllCreatorFees"];
|
|
99
128
|
walletLedger: ReturnType<typeof createCoreSolard>["walletLedger"];
|
|
100
129
|
historicalTape: ReturnType<typeof createCoreSolard>["historicalTape"];
|
|
101
|
-
getSupportedPumpPairs: ReturnType<
|
|
102
|
-
|
|
130
|
+
getSupportedPumpPairs: ReturnType<
|
|
131
|
+
typeof createCoreSolard
|
|
132
|
+
>["getSupportedPumpPairs"];
|
|
133
|
+
getSupportedLaunchLabPairs: ReturnType<
|
|
134
|
+
typeof createCoreSolard
|
|
135
|
+
>["getSupportedLaunchLabPairs"];
|
|
103
136
|
listVanityMints: ReturnType<typeof createCoreSolard>["listVanityMints"];
|
|
104
137
|
releaseVanityMint: ReturnType<typeof createCoreSolard>["releaseVanityMint"];
|
|
105
|
-
closeEmptyTokenAccounts: ReturnType<
|
|
106
|
-
|
|
138
|
+
closeEmptyTokenAccounts: ReturnType<
|
|
139
|
+
typeof createCoreSolard
|
|
140
|
+
>["closeEmptyTokenAccounts"];
|
|
141
|
+
prepareTokenDeployment: ReturnType<
|
|
142
|
+
typeof createCoreSolard
|
|
143
|
+
>["prepareTokenDeployment"];
|
|
107
144
|
deployToken: ReturnType<typeof createCoreSolard>["deployToken"];
|
|
108
145
|
warmBlockhash: ReturnType<typeof createCoreSolard>["warmBlockhash"];
|
|
109
146
|
curveLiquidity: ReturnType<typeof createCoreSolard>["curveLiquidity"];
|
|
@@ -180,25 +217,38 @@ function tradeAmount(value: HumanAmount | string | number): HumanAmount {
|
|
|
180
217
|
: value;
|
|
181
218
|
}
|
|
182
219
|
|
|
183
|
-
function sellSize(input: SolardSellInput): {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (
|
|
197
|
-
|
|
198
|
-
|
|
220
|
+
function sellSize(input: SolardSellInput): {
|
|
221
|
+
bps?: number;
|
|
222
|
+
amountRaw?: bigint | string;
|
|
223
|
+
} {
|
|
224
|
+
const value = input.amount;
|
|
225
|
+
if (input.amountRaw !== undefined && value !== undefined)
|
|
226
|
+
throw new Error("sell amountRaw and amount are mutually exclusive");
|
|
227
|
+
const raw =
|
|
228
|
+
input.amountRaw !== undefined
|
|
229
|
+
? input.amountRaw
|
|
230
|
+
: typeof value === "object" && value !== null && "raw" in value
|
|
231
|
+
? value.raw
|
|
232
|
+
: undefined;
|
|
233
|
+
if (raw !== undefined) {
|
|
234
|
+
if (typeof value === "object" && value !== null && "bps" in value)
|
|
235
|
+
throw new Error("sell raw and bps are mutually exclusive");
|
|
236
|
+
if (
|
|
237
|
+
(typeof raw !== "bigint" &&
|
|
238
|
+
(typeof raw !== "string" || !/^\d+$/.test(raw))) ||
|
|
239
|
+
BigInt(raw) <= 0n
|
|
240
|
+
)
|
|
241
|
+
throw new Error("sell amountRaw must be a positive raw integer");
|
|
242
|
+
return { amountRaw: raw };
|
|
243
|
+
}
|
|
244
|
+
if (value == null || value === "all") return { bps: 10_000 };
|
|
245
|
+
if (!("bps" in value)) throw new Error("sell amount must specify bps or raw");
|
|
246
|
+
const bps = value.bps;
|
|
247
|
+
if (!Number.isInteger(bps) || !(bps > 0 && bps <= 10_000))
|
|
248
|
+
throw new Error("sell amount.bps must be between 1 and 10000");
|
|
249
|
+
return { bps };
|
|
199
250
|
}
|
|
200
251
|
|
|
201
|
-
|
|
202
252
|
async function executeTrade(
|
|
203
253
|
core: ReturnType<typeof createCoreSolard>,
|
|
204
254
|
side: "buy" | "sell",
|
|
@@ -207,16 +257,33 @@ async function executeTrade(
|
|
|
207
257
|
): Promise<SolardTradeExecutionResult> {
|
|
208
258
|
if (side === "buy") {
|
|
209
259
|
const buy = input as SolardBuyInput;
|
|
210
|
-
return await core.buy(buy.token, buy.wallet, tradeAmount(buy.amount), {
|
|
260
|
+
return await core.buy(buy.token, buy.wallet, tradeAmount(buy.amount), {
|
|
261
|
+
...options,
|
|
262
|
+
slippageBps: buy.slippageBps,
|
|
263
|
+
minOutputRaw: buy.minOutputRaw,
|
|
264
|
+
maxPriceSol: buy.maxPriceSol,
|
|
265
|
+
reserves: buy.reserves,
|
|
266
|
+
});
|
|
211
267
|
}
|
|
212
|
-
const sell = input as SolardSellInput;
|
|
213
|
-
let size: ReturnType<typeof sellSize>;
|
|
214
|
-
try {
|
|
215
|
-
|
|
216
|
-
|
|
268
|
+
const sell = input as SolardSellInput;
|
|
269
|
+
let size: ReturnType<typeof sellSize>;
|
|
270
|
+
try {
|
|
271
|
+
size = sellSize(sell);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
throw new TradePreSubmissionError(error);
|
|
274
|
+
}
|
|
275
|
+
return await core.sell(sell.token, sell.wallet, {
|
|
276
|
+
...options,
|
|
277
|
+
...size,
|
|
278
|
+
slippageBps: sell.slippageBps,
|
|
279
|
+
minOutputLamports: sell.minOutputLamports,
|
|
280
|
+
minPriceSol: sell.minPriceSol,
|
|
281
|
+
reserves: sell.reserves,
|
|
282
|
+
closeTokenAccount: sell.closeTokenAccount,
|
|
283
|
+
});
|
|
217
284
|
}
|
|
218
285
|
|
|
219
|
-
export function createSolard(options: SolardOptions = {}): Solard {
|
|
286
|
+
export function createSolard(options: SolardOptions = {}): Solard {
|
|
220
287
|
const core = createCoreSolard(options);
|
|
221
288
|
const history: SolardHistoryApi = Object.freeze({
|
|
222
289
|
replay: (token, replayOptions) => core.history.replay(token, replayOptions),
|
|
@@ -229,19 +296,39 @@ export function createSolard(options: SolardOptions = {}): Solard {
|
|
|
229
296
|
{ merge: core.events.merge },
|
|
230
297
|
) as SolardEventsApi;
|
|
231
298
|
return Object.freeze({
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
299
|
+
tx:core.tx.bind(core),
|
|
300
|
+
compileGroups:core.compileGroups.bind(core),
|
|
301
|
+
simulatePlan:core.simulatePlan.bind(core),
|
|
302
|
+
sendBatchPlans:core.sendBatchPlans.bind(core),
|
|
303
|
+
listenTrades: (
|
|
304
|
+
listenerOptions: Omit<ListenTradesOptions, "tokens"> & {
|
|
305
|
+
tokens?: readonly string[];
|
|
306
|
+
} = {},
|
|
307
|
+
) =>
|
|
308
|
+
openTradeListener({
|
|
309
|
+
websocketUrls: listenerOptions.websocketUrls ?? options.websocketUrls,
|
|
310
|
+
rpcUrls:
|
|
311
|
+
options.rpcUrls ?? (options.rpcUrl ? [options.rpcUrl] : undefined),
|
|
312
|
+
dbPath: options.dbPath,
|
|
313
|
+
...listenerOptions,
|
|
314
|
+
tokens: listenerOptions.tokens ?? [],
|
|
315
|
+
}),
|
|
316
|
+
prepareFastTrade: core.prepareFastTrade.bind(core),
|
|
317
|
+
prepareUnsignedBuy: core.prepareUnsignedBuy.bind(core),
|
|
318
|
+
prepareUnsignedTokenDeployment: core.prepareUnsignedTokenDeployment.bind(core),
|
|
319
|
+
resolvePumpLaunchQuote: core.resolvePumpLaunchQuote.bind(core),
|
|
320
|
+
simulateUnsignedTokenDeployment: core.simulateUnsignedTokenDeployment.bind(core),
|
|
321
|
+
simulateUnsignedBuy: core.simulateUnsignedBuy.bind(core),
|
|
322
|
+
prepareUnsignedSell: core.prepareUnsignedSell.bind(core),
|
|
323
|
+
simulateUnsignedSell: core.simulateUnsignedSell.bind(core),
|
|
324
|
+
proposeUnsignedBuyLookupTable: core.proposeUnsignedBuyLookupTable.bind(core),
|
|
238
325
|
resolveCurrentMarket: core.resolveCurrentMarket.bind(core),
|
|
239
326
|
getClaimableCreatorFees: core.getClaimableCreatorFees.bind(core),
|
|
240
327
|
claimAllCreatorFees: core.claimAllCreatorFees.bind(core),
|
|
241
328
|
walletLedger: core.walletLedger.bind(core),
|
|
242
329
|
historicalTape: core.historicalTape.bind(core),
|
|
243
|
-
getSupportedPumpPairs: core.getSupportedPumpPairs.bind(core),
|
|
244
|
-
getSupportedLaunchLabPairs: core.getSupportedLaunchLabPairs.bind(core),
|
|
330
|
+
getSupportedPumpPairs: core.getSupportedPumpPairs.bind(core),
|
|
331
|
+
getSupportedLaunchLabPairs: core.getSupportedLaunchLabPairs.bind(core),
|
|
245
332
|
listVanityMints: core.listVanityMints.bind(core),
|
|
246
333
|
releaseVanityMint: core.releaseVanityMint.bind(core),
|
|
247
334
|
closeEmptyTokenAccounts: core.closeEmptyTokenAccounts.bind(core),
|
package/src/default.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { getSolUsdPrice } from "@solard/core";
|
|
2
|
-
import {
|
|
3
|
-
subscribeLaunches,
|
|
4
|
-
subscribeMigrations,
|
|
5
|
-
} from "./live.ts";
|
|
2
|
+
import { subscribeLaunches, subscribeMigrations } from "./live.ts";
|
|
6
3
|
import { createSolard, type Solard } from "./client.ts";
|
|
7
4
|
|
|
8
5
|
type DefaultSolard = Solard & {
|
|
@@ -20,7 +17,7 @@ function client(): Solard {
|
|
|
20
17
|
|
|
21
18
|
const operations = {
|
|
22
19
|
getSolUsdPrice,
|
|
23
|
-
subscribeLaunches,
|
|
20
|
+
subscribeLaunches,
|
|
24
21
|
subscribeMigrations,
|
|
25
22
|
} as const;
|
|
26
23
|
|