quicknode-solana-kit 1.0.2 → 1.0.3
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 +953 -257
- package/dist/addons.d.ts.map +1 -1
- package/dist/addons.js +190 -0
- package/dist/addons.js.map +1 -1
- package/dist/goldrush/index.d.ts +10 -0
- package/dist/goldrush/index.d.ts.map +1 -0
- package/dist/goldrush/index.js +37 -0
- package/dist/goldrush/index.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +92 -2
- package/dist/index.js.map +1 -1
- package/dist/iris/index.d.ts +3 -0
- package/dist/iris/index.d.ts.map +1 -0
- package/dist/iris/index.js +29 -0
- package/dist/iris/index.js.map +1 -0
- package/dist/mev/index.d.ts +4 -0
- package/dist/mev/index.d.ts.map +1 -0
- package/dist/mev/index.js +52 -0
- package/dist/mev/index.js.map +1 -0
- package/dist/openocean/index.d.ts +13 -0
- package/dist/openocean/index.d.ts.map +1 -0
- package/dist/openocean/index.js +63 -0
- package/dist/openocean/index.js.map +1 -0
- package/dist/pumpfun/index.d.ts +7 -0
- package/dist/pumpfun/index.d.ts.map +1 -0
- package/dist/pumpfun/index.js +54 -0
- package/dist/pumpfun/index.js.map +1 -0
- package/dist/scorechain/index.d.ts +4 -0
- package/dist/scorechain/index.d.ts.map +1 -0
- package/dist/scorechain/index.js +26 -0
- package/dist/scorechain/index.js.map +1 -0
- package/dist/stablecoin/index.d.ts +3 -0
- package/dist/stablecoin/index.d.ts.map +1 -0
- package/dist/stablecoin/index.js +16 -0
- package/dist/stablecoin/index.js.map +1 -0
- package/dist/titan/index.d.ts +5 -0
- package/dist/titan/index.d.ts.map +1 -0
- package/dist/titan/index.js +119 -0
- package/dist/titan/index.js.map +1 -0
- package/dist/types/index.d.ts +234 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/addon-guard.d.ts.map +1 -1
- package/dist/utils/addon-guard.js +47 -0
- package/dist/utils/addon-guard.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,458 +1,1154 @@
|
|
|
1
1
|
# quicknode-solana-kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Typed Solana SDK for QuickNode endpoints and QuickNode-powered add-ons.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This package gives you one client for:
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
- normal Solana RPC via `@solana/web3.js`
|
|
8
|
+
- QuickNode custom RPC methods
|
|
9
|
+
- QuickNode-mounted REST add-ons
|
|
10
|
+
- real-time subscriptions through Solana WebSockets
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
If all you know today is:
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
```ts
|
|
15
|
+
import { Connection } from '@solana/web3.js';
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
const connection = new Connection('https://your-endpoint.quiknode.pro/TOKEN/', 'confirmed');
|
|
18
|
+
```
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
this package is the next layer on top of that.
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
```ts
|
|
21
|
-
// ~200 lines of manual code every time:
|
|
22
|
-
// - call qn_estimatePriorityFees, parse it
|
|
23
|
-
// - figure out which level to pick
|
|
24
|
-
// - build SetComputeUnitLimit instruction
|
|
25
|
-
// - build SetComputeUnitPrice instruction
|
|
26
|
-
// - remove existing compute budget ixs to avoid duplicates
|
|
27
|
-
// - simulate to estimate compute units
|
|
28
|
-
// - handle retry when blockhash expires
|
|
29
|
-
// - confirm and return useful data
|
|
30
|
-
```
|
|
22
|
+
It still uses a normal Solana `Connection`, but wraps common QuickNode features into a single typed API.
|
|
31
23
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const result = await kit.sendSmartTransaction({ transaction, signer });
|
|
35
|
-
// That's it. Everything above is handled.
|
|
24
|
+
```bash
|
|
25
|
+
npm install quicknode-solana-kit
|
|
36
26
|
```
|
|
37
27
|
|
|
38
|
-
|
|
28
|
+
## What This Package Actually Does
|
|
39
29
|
|
|
40
|
-
|
|
30
|
+
`quicknode-solana-kit` is not a replacement for Solana RPC.
|
|
41
31
|
|
|
42
|
-
|
|
43
|
-
- A QuickNode Solana endpoint → **free at [dashboard.quicknode.com](https://dashboard.quicknode.com)**
|
|
32
|
+
It is a wrapper around three patterns:
|
|
44
33
|
|
|
45
|
-
|
|
34
|
+
1. Standard Solana RPC and WebSocket calls through `@solana/web3.js`
|
|
35
|
+
2. QuickNode custom JSON-RPC methods like `qn_estimatePriorityFees`
|
|
36
|
+
3. REST-style add-ons mounted on your QuickNode endpoint like `/jupiter/v6/quote`
|
|
46
37
|
|
|
47
|
-
|
|
38
|
+
The package creates a normal Solana `Connection` internally, then adds methods like:
|
|
48
39
|
|
|
49
|
-
|
|
40
|
+
- `sendSmartTransaction()`
|
|
41
|
+
- `estimatePriorityFees()`
|
|
42
|
+
- `getAssetsByOwner()`
|
|
43
|
+
- `getSwapQuote()`
|
|
44
|
+
- `getPumpFunTokens()`
|
|
45
|
+
- `sendMerkleProtectedTransaction()`
|
|
46
|
+
- `getGoldRushBalances()`
|
|
47
|
+
- `assessWalletRisk()`
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
52
|
npm install quicknode-solana-kit
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
Peer/runtime requirements:
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
```
|
|
60
|
-
https://your-name.solana-mainnet.quiknode.pro/YOUR_TOKEN/
|
|
61
|
-
```
|
|
57
|
+
- Node.js 18+
|
|
58
|
+
- a QuickNode Solana endpoint
|
|
62
59
|
|
|
63
|
-
|
|
60
|
+
## Quick Start
|
|
64
61
|
|
|
65
|
-
|
|
66
|
-
- Enable **Priority Fee API** (free) → unlocks `estimatePriorityFees()` + auto-fees in `sendSmartTransaction()`
|
|
67
|
-
- Enable **Metaplex DAS API** (free) → unlocks all NFT query methods
|
|
62
|
+
### 1. Create a QuickNode Solana endpoint
|
|
68
63
|
|
|
69
|
-
|
|
64
|
+
Example endpoint:
|
|
65
|
+
|
|
66
|
+
```txt
|
|
67
|
+
https://your-name.solana-mainnet.quiknode.pro/YOUR_TOKEN/
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. Create the client
|
|
70
71
|
|
|
71
72
|
```ts
|
|
72
|
-
import { QNSolanaKit } from '
|
|
73
|
+
import { QNSolanaKit } from 'quicknode-solana-kit';
|
|
73
74
|
|
|
74
75
|
const kit = new QNSolanaKit({
|
|
75
|
-
endpointUrl: 'https://your-name.solana-mainnet.quiknode.pro/
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// The SDK works without any — it just shows helpful messages
|
|
79
|
-
// when you call a method that needs an add-on you haven't enabled.
|
|
76
|
+
endpointUrl: 'https://your-name.solana-mainnet.quiknode.pro/YOUR_TOKEN/',
|
|
77
|
+
commitment: 'confirmed',
|
|
78
|
+
timeout: 30_000,
|
|
80
79
|
addOns: {
|
|
81
|
-
priorityFees: true,
|
|
82
|
-
das:
|
|
83
|
-
metis:
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
priorityFees: true,
|
|
81
|
+
das: true,
|
|
82
|
+
metis: false,
|
|
83
|
+
yellowstone: false,
|
|
84
|
+
liljit: false,
|
|
85
|
+
pumpfun: false,
|
|
86
|
+
stablecoinBalance: false,
|
|
87
|
+
openocean: false,
|
|
88
|
+
merkle: false,
|
|
89
|
+
blinklabs: false,
|
|
90
|
+
iris: false,
|
|
91
|
+
goldrush: false,
|
|
92
|
+
titan: false,
|
|
93
|
+
scorechain: false,
|
|
86
94
|
},
|
|
87
95
|
});
|
|
88
96
|
```
|
|
89
97
|
|
|
90
|
-
###
|
|
98
|
+
### 3. Use the built-in Solana connection
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
const blockhash = await kit.connection.getLatestBlockhash();
|
|
102
|
+
console.log(blockhash.blockhash);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 4. Probe your endpoint
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
const status = await kit.checkAddOns();
|
|
109
|
+
console.log(status.addOns);
|
|
110
|
+
console.log(status.canUse);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
You can also run the CLI:
|
|
91
114
|
|
|
92
115
|
```bash
|
|
93
|
-
# Probes your endpoint and shows exactly which add-ons are active
|
|
94
116
|
npm run check
|
|
95
117
|
```
|
|
96
118
|
|
|
97
|
-
|
|
119
|
+
## How Add-Ons Work
|
|
120
|
+
|
|
121
|
+
This package uses add-ons in two ways:
|
|
122
|
+
|
|
123
|
+
### 1. Local config guard
|
|
124
|
+
|
|
125
|
+
You declare what you think is enabled:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const kit = new QNSolanaKit({
|
|
129
|
+
endpointUrl: process.env.QN_ENDPOINT_URL!,
|
|
130
|
+
addOns: {
|
|
131
|
+
priorityFees: true,
|
|
132
|
+
das: true,
|
|
133
|
+
metis: false,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
98
136
|
```
|
|
99
|
-
@quicknode/solana-kit — Add-on Status
|
|
100
|
-
──────────────────────────────────────────────────────
|
|
101
|
-
Endpoint: https://your-name.solana-mainnet.quiknode.pro...
|
|
102
137
|
|
|
103
|
-
|
|
104
|
-
enabled — Dynamic priority fee estimation for faster tx inclusion
|
|
138
|
+
If you explicitly set an add-on to `false` and call a method that requires it, the SDK throws an `AddOnNotEnabledError`.
|
|
105
139
|
|
|
106
|
-
|
|
107
|
-
enabled — Query NFTs, compressed NFTs, token metadata
|
|
140
|
+
If you leave a value `undefined`, the SDK warns and still tries the network call.
|
|
108
141
|
|
|
109
|
-
|
|
110
|
-
not enabled — Best-price token swaps via Jupiter aggregator
|
|
111
|
-
Enable: https://marketplace.quicknode.com/add-ons/metis-jupiter-v6-swap-api
|
|
142
|
+
### 2. Real endpoint capability
|
|
112
143
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
144
|
+
The actual source of truth is your endpoint.
|
|
145
|
+
|
|
146
|
+
`checkAddOns()` probes the endpoint by making sample RPC or REST calls and returns what is live.
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
const result = await kit.checkAddOns();
|
|
150
|
+
|
|
151
|
+
console.log(result.canUse.smartTransactions);
|
|
152
|
+
console.log(result.canUse.nftQueries);
|
|
153
|
+
console.log(result.canUse.swaps);
|
|
154
|
+
console.log(result.canUse.openOceanSwaps);
|
|
155
|
+
console.log(result.canUse.goldRushData);
|
|
120
156
|
```
|
|
121
157
|
|
|
122
|
-
|
|
158
|
+
## Add-On Map
|
|
123
159
|
|
|
124
|
-
|
|
160
|
+
Here is how each add-on is implemented inside the package.
|
|
125
161
|
|
|
126
|
-
| Add-on
|
|
127
|
-
|
|
128
|
-
|
|
|
129
|
-
|
|
|
130
|
-
|
|
|
131
|
-
|
|
|
132
|
-
|
|
|
162
|
+
| Add-on key | What it unlocks | Transport used by SDK | Example endpoint shape |
|
|
163
|
+
|---|---|---|---|
|
|
164
|
+
| `priorityFees` | live fee estimation and smart tx fee selection | JSON-RPC | `qn_estimatePriorityFees` |
|
|
165
|
+
| `das` | NFT / digital asset queries | JSON-RPC | `getAssetsByOwner` |
|
|
166
|
+
| `metis` | Jupiter quote and swap | REST | `/jupiter/v6/quote` |
|
|
167
|
+
| `yellowstone` | account streaming preference | currently falls back to WebSocket | no active gRPC client yet |
|
|
168
|
+
| `liljit` | intended Jito support | checked by probe, not fully wired into smart tx flow yet | `sendBundle` |
|
|
169
|
+
| `pumpfun` | pump.fun market data | REST | `/pump-fun/coins` |
|
|
170
|
+
| `stablecoinBalance` | stablecoin balances across chains | JSON-RPC | `qn_getWalletStablecoinBalances` |
|
|
171
|
+
| `openocean` | OpenOcean quote and swap | REST | `/openocean/v4/solana/quote` |
|
|
172
|
+
| `merkle` | MEV-protected tx submission | JSON-RPC | `mev_sendTransaction` |
|
|
173
|
+
| `blinklabs` | alternate protected tx submission | JSON-RPC | `blinklabs_sendTransaction` |
|
|
174
|
+
| `iris` | low-latency tx sender | JSON-RPC | `iris_sendTransaction` |
|
|
175
|
+
| `goldrush` | multichain balances and tx history | REST | `/goldrush/v1/...` |
|
|
176
|
+
| `titan` | swap quote, swap, quote stream | REST + WebSocket | `/titan/v1/quote` |
|
|
177
|
+
| `scorechain` | wallet risk checks | REST | `/scorechain/v1/risk` |
|
|
133
178
|
|
|
134
|
-
|
|
135
|
-
WebSocket streaming (`watchAccount`, `watchProgram`, `watchSlot`) works out of the box with no add-ons.
|
|
179
|
+
## Common Pattern
|
|
136
180
|
|
|
137
|
-
|
|
181
|
+
Most features follow one of these flows.
|
|
138
182
|
|
|
139
|
-
|
|
183
|
+
### Standard Solana RPC
|
|
140
184
|
|
|
141
|
-
|
|
185
|
+
```ts
|
|
186
|
+
const accounts = await kit.connection.getTokenAccountsByOwner(
|
|
187
|
+
wallet,
|
|
188
|
+
{ programId: TOKEN_PROGRAM_ID },
|
|
189
|
+
);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### QuickNode custom RPC
|
|
142
193
|
|
|
143
|
-
|
|
194
|
+
The SDK hides the raw method call:
|
|
144
195
|
|
|
145
196
|
```ts
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
},
|
|
197
|
+
const fees = await kit.estimatePriorityFees();
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
instead of:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
await fetch(endpoint, {
|
|
204
|
+
method: 'POST',
|
|
205
|
+
headers: { 'Content-Type': 'application/json' },
|
|
206
|
+
body: JSON.stringify({
|
|
207
|
+
jsonrpc: '2.0',
|
|
208
|
+
id: 1,
|
|
209
|
+
method: 'qn_estimatePriorityFees',
|
|
210
|
+
params: { last_n_blocks: 100, api_version: 2 },
|
|
211
|
+
}),
|
|
155
212
|
});
|
|
213
|
+
```
|
|
156
214
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
215
|
+
### REST add-on mounted on the same endpoint
|
|
216
|
+
|
|
217
|
+
The SDK also hides path-building:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
const quote = await kit.getSwapQuote({
|
|
221
|
+
inputMint: TOKENS.SOL,
|
|
222
|
+
outputMint: TOKENS.USDC,
|
|
223
|
+
amount: BigInt(1_000_000_000),
|
|
224
|
+
});
|
|
162
225
|
```
|
|
163
226
|
|
|
164
|
-
|
|
227
|
+
instead of manually calling:
|
|
165
228
|
|
|
166
|
-
|
|
229
|
+
```txt
|
|
230
|
+
https://your-endpoint.quiknode.pro/TOKEN/jupiter/v6/quote?...
|
|
231
|
+
```
|
|
167
232
|
|
|
168
|
-
|
|
169
|
-
**Use this with wallet adapters** (Phantom, Backpack, etc.) where you don't hold the key.
|
|
233
|
+
## Client Configuration
|
|
170
234
|
|
|
171
235
|
```ts
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
236
|
+
import { QNSolanaKit } from 'quicknode-solana-kit';
|
|
237
|
+
|
|
238
|
+
const kit = new QNSolanaKit({
|
|
239
|
+
endpointUrl: process.env.QN_ENDPOINT_URL!,
|
|
240
|
+
commitment: 'confirmed',
|
|
241
|
+
timeout: 30_000,
|
|
242
|
+
addOns: {
|
|
243
|
+
priorityFees: true,
|
|
244
|
+
das: true,
|
|
245
|
+
},
|
|
176
246
|
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Config fields
|
|
177
250
|
|
|
178
|
-
|
|
179
|
-
|
|
251
|
+
```ts
|
|
252
|
+
interface QNConfig {
|
|
253
|
+
endpointUrl: string;
|
|
254
|
+
commitment?: 'processed' | 'confirmed' | 'finalized';
|
|
255
|
+
timeout?: number;
|
|
256
|
+
addOns?: {
|
|
257
|
+
priorityFees?: boolean;
|
|
258
|
+
liljit?: boolean;
|
|
259
|
+
das?: boolean;
|
|
260
|
+
metis?: boolean;
|
|
261
|
+
yellowstone?: boolean;
|
|
262
|
+
pumpfun?: boolean;
|
|
263
|
+
stablecoinBalance?: boolean;
|
|
264
|
+
openocean?: boolean;
|
|
265
|
+
merkle?: boolean;
|
|
266
|
+
blinklabs?: boolean;
|
|
267
|
+
iris?: boolean;
|
|
268
|
+
goldrush?: boolean;
|
|
269
|
+
titan?: boolean;
|
|
270
|
+
scorechain?: boolean;
|
|
271
|
+
};
|
|
272
|
+
}
|
|
180
273
|
```
|
|
181
274
|
|
|
182
|
-
|
|
275
|
+
## API Reference
|
|
276
|
+
|
|
277
|
+
### Diagnostics
|
|
278
|
+
|
|
279
|
+
#### `kit.checkAddOns()`
|
|
280
|
+
|
|
281
|
+
Probes your endpoint and returns add-on availability.
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
const status = await kit.checkAddOns();
|
|
183
285
|
|
|
184
|
-
|
|
286
|
+
for (const addon of status.addOns) {
|
|
287
|
+
console.log(addon.name, addon.enabled, addon.tier);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
console.log(status.canUse.smartTransactions);
|
|
291
|
+
console.log(status.canUse.nftQueries);
|
|
292
|
+
console.log(status.canUse.swaps);
|
|
293
|
+
console.log(status.canUse.pumpFun);
|
|
294
|
+
console.log(status.canUse.goldRushData);
|
|
295
|
+
console.log(status.canUse.riskAssessment);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Transactions
|
|
299
|
+
|
|
300
|
+
#### `kit.estimatePriorityFees(options?)`
|
|
301
|
+
|
|
302
|
+
Requires: `priorityFees`
|
|
303
|
+
|
|
304
|
+
Gets live priority fee estimates from QuickNode.
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
const fees = await kit.estimatePriorityFees();
|
|
308
|
+
|
|
309
|
+
console.log(fees.low);
|
|
310
|
+
console.log(fees.medium);
|
|
311
|
+
console.log(fees.recommended);
|
|
312
|
+
console.log(fees.high);
|
|
313
|
+
console.log(fees.extreme);
|
|
314
|
+
console.log(fees.networkCongestion);
|
|
315
|
+
```
|
|
185
316
|
|
|
186
|
-
|
|
317
|
+
With an account filter:
|
|
187
318
|
|
|
188
319
|
```ts
|
|
189
320
|
const fees = await kit.estimatePriorityFees({
|
|
190
|
-
account:
|
|
191
|
-
lastNBlocks:
|
|
321
|
+
account: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',
|
|
322
|
+
lastNBlocks: 50,
|
|
192
323
|
});
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
#### `kit.sendSmartTransaction({ transaction, signer, options })`
|
|
327
|
+
|
|
328
|
+
Uses:
|
|
329
|
+
|
|
330
|
+
- Solana simulation to estimate compute units
|
|
331
|
+
- QuickNode Priority Fee API when available
|
|
332
|
+
- compute budget instruction injection
|
|
333
|
+
- retry loop with backoff
|
|
334
|
+
|
|
335
|
+
Requires: no add-on strictly required, but `priorityFees` makes it much better
|
|
336
|
+
|
|
337
|
+
```ts
|
|
338
|
+
import bs58 from 'bs58';
|
|
339
|
+
import {
|
|
340
|
+
Keypair,
|
|
341
|
+
LAMPORTS_PER_SOL,
|
|
342
|
+
SystemProgram,
|
|
343
|
+
Transaction,
|
|
344
|
+
} from '@solana/web3.js';
|
|
345
|
+
import { QNSolanaKit } from 'quicknode-solana-kit';
|
|
346
|
+
|
|
347
|
+
const kit = new QNSolanaKit({
|
|
348
|
+
endpointUrl: process.env.QN_ENDPOINT_URL!,
|
|
349
|
+
addOns: { priorityFees: true },
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const signer = Keypair.fromSecretKey(bs58.decode(process.env.WALLET_PRIVATE_KEY!));
|
|
353
|
+
|
|
354
|
+
const transaction = new Transaction().add(
|
|
355
|
+
SystemProgram.transfer({
|
|
356
|
+
fromPubkey: signer.publicKey,
|
|
357
|
+
toPubkey: signer.publicKey,
|
|
358
|
+
lamports: Math.floor(0.001 * LAMPORTS_PER_SOL),
|
|
359
|
+
}),
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
const result = await kit.sendSmartTransaction({
|
|
363
|
+
transaction,
|
|
364
|
+
signer,
|
|
365
|
+
options: {
|
|
366
|
+
feeLevel: 'recommended',
|
|
367
|
+
simulateFirst: true,
|
|
368
|
+
maxRetries: 5,
|
|
369
|
+
computeUnitBuffer: 10,
|
|
370
|
+
skipPreflight: false,
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
console.log(result.signature);
|
|
375
|
+
console.log(result.slot);
|
|
376
|
+
console.log(result.priorityFeeMicroLamports);
|
|
377
|
+
console.log(result.computeUnitsUsed);
|
|
378
|
+
console.log(result.confirmationMs);
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
#### `kit.prepareSmartTransaction({ transaction, payer, options })`
|
|
382
|
+
|
|
383
|
+
Prepares a transaction with compute budget instructions and recent blockhash, but does not send it.
|
|
193
384
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
385
|
+
This is useful for wallet adapters.
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
const prepared = await kit.prepareSmartTransaction({
|
|
389
|
+
transaction: myTransaction,
|
|
390
|
+
payer: wallet.publicKey,
|
|
391
|
+
options: {
|
|
392
|
+
feeLevel: 'high',
|
|
393
|
+
computeUnitBuffer: 10,
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
console.log(prepared.priorityFeeMicroLamports);
|
|
398
|
+
console.log(prepared.computeUnits);
|
|
399
|
+
|
|
400
|
+
const signature = await wallet.sendTransaction(prepared.transaction, kit.connection);
|
|
401
|
+
console.log(signature);
|
|
200
402
|
```
|
|
201
403
|
|
|
202
|
-
|
|
404
|
+
### Digital Assets and Tokens
|
|
405
|
+
|
|
406
|
+
#### `kit.getAssetsByOwner(options)`
|
|
203
407
|
|
|
204
|
-
|
|
408
|
+
Requires: `das`
|
|
205
409
|
|
|
206
|
-
|
|
410
|
+
Gets digital assets owned by a wallet.
|
|
207
411
|
|
|
208
412
|
```ts
|
|
209
|
-
const
|
|
210
|
-
ownerAddress: '
|
|
211
|
-
limit:
|
|
212
|
-
|
|
213
|
-
sortDirection: 'desc',
|
|
413
|
+
const result = await kit.getAssetsByOwner({
|
|
414
|
+
ownerAddress: 'E645TckHQnDcavVv92Etc6xSWQaq8zzPtPRGBheviRAk',
|
|
415
|
+
limit: 10,
|
|
416
|
+
page: 1,
|
|
214
417
|
});
|
|
215
418
|
|
|
216
|
-
|
|
419
|
+
console.log(result.total);
|
|
420
|
+
|
|
421
|
+
for (const asset of result.items) {
|
|
422
|
+
console.log(asset.id);
|
|
217
423
|
console.log(asset.content.metadata.name);
|
|
218
424
|
console.log(asset.ownership.owner);
|
|
219
|
-
console.log(asset.compression?.compressed);
|
|
220
|
-
}
|
|
425
|
+
console.log(asset.compression?.compressed);
|
|
426
|
+
}
|
|
221
427
|
```
|
|
222
428
|
|
|
223
|
-
|
|
429
|
+
#### `kit.getAsset(mintAddress)`
|
|
224
430
|
|
|
225
|
-
|
|
431
|
+
Requires: `das`
|
|
226
432
|
|
|
227
|
-
|
|
433
|
+
Gets one asset by id or mint address.
|
|
228
434
|
|
|
229
435
|
```ts
|
|
230
|
-
const asset = await kit.getAsset('
|
|
436
|
+
const asset = await kit.getAsset('NFT_MINT_OR_ASSET_ID');
|
|
437
|
+
|
|
438
|
+
console.log(asset.id);
|
|
231
439
|
console.log(asset.content.metadata.name);
|
|
440
|
+
console.log(asset.content.metadata.symbol);
|
|
232
441
|
console.log(asset.content.metadata.image);
|
|
233
442
|
console.log(asset.royalty?.basis_points);
|
|
234
443
|
```
|
|
235
444
|
|
|
236
|
-
|
|
445
|
+
#### `kit.getAssetsByCollection(options)`
|
|
237
446
|
|
|
238
|
-
|
|
447
|
+
Requires: `das`
|
|
239
448
|
|
|
240
|
-
|
|
449
|
+
Gets assets by collection mint.
|
|
241
450
|
|
|
242
451
|
```ts
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
452
|
+
const collectionAssets = await kit.getAssetsByCollection({
|
|
453
|
+
collectionMint: 'COLLECTION_MINT',
|
|
454
|
+
limit: 20,
|
|
455
|
+
page: 1,
|
|
247
456
|
});
|
|
457
|
+
|
|
458
|
+
console.log(collectionAssets.total);
|
|
459
|
+
console.log(collectionAssets.items.map(item => item.content.metadata.name));
|
|
248
460
|
```
|
|
249
461
|
|
|
250
|
-
|
|
462
|
+
#### `kit.searchAssets(options)`
|
|
251
463
|
|
|
252
|
-
|
|
464
|
+
Requires: `das`
|
|
253
465
|
|
|
254
|
-
|
|
466
|
+
Searches by owner, creator, collection, token type, or compressed status.
|
|
255
467
|
|
|
256
468
|
```ts
|
|
257
|
-
const
|
|
258
|
-
|
|
469
|
+
const compressed = await kit.searchAssets({
|
|
470
|
+
ownerAddress: 'WALLET_ADDRESS',
|
|
471
|
+
tokenType: 'compressedNFT',
|
|
472
|
+
compressed: true,
|
|
473
|
+
limit: 50,
|
|
474
|
+
page: 1,
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
console.log(compressed.items.length);
|
|
259
478
|
```
|
|
260
479
|
|
|
261
|
-
|
|
480
|
+
By creator:
|
|
262
481
|
|
|
263
|
-
|
|
482
|
+
```ts
|
|
483
|
+
const created = await kit.searchAssets({
|
|
484
|
+
creatorAddress: 'CREATOR_ADDRESS',
|
|
485
|
+
limit: 25,
|
|
486
|
+
});
|
|
487
|
+
```
|
|
264
488
|
|
|
265
|
-
|
|
489
|
+
By collection:
|
|
266
490
|
|
|
267
491
|
```ts
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
492
|
+
const byCollection = await kit.searchAssets({
|
|
493
|
+
collection: 'COLLECTION_MINT',
|
|
494
|
+
limit: 25,
|
|
495
|
+
});
|
|
272
496
|
```
|
|
273
497
|
|
|
274
|
-
|
|
498
|
+
#### `kit.getAssetProof(assetId)`
|
|
275
499
|
|
|
276
|
-
|
|
500
|
+
Requires: `das`
|
|
277
501
|
|
|
278
|
-
|
|
502
|
+
Gets the Merkle proof for a compressed asset.
|
|
279
503
|
|
|
280
504
|
```ts
|
|
281
|
-
const
|
|
282
|
-
console.log('SOL balance:', update.lamports / 1e9);
|
|
283
|
-
console.log('Backend:', update.backend); // 'yellowstone' or 'websocket'
|
|
284
|
-
});
|
|
505
|
+
const proof = await kit.getAssetProof('ASSET_ID');
|
|
285
506
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
507
|
+
console.log(proof.root);
|
|
508
|
+
console.log(proof.proof);
|
|
509
|
+
console.log(proof.tree_id);
|
|
289
510
|
```
|
|
290
511
|
|
|
291
|
-
|
|
512
|
+
#### `kit.getTokenAccounts(walletAddress)`
|
|
292
513
|
|
|
293
|
-
|
|
514
|
+
No add-on required.
|
|
294
515
|
|
|
295
|
-
|
|
516
|
+
Gets parsed SPL token accounts using standard Solana RPC.
|
|
296
517
|
|
|
297
518
|
```ts
|
|
298
|
-
const
|
|
519
|
+
const tokenAccounts = await kit.getTokenAccounts('WALLET_ADDRESS');
|
|
299
520
|
|
|
300
|
-
const
|
|
301
|
-
if (
|
|
302
|
-
|
|
521
|
+
for (const token of tokenAccounts) {
|
|
522
|
+
if (token.uiAmount > 0) {
|
|
523
|
+
console.log(token.mint, token.uiAmount);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### Streaming
|
|
529
|
+
|
|
530
|
+
#### `kit.watchAccount(address, onUpdate, options?)`
|
|
531
|
+
|
|
532
|
+
No paid add-on required for basic usage.
|
|
533
|
+
|
|
534
|
+
If `yellowstone` is enabled in config, the package prefers that path, but the current implementation falls back to standard WebSocket subscriptions.
|
|
535
|
+
|
|
536
|
+
```ts
|
|
537
|
+
const handle = kit.watchAccount(
|
|
538
|
+
'E645TckHQnDcavVv92Etc6xSWQaq8zzPtPRGBheviRAk',
|
|
539
|
+
(update) => {
|
|
540
|
+
console.log(update.pubkey);
|
|
541
|
+
console.log(update.lamports);
|
|
542
|
+
console.log(update.owner);
|
|
543
|
+
console.log(update.slot);
|
|
544
|
+
console.log(update.backend);
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
backend: 'auto',
|
|
548
|
+
commitment: 'confirmed',
|
|
549
|
+
},
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
setTimeout(() => {
|
|
553
|
+
console.log(handle.isConnected());
|
|
554
|
+
handle.unsubscribe();
|
|
555
|
+
}, 15_000);
|
|
303
556
|
```
|
|
304
557
|
|
|
305
|
-
|
|
558
|
+
#### `kit.watchProgram(programId, onTx, options?)`
|
|
306
559
|
|
|
307
|
-
|
|
560
|
+
Watches program logs through Solana WebSockets.
|
|
308
561
|
|
|
309
|
-
|
|
562
|
+
```ts
|
|
563
|
+
const handle = kit.watchProgram(
|
|
564
|
+
'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',
|
|
565
|
+
(tx) => {
|
|
566
|
+
console.log(tx.signature);
|
|
567
|
+
console.log(tx.logs);
|
|
568
|
+
console.log(tx.err);
|
|
569
|
+
},
|
|
570
|
+
{ commitment: 'confirmed' },
|
|
571
|
+
);
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
#### `kit.watchSlot(onSlot)`
|
|
575
|
+
|
|
576
|
+
Watches slot changes.
|
|
310
577
|
|
|
311
578
|
```ts
|
|
312
579
|
const handle = kit.watchSlot((slot) => {
|
|
313
|
-
|
|
580
|
+
console.log('slot', slot);
|
|
314
581
|
});
|
|
582
|
+
|
|
583
|
+
setTimeout(() => handle.unsubscribe(), 10_000);
|
|
315
584
|
```
|
|
316
585
|
|
|
317
|
-
|
|
586
|
+
### Jupiter / Metis
|
|
318
587
|
|
|
319
|
-
|
|
588
|
+
Requires: `metis`
|
|
320
589
|
|
|
321
|
-
|
|
590
|
+
The SDK builds URLs under your endpoint like:
|
|
591
|
+
|
|
592
|
+
```txt
|
|
593
|
+
https://your-endpoint.quiknode.pro/TOKEN/jupiter/v6/quote
|
|
594
|
+
https://your-endpoint.quiknode.pro/TOKEN/jupiter/v6/swap
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
#### `kit.getSwapQuote(options)`
|
|
322
598
|
|
|
323
599
|
```ts
|
|
324
|
-
import { TOKENS } from '
|
|
600
|
+
import { TOKENS } from 'quicknode-solana-kit';
|
|
325
601
|
|
|
326
602
|
const quote = await kit.getSwapQuote({
|
|
327
|
-
inputMint:
|
|
603
|
+
inputMint: TOKENS.SOL,
|
|
328
604
|
outputMint: TOKENS.USDC,
|
|
329
|
-
amount:
|
|
605
|
+
amount: BigInt(1_000_000_000),
|
|
606
|
+
slippageBps: 50,
|
|
330
607
|
});
|
|
331
608
|
|
|
332
|
-
console.log(
|
|
333
|
-
console.log(
|
|
609
|
+
console.log(quote.inAmount);
|
|
610
|
+
console.log(quote.outAmount);
|
|
611
|
+
console.log(quote.priceImpactPct);
|
|
612
|
+
console.log(quote.routePlan);
|
|
334
613
|
```
|
|
335
614
|
|
|
336
|
-
|
|
615
|
+
#### `kit.swap(options)`
|
|
337
616
|
|
|
338
|
-
|
|
617
|
+
The SDK flow is:
|
|
339
618
|
|
|
340
|
-
|
|
619
|
+
1. fetch quote
|
|
620
|
+
2. request serialized swap transaction
|
|
621
|
+
3. deserialize transaction
|
|
622
|
+
4. sign locally
|
|
623
|
+
5. send with normal Solana connection
|
|
624
|
+
6. confirm
|
|
341
625
|
|
|
342
626
|
```ts
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
627
|
+
import bs58 from 'bs58';
|
|
628
|
+
import { Keypair } from '@solana/web3.js';
|
|
629
|
+
import { QNSolanaKit, TOKENS } from 'quicknode-solana-kit';
|
|
630
|
+
|
|
631
|
+
const signer = Keypair.fromSecretKey(bs58.decode(process.env.WALLET_PRIVATE_KEY!));
|
|
632
|
+
|
|
633
|
+
const kit = new QNSolanaKit({
|
|
634
|
+
endpointUrl: process.env.QN_ENDPOINT_URL!,
|
|
635
|
+
addOns: { metis: true },
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
const swapResult = await kit.swap({
|
|
639
|
+
inputMint: TOKENS.SOL,
|
|
640
|
+
outputMint: TOKENS.USDC,
|
|
641
|
+
amount: BigInt(100_000_000),
|
|
642
|
+
userPublicKey: signer.publicKey.toString(),
|
|
643
|
+
signer,
|
|
644
|
+
slippageBps: 50,
|
|
645
|
+
feeLevel: 'recommended',
|
|
351
646
|
});
|
|
352
647
|
|
|
353
|
-
console.log(
|
|
648
|
+
console.log(swapResult.signature);
|
|
649
|
+
console.log(swapResult.inputAmount);
|
|
650
|
+
console.log(swapResult.outputAmount);
|
|
651
|
+
console.log(swapResult.priceImpactPct);
|
|
354
652
|
```
|
|
355
653
|
|
|
356
|
-
|
|
654
|
+
#### `TOKENS`
|
|
357
655
|
|
|
358
|
-
|
|
656
|
+
Token shortcuts:
|
|
359
657
|
|
|
360
|
-
|
|
658
|
+
```ts
|
|
659
|
+
import { TOKENS } from 'quicknode-solana-kit';
|
|
660
|
+
|
|
661
|
+
console.log(TOKENS.SOL);
|
|
662
|
+
console.log(TOKENS.USDC);
|
|
663
|
+
console.log(TOKENS.USDT);
|
|
664
|
+
console.log(TOKENS.BONK);
|
|
665
|
+
console.log(TOKENS.JUP);
|
|
666
|
+
console.log(TOKENS.RAY);
|
|
667
|
+
console.log(TOKENS.WIF);
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Pump.fun
|
|
671
|
+
|
|
672
|
+
Requires: `pumpfun`
|
|
673
|
+
|
|
674
|
+
The SDK uses REST paths under your endpoint:
|
|
675
|
+
|
|
676
|
+
```txt
|
|
677
|
+
/pump-fun/coins
|
|
678
|
+
/pump-fun/coins/:mint
|
|
679
|
+
/pump-fun/coins/:mint/holders
|
|
680
|
+
/pump-fun/trades/all
|
|
681
|
+
```
|
|
361
682
|
|
|
362
|
-
|
|
683
|
+
#### `kit.getPumpFunTokens(options?)`
|
|
363
684
|
|
|
364
685
|
```ts
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
686
|
+
const tokens = await kit.getPumpFunTokens({
|
|
687
|
+
limit: 10,
|
|
688
|
+
offset: 0,
|
|
689
|
+
includeNsfw: false,
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
for (const token of tokens) {
|
|
693
|
+
console.log(token.mint, token.symbol, token.marketCapSol);
|
|
694
|
+
}
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
#### `kit.getPumpFunToken(mint)`
|
|
698
|
+
|
|
699
|
+
```ts
|
|
700
|
+
const token = await kit.getPumpFunToken('TOKEN_MINT');
|
|
701
|
+
|
|
702
|
+
console.log(token.name);
|
|
703
|
+
console.log(token.symbol);
|
|
704
|
+
console.log(token.creator);
|
|
705
|
+
console.log(token.price);
|
|
706
|
+
console.log(token.bondingCurve.complete);
|
|
369
707
|
```
|
|
370
708
|
|
|
371
|
-
|
|
709
|
+
#### `kit.getPumpFunTokensByCreator(options)`
|
|
710
|
+
|
|
711
|
+
```ts
|
|
712
|
+
const created = await kit.getPumpFunTokensByCreator({
|
|
713
|
+
creator: 'CREATOR_WALLET',
|
|
714
|
+
limit: 20,
|
|
715
|
+
offset: 0,
|
|
716
|
+
});
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
#### `kit.getPumpFunTokenHolders(mint)`
|
|
720
|
+
|
|
721
|
+
```ts
|
|
722
|
+
const holders = await kit.getPumpFunTokenHolders('TOKEN_MINT');
|
|
723
|
+
|
|
724
|
+
for (const holder of holders.slice(0, 10)) {
|
|
725
|
+
console.log(holder.address, holder.balance, holder.percentage);
|
|
726
|
+
}
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
#### `kit.getPumpFunTokenTrades(mint, options?)`
|
|
730
|
+
|
|
731
|
+
```ts
|
|
732
|
+
const trades = await kit.getPumpFunTokenTrades('TOKEN_MINT', {
|
|
733
|
+
limit: 25,
|
|
734
|
+
offset: 0,
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
for (const trade of trades) {
|
|
738
|
+
console.log(trade.signature, trade.isBuy, trade.solAmount, trade.tokenAmount);
|
|
739
|
+
}
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
### Stablecoin Balance API
|
|
743
|
+
|
|
744
|
+
Requires: `stablecoinBalance`
|
|
745
|
+
|
|
746
|
+
Uses QuickNode custom RPC method `qn_getWalletStablecoinBalances`.
|
|
747
|
+
|
|
748
|
+
#### `kit.getStablecoinBalance(options)`
|
|
749
|
+
|
|
750
|
+
```ts
|
|
751
|
+
const balances = await kit.getStablecoinBalance({
|
|
752
|
+
walletAddress: 'WALLET_ADDRESS',
|
|
753
|
+
chains: ['solana', 'ethereum', 'base'],
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
console.log(balances.walletAddress);
|
|
757
|
+
console.log(balances.totalUsdValue);
|
|
758
|
+
|
|
759
|
+
for (const balance of balances.balances) {
|
|
760
|
+
console.log(balance.chain, balance.symbol, balance.balance, balance.usdValue);
|
|
761
|
+
}
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### OpenOcean
|
|
765
|
+
|
|
766
|
+
Requires: `openocean`
|
|
767
|
+
|
|
768
|
+
The SDK uses REST paths under:
|
|
769
|
+
|
|
770
|
+
```txt
|
|
771
|
+
/openocean/v4/solana/quote
|
|
772
|
+
/openocean/v4/solana/swap_quote
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
#### `kit.getOpenOceanQuote(options)`
|
|
776
|
+
|
|
777
|
+
```ts
|
|
778
|
+
const quote = await kit.getOpenOceanQuote({
|
|
779
|
+
inTokenAddress: 'So11111111111111111111111111111111111111112',
|
|
780
|
+
outTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
781
|
+
amount: '1000000000',
|
|
782
|
+
slippage: 1,
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
console.log(quote.inAmount);
|
|
786
|
+
console.log(quote.outAmount);
|
|
787
|
+
console.log(quote.minOutAmount);
|
|
788
|
+
console.log(quote.priceImpact);
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
#### `kit.openOceanSwap(options)`
|
|
792
|
+
|
|
793
|
+
Like the Metis integration, this fetches a serialized transaction, signs locally, sends, then confirms.
|
|
794
|
+
|
|
795
|
+
```ts
|
|
796
|
+
import bs58 from 'bs58';
|
|
797
|
+
import { Keypair } from '@solana/web3.js';
|
|
798
|
+
|
|
799
|
+
const signer = Keypair.fromSecretKey(bs58.decode(process.env.WALLET_PRIVATE_KEY!));
|
|
800
|
+
|
|
801
|
+
const result = await kit.openOceanSwap({
|
|
802
|
+
inTokenAddress: 'So11111111111111111111111111111111111111112',
|
|
803
|
+
outTokenAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
804
|
+
amount: '10000000',
|
|
805
|
+
slippage: 1,
|
|
806
|
+
userAddress: signer.publicKey.toString(),
|
|
807
|
+
signer,
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
console.log(result.signature);
|
|
811
|
+
console.log(result.inAmount);
|
|
812
|
+
console.log(result.outAmount);
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
#### `OO_TOKENS`
|
|
816
|
+
|
|
817
|
+
```ts
|
|
818
|
+
import { OO_TOKENS } from 'quicknode-solana-kit';
|
|
819
|
+
|
|
820
|
+
console.log(OO_TOKENS.SOL);
|
|
821
|
+
console.log(OO_TOKENS.USDC);
|
|
822
|
+
console.log(OO_TOKENS.USDT);
|
|
823
|
+
console.log(OO_TOKENS.BONK);
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
### MEV Protection
|
|
827
|
+
|
|
828
|
+
These methods accept a base64-encoded signed transaction and submit it through the add-on provider, then confirm using a normal Solana connection.
|
|
829
|
+
|
|
830
|
+
#### `kit.sendMerkleProtectedTransaction(options)`
|
|
831
|
+
|
|
832
|
+
Requires: `merkle`
|
|
833
|
+
|
|
834
|
+
```ts
|
|
835
|
+
const result = await kit.sendMerkleProtectedTransaction({
|
|
836
|
+
serializedTransaction: signedTxBase64,
|
|
837
|
+
tipLamports: 10_000,
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
console.log(result.signature);
|
|
841
|
+
console.log(result.provider);
|
|
842
|
+
console.log(result.confirmationMs);
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
#### `kit.sendBlinkLabsTransaction(options)`
|
|
846
|
+
|
|
847
|
+
Requires: `blinklabs`
|
|
848
|
+
|
|
849
|
+
```ts
|
|
850
|
+
const result = await kit.sendBlinkLabsTransaction({
|
|
851
|
+
serializedTransaction: signedTxBase64,
|
|
852
|
+
tipLamports: 5_000,
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
console.log(result.signature);
|
|
856
|
+
console.log(result.provider);
|
|
857
|
+
console.log(result.confirmationMs);
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
### Iris Transaction Sender
|
|
861
|
+
|
|
862
|
+
Requires: `iris`
|
|
863
|
+
|
|
864
|
+
Uses QuickNode custom RPC method `iris_sendTransaction`.
|
|
865
|
+
|
|
866
|
+
#### `kit.sendIrisTransaction(options)`
|
|
867
|
+
|
|
868
|
+
```ts
|
|
869
|
+
const result = await kit.sendIrisTransaction({
|
|
870
|
+
serializedTransaction: signedTxBase64,
|
|
871
|
+
skipPreflight: false,
|
|
872
|
+
maxRetries: 3,
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
console.log(result.signature);
|
|
876
|
+
console.log(result.slot);
|
|
877
|
+
console.log(result.confirmationMs);
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
### GoldRush
|
|
881
|
+
|
|
882
|
+
Requires: `goldrush`
|
|
883
|
+
|
|
884
|
+
Uses REST paths under `/goldrush/v1`.
|
|
885
|
+
|
|
886
|
+
#### `kit.getGoldRushBalances(options)`
|
|
887
|
+
|
|
888
|
+
```ts
|
|
889
|
+
const balances = await kit.getGoldRushBalances({
|
|
890
|
+
walletAddress: 'WALLET_ADDRESS',
|
|
891
|
+
chain: 'solana-mainnet',
|
|
892
|
+
noSpam: true,
|
|
893
|
+
quoteCurrency: 'USD',
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
console.log(balances.chain);
|
|
897
|
+
console.log(balances.address);
|
|
898
|
+
|
|
899
|
+
for (const item of balances.items) {
|
|
900
|
+
console.log(item.symbol, item.balance, item.usdBalance);
|
|
901
|
+
}
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
#### `kit.getGoldRushTransactions(options)`
|
|
905
|
+
|
|
906
|
+
```ts
|
|
907
|
+
const txs = await kit.getGoldRushTransactions({
|
|
908
|
+
walletAddress: 'WALLET_ADDRESS',
|
|
909
|
+
chain: 'solana-mainnet',
|
|
910
|
+
pageSize: 25,
|
|
911
|
+
pageNumber: 0,
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
console.log(txs.currentPage);
|
|
915
|
+
|
|
916
|
+
for (const tx of txs.items) {
|
|
917
|
+
console.log(tx.txHash, tx.successful, tx.value);
|
|
918
|
+
}
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
### Titan
|
|
922
|
+
|
|
923
|
+
Requires: `titan`
|
|
924
|
+
|
|
925
|
+
The SDK supports:
|
|
926
|
+
|
|
927
|
+
- point-in-time quote
|
|
928
|
+
- swap execution
|
|
929
|
+
- quote streaming over WebSocket
|
|
930
|
+
|
|
931
|
+
#### `kit.getTitanSwapQuote(options)`
|
|
932
|
+
|
|
933
|
+
```ts
|
|
934
|
+
const quote = await kit.getTitanSwapQuote({
|
|
935
|
+
inputMint: 'So11111111111111111111111111111111111111112',
|
|
936
|
+
outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
937
|
+
amount: '1000000000',
|
|
938
|
+
slippageBps: 50,
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
console.log(quote.inAmount);
|
|
942
|
+
console.log(quote.outAmount);
|
|
943
|
+
console.log(quote.minOutAmount);
|
|
944
|
+
console.log(quote.routes);
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
#### `kit.titanSwap(options)`
|
|
948
|
+
|
|
949
|
+
```ts
|
|
950
|
+
const result = await kit.titanSwap({
|
|
951
|
+
inputMint: 'So11111111111111111111111111111111111111112',
|
|
952
|
+
outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
953
|
+
amount: '10000000',
|
|
954
|
+
slippageBps: 50,
|
|
955
|
+
userPublicKey: walletPublicKey,
|
|
956
|
+
});
|
|
957
|
+
|
|
958
|
+
console.log(result.signature);
|
|
959
|
+
console.log(result.inAmount);
|
|
960
|
+
console.log(result.outAmount);
|
|
961
|
+
```
|
|
962
|
+
|
|
963
|
+
#### `kit.subscribeTitanQuotes(options, onQuote, onError?)`
|
|
964
|
+
|
|
965
|
+
```ts
|
|
966
|
+
const unsubscribe = kit.subscribeTitanQuotes(
|
|
967
|
+
{
|
|
968
|
+
inputMint: 'So11111111111111111111111111111111111111112',
|
|
969
|
+
outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
970
|
+
amount: '1000000000',
|
|
971
|
+
slippageBps: 50,
|
|
972
|
+
},
|
|
973
|
+
(quote) => {
|
|
974
|
+
console.log('quote', quote.outAmount, quote.priceImpactPct);
|
|
975
|
+
},
|
|
976
|
+
(err) => {
|
|
977
|
+
console.error(err);
|
|
978
|
+
},
|
|
979
|
+
);
|
|
980
|
+
|
|
981
|
+
setTimeout(() => unsubscribe(), 15_000);
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
### Scorechain
|
|
985
|
+
|
|
986
|
+
Requires: `scorechain`
|
|
987
|
+
|
|
988
|
+
Uses REST path `/scorechain/v1/risk`.
|
|
989
|
+
|
|
990
|
+
#### `kit.assessWalletRisk(options)`
|
|
991
|
+
|
|
992
|
+
```ts
|
|
993
|
+
const assessment = await kit.assessWalletRisk({
|
|
994
|
+
address: 'WALLET_ADDRESS',
|
|
995
|
+
network: 'solana',
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
console.log(assessment.address);
|
|
999
|
+
console.log(assessment.riskScore);
|
|
1000
|
+
console.log(assessment.riskLevel);
|
|
1001
|
+
console.log(assessment.amlStatus);
|
|
1002
|
+
console.log(assessment.flags);
|
|
1003
|
+
console.log(assessment.reportUrl);
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
#### `kit.isWalletSafe(address)`
|
|
1007
|
+
|
|
1008
|
+
Returns `true` only when:
|
|
1009
|
+
|
|
1010
|
+
- `amlStatus === 'clean'`
|
|
1011
|
+
- `riskLevel === 'low'`
|
|
1012
|
+
|
|
1013
|
+
```ts
|
|
1014
|
+
const safe = await kit.isWalletSafe('WALLET_ADDRESS');
|
|
1015
|
+
console.log(safe);
|
|
1016
|
+
```
|
|
372
1017
|
|
|
373
1018
|
## Error Handling
|
|
374
1019
|
|
|
375
|
-
|
|
1020
|
+
The package exports custom errors:
|
|
1021
|
+
|
|
1022
|
+
- `AddOnNotEnabledError`
|
|
1023
|
+
- `TransactionFailedError`
|
|
1024
|
+
- `TransactionTimeoutError`
|
|
1025
|
+
- `MaxRetriesExceededError`
|
|
1026
|
+
- `InvalidEndpointError`
|
|
1027
|
+
- `RPCError`
|
|
1028
|
+
|
|
1029
|
+
Example:
|
|
376
1030
|
|
|
377
1031
|
```ts
|
|
378
1032
|
import {
|
|
379
1033
|
AddOnNotEnabledError,
|
|
1034
|
+
RPCError,
|
|
380
1035
|
TransactionFailedError,
|
|
381
|
-
TransactionTimeoutError,
|
|
382
1036
|
MaxRetriesExceededError,
|
|
383
|
-
|
|
384
|
-
} from '@quicknode/solana-kit';
|
|
1037
|
+
} from 'quicknode-solana-kit';
|
|
385
1038
|
|
|
386
1039
|
try {
|
|
387
1040
|
await kit.sendSmartTransaction({ transaction, signer });
|
|
388
1041
|
} catch (err) {
|
|
389
1042
|
if (err instanceof AddOnNotEnabledError) {
|
|
390
|
-
|
|
391
|
-
console.error(err.message);
|
|
1043
|
+
console.error('Enable the missing add-on in QuickNode and update kit config.');
|
|
392
1044
|
} else if (err instanceof TransactionFailedError) {
|
|
393
|
-
|
|
394
|
-
console.error('Failed on-chain:', err.reason);
|
|
395
|
-
console.error('Explorer:', `https://explorer.solana.com/tx/${err.signature}`);
|
|
396
|
-
} else if (err instanceof TransactionTimeoutError) {
|
|
397
|
-
console.error('Timed out. Try a higher feeLevel.');
|
|
1045
|
+
console.error('On-chain failure:', err.signature, err.reason);
|
|
398
1046
|
} else if (err instanceof MaxRetriesExceededError) {
|
|
399
|
-
console.error(
|
|
1047
|
+
console.error('Retries exhausted:', err.maxRetries);
|
|
400
1048
|
} else if (err instanceof RPCError) {
|
|
401
|
-
console.error(
|
|
1049
|
+
console.error('RPC error:', err.statusCode, err.message);
|
|
1050
|
+
} else {
|
|
1051
|
+
console.error(err);
|
|
402
1052
|
}
|
|
403
1053
|
}
|
|
404
1054
|
```
|
|
405
1055
|
|
|
406
|
-
|
|
1056
|
+
## Examples Included In The Package
|
|
1057
|
+
|
|
1058
|
+
Run the examples from the package folder:
|
|
1059
|
+
|
|
1060
|
+
```bash
|
|
1061
|
+
npm run example:tx
|
|
1062
|
+
npm run example:nft
|
|
1063
|
+
npm run example:stream
|
|
1064
|
+
npm run example:swap
|
|
1065
|
+
npm run example:all
|
|
1066
|
+
```
|
|
1067
|
+
|
|
1068
|
+
Environment variables used by the examples:
|
|
1069
|
+
|
|
1070
|
+
```bash
|
|
1071
|
+
QN_ENDPOINT_URL=
|
|
1072
|
+
WALLET_PRIVATE_KEY=
|
|
1073
|
+
WALLET_ADDRESS=
|
|
1074
|
+
ADDON_PRIORITY_FEES=true
|
|
1075
|
+
ADDON_DAS=true
|
|
1076
|
+
ADDON_METIS=true
|
|
1077
|
+
EXECUTE_SWAP=false
|
|
1078
|
+
```
|
|
407
1079
|
|
|
408
|
-
##
|
|
1080
|
+
## Minimal Examples
|
|
409
1081
|
|
|
410
|
-
|
|
1082
|
+
### Minimal client
|
|
411
1083
|
|
|
412
1084
|
```ts
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
1085
|
+
import { QNSolanaKit } from 'quicknode-solana-kit';
|
|
1086
|
+
|
|
1087
|
+
const kit = new QNSolanaKit({
|
|
1088
|
+
endpointUrl: process.env.QN_ENDPOINT_URL!,
|
|
1089
|
+
});
|
|
418
1090
|
```
|
|
419
1091
|
|
|
420
|
-
|
|
1092
|
+
### Minimal fee estimate
|
|
421
1093
|
|
|
422
|
-
|
|
1094
|
+
```ts
|
|
1095
|
+
const fees = await kit.estimatePriorityFees();
|
|
1096
|
+
console.log(fees.recommended);
|
|
1097
|
+
```
|
|
423
1098
|
|
|
424
|
-
|
|
425
|
-
# Clone and install
|
|
426
|
-
git clone https://github.com/quiknode-labs/qn-solana-kit
|
|
427
|
-
cd qn-solana-kit
|
|
428
|
-
npm install
|
|
1099
|
+
### Minimal NFT query
|
|
429
1100
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
1101
|
+
```ts
|
|
1102
|
+
const assets = await kit.getAssetsByOwner({
|
|
1103
|
+
ownerAddress: 'WALLET_ADDRESS',
|
|
1104
|
+
});
|
|
434
1105
|
|
|
435
|
-
|
|
436
|
-
|
|
1106
|
+
console.log(assets.items.length);
|
|
1107
|
+
```
|
|
437
1108
|
|
|
438
|
-
|
|
439
|
-
npm run example:tx # Smart transaction (needs Priority Fee API add-on)
|
|
440
|
-
npm run example:nft # NFT queries (needs DAS API add-on)
|
|
441
|
-
npm run example:stream # Live streaming (works on free tier)
|
|
442
|
-
npm run example:swap # Jupiter swap quote (needs Metis add-on)
|
|
1109
|
+
### Minimal swap quote
|
|
443
1110
|
|
|
444
|
-
|
|
445
|
-
|
|
1111
|
+
```ts
|
|
1112
|
+
import { TOKENS } from 'quicknode-solana-kit';
|
|
1113
|
+
|
|
1114
|
+
const quote = await kit.getSwapQuote({
|
|
1115
|
+
inputMint: TOKENS.SOL,
|
|
1116
|
+
outputMint: TOKENS.USDC,
|
|
1117
|
+
amount: BigInt(1_000_000_000),
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
console.log(quote.outAmount);
|
|
446
1121
|
```
|
|
447
1122
|
|
|
1123
|
+
## Notes and Current Limitations
|
|
448
1124
|
|
|
449
|
-
|
|
1125
|
+
- `yellowstone` is exposed in config and add-on checks, but account streaming currently falls back to standard Solana WebSockets.
|
|
1126
|
+
- `liljit` is probed by `checkAddOns()`, but `sendSmartTransaction()` does not currently route through Jito bundles yet.
|
|
1127
|
+
- `sendSmartTransaction()` works without `priorityFees`, but falls back to a default compute unit price.
|
|
1128
|
+
- some add-ons return serialized transactions; the SDK signs and sends those locally using `@solana/web3.js`
|
|
1129
|
+
|
|
1130
|
+
## Import Patterns
|
|
1131
|
+
|
|
1132
|
+
Class-based usage:
|
|
1133
|
+
|
|
1134
|
+
```ts
|
|
1135
|
+
import { QNSolanaKit } from 'quicknode-solana-kit';
|
|
1136
|
+
```
|
|
1137
|
+
|
|
1138
|
+
Function-level usage:
|
|
1139
|
+
|
|
1140
|
+
```ts
|
|
1141
|
+
import {
|
|
1142
|
+
estimatePriorityFees,
|
|
1143
|
+
getAssetsByOwner,
|
|
1144
|
+
getSwapQuote,
|
|
1145
|
+
swap,
|
|
1146
|
+
watchAccount,
|
|
1147
|
+
TOKENS,
|
|
1148
|
+
OO_TOKENS,
|
|
1149
|
+
} from 'quicknode-solana-kit';
|
|
1150
|
+
```
|
|
450
1151
|
|
|
451
|
-
|
|
452
|
-
- Add-ons Marketplace: https://marketplace.quicknode.com
|
|
453
|
-
- Priority Fee API: https://www.quicknode.com/docs/solana/qn_estimatePriorityFees
|
|
454
|
-
- Metaplex DAS API: https://www.quicknode.com/docs/solana/getAsset
|
|
455
|
-
- Metis (Jupiter): https://marketplace.quicknode.com/add-ons/metis-jupiter-v6-swap-api
|
|
456
|
-
- Yellowstone gRPC: https://marketplace.quicknode.com/add-ons/yellowstone-grpc
|
|
1152
|
+
## License
|
|
457
1153
|
|
|
458
|
-
|
|
1154
|
+
MIT
|