quicknode-solana-kit 1.0.1 → 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 +949 -290
- 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,495 +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
|
-
npm install
|
|
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
|
-
|
|
138
|
+
If you explicitly set an add-on to `false` and call a method that requires it, the SDK throws an `AddOnNotEnabledError`.
|
|
139
|
+
|
|
140
|
+
If you leave a value `undefined`, the SDK warns and still tries the network call.
|
|
105
141
|
|
|
106
|
-
|
|
107
|
-
enabled — Query NFTs, compressed NFTs, token metadata
|
|
142
|
+
### 2. Real endpoint capability
|
|
108
143
|
|
|
109
|
-
|
|
110
|
-
not enabled — Best-price token swaps via Jupiter aggregator
|
|
111
|
-
Enable: https://marketplace.quicknode.com/add-ons/metis-jupiter-v6-swap-api
|
|
144
|
+
The actual source of truth is your endpoint.
|
|
112
145
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
const accounts = await kit.connection.getTokenAccountsByOwner(
|
|
187
|
+
wallet,
|
|
188
|
+
{ programId: TOKEN_PROGRAM_ID },
|
|
189
|
+
);
|
|
190
|
+
```
|
|
140
191
|
|
|
141
|
-
###
|
|
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
|
+
```
|
|
214
|
+
|
|
215
|
+
### REST add-on mounted on the same endpoint
|
|
156
216
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
+
```
|
|
177
248
|
|
|
178
|
-
|
|
179
|
-
|
|
249
|
+
### Config fields
|
|
250
|
+
|
|
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
|
|
183
278
|
|
|
184
|
-
|
|
279
|
+
#### `kit.checkAddOns()`
|
|
185
280
|
|
|
186
|
-
|
|
281
|
+
Probes your endpoint and returns add-on availability.
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
const status = await kit.checkAddOns();
|
|
285
|
+
|
|
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
|
+
```
|
|
316
|
+
|
|
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
|
+
```
|
|
193
325
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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);
|
|
200
379
|
```
|
|
201
380
|
|
|
202
|
-
|
|
381
|
+
#### `kit.prepareSmartTransaction({ transaction, payer, options })`
|
|
203
382
|
|
|
204
|
-
|
|
383
|
+
Prepares a transaction with compute budget instructions and recent blockhash, but does not send it.
|
|
205
384
|
|
|
206
|
-
|
|
385
|
+
This is useful for wallet adapters.
|
|
207
386
|
|
|
208
387
|
```ts
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
388
|
+
const prepared = await kit.prepareSmartTransaction({
|
|
389
|
+
transaction: myTransaction,
|
|
390
|
+
payer: wallet.publicKey,
|
|
391
|
+
options: {
|
|
392
|
+
feeLevel: 'high',
|
|
393
|
+
computeUnitBuffer: 10,
|
|
394
|
+
},
|
|
214
395
|
});
|
|
215
396
|
|
|
216
|
-
|
|
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);
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Digital Assets and Tokens
|
|
405
|
+
|
|
406
|
+
#### `kit.getAssetsByOwner(options)`
|
|
407
|
+
|
|
408
|
+
Requires: `das`
|
|
409
|
+
|
|
410
|
+
Gets digital assets owned by a wallet.
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
const result = await kit.getAssetsByOwner({
|
|
414
|
+
ownerAddress: 'E645TckHQnDcavVv92Etc6xSWQaq8zzPtPRGBheviRAk',
|
|
415
|
+
limit: 10,
|
|
416
|
+
page: 1,
|
|
417
|
+
});
|
|
418
|
+
|
|
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
|
+
}
|
|
303
526
|
```
|
|
304
527
|
|
|
305
|
-
|
|
528
|
+
### Streaming
|
|
529
|
+
|
|
530
|
+
#### `kit.watchAccount(address, onUpdate, options?)`
|
|
306
531
|
|
|
307
|
-
|
|
532
|
+
No paid add-on required for basic usage.
|
|
308
533
|
|
|
309
|
-
|
|
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);
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
#### `kit.watchProgram(programId, onTx, options?)`
|
|
559
|
+
|
|
560
|
+
Watches program logs through Solana WebSockets.
|
|
561
|
+
|
|
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
|
|
587
|
+
|
|
588
|
+
Requires: `metis`
|
|
318
589
|
|
|
319
|
-
|
|
590
|
+
The SDK builds URLs under your endpoint like:
|
|
320
591
|
|
|
321
|
-
|
|
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`
|
|
361
673
|
|
|
362
|
-
|
|
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
|
+
```
|
|
682
|
+
|
|
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
|
|
407
1057
|
|
|
408
|
-
|
|
1058
|
+
Run the examples from the package folder:
|
|
409
1059
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
import { watchAccount } from '@quicknode/solana-kit';
|
|
417
|
-
import { swap, TOKENS } from '@quicknode/solana-kit';
|
|
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
|
|
418
1066
|
```
|
|
419
1067
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
## Running the Examples
|
|
1068
|
+
Environment variables used by the examples:
|
|
423
1069
|
|
|
424
1070
|
```bash
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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
|
+
```
|
|
429
1079
|
|
|
430
|
-
|
|
431
|
-
cp .env.example .env
|
|
432
|
-
# Fill in QN_ENDPOINT_URL (required)
|
|
433
|
-
# Fill in WALLET_ADDRESS and WALLET_PRIVATE_KEY for tx/swap examples
|
|
1080
|
+
## Minimal Examples
|
|
434
1081
|
|
|
435
|
-
|
|
436
|
-
npm run check
|
|
1082
|
+
### Minimal client
|
|
437
1083
|
|
|
438
|
-
|
|
439
|
-
|
|
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)
|
|
1084
|
+
```ts
|
|
1085
|
+
import { QNSolanaKit } from 'quicknode-solana-kit';
|
|
443
1086
|
|
|
444
|
-
|
|
445
|
-
|
|
1087
|
+
const kit = new QNSolanaKit({
|
|
1088
|
+
endpointUrl: process.env.QN_ENDPOINT_URL!,
|
|
1089
|
+
});
|
|
1090
|
+
```
|
|
1091
|
+
|
|
1092
|
+
### Minimal fee estimate
|
|
1093
|
+
|
|
1094
|
+
```ts
|
|
1095
|
+
const fees = await kit.estimatePriorityFees();
|
|
1096
|
+
console.log(fees.recommended);
|
|
446
1097
|
```
|
|
447
1098
|
|
|
448
|
-
|
|
1099
|
+
### Minimal NFT query
|
|
449
1100
|
|
|
450
|
-
|
|
1101
|
+
```ts
|
|
1102
|
+
const assets = await kit.getAssetsByOwner({
|
|
1103
|
+
ownerAddress: 'WALLET_ADDRESS',
|
|
1104
|
+
});
|
|
451
1105
|
|
|
1106
|
+
console.log(assets.items.length);
|
|
452
1107
|
```
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
assets/
|
|
467
|
-
das.ts ← getAssetsByOwner, getAsset, searchAssets, etc.
|
|
468
|
-
streaming/
|
|
469
|
-
watcher.ts ← watchAccount, watchProgram, watchSlot
|
|
470
|
-
swap/
|
|
471
|
-
jupiter.ts ← swap, getSwapQuote, TOKENS
|
|
472
|
-
examples/
|
|
473
|
-
1-smart-transaction.ts
|
|
474
|
-
2-nft-queries.ts
|
|
475
|
-
3-live-streaming.ts
|
|
476
|
-
4-jupiter-swap.ts
|
|
477
|
-
run-all.ts
|
|
1108
|
+
|
|
1109
|
+
### Minimal swap quote
|
|
1110
|
+
|
|
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);
|
|
478
1121
|
```
|
|
479
1122
|
|
|
480
|
-
|
|
1123
|
+
## Notes and Current Limitations
|
|
1124
|
+
|
|
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:
|
|
481
1133
|
|
|
482
|
-
|
|
1134
|
+
```ts
|
|
1135
|
+
import { QNSolanaKit } from 'quicknode-solana-kit';
|
|
1136
|
+
```
|
|
483
1137
|
|
|
484
|
-
-
|
|
485
|
-
- Add-ons Marketplace: https://marketplace.quicknode.com
|
|
486
|
-
- Priority Fee API: https://www.quicknode.com/docs/solana/qn_estimatePriorityFees
|
|
487
|
-
- Metaplex DAS API: https://www.quicknode.com/docs/solana/getAsset
|
|
488
|
-
- Metis (Jupiter): https://marketplace.quicknode.com/add-ons/metis-jupiter-v6-swap-api
|
|
489
|
-
- Yellowstone gRPC: https://marketplace.quicknode.com/add-ons/yellowstone-grpc
|
|
1138
|
+
Function-level usage:
|
|
490
1139
|
|
|
491
|
-
|
|
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
|
+
```
|
|
492
1151
|
|
|
493
1152
|
## License
|
|
494
1153
|
|
|
495
|
-
MIT
|
|
1154
|
+
MIT
|