@gabox-labs/sdk 0.1.1 → 0.6.0
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/CHANGELOG.md +249 -1
- package/README.md +116 -458
- package/dist/generated/index.d.ts +334 -755
- package/dist/generated/index.js +2403 -338
- package/dist/generated/index.js.map +1 -1
- package/dist/index-BDfGvmgF.d.ts +934 -0
- package/dist/index.d.ts +211 -472
- package/dist/index.js +539 -1093
- package/dist/index.js.map +1 -1
- package/dist/raydium/index.d.ts +2 -0
- package/dist/raydium/index.js +2 -0
- package/dist/raydium-B-l9V3O-.js +2604 -0
- package/dist/raydium-B-l9V3O-.js.map +1 -0
- package/llms.txt +4 -2
- package/package.json +11 -16
- package/skills/gabox-sdk/SKILL.md +40 -141
- package/skills/gabox-sdk/references/api.md +102 -145
- package/dist/gaboxV2-CV2XltqC.js +0 -3347
- package/dist/gaboxV2-CV2XltqC.js.map +0 -1
- package/dist/index-BxvSkzCO.d.ts +0 -471
- package/dist/pump/index.d.ts +0 -2
- package/dist/pump/index.js +0 -2
- package/dist/pump-D0K_0uiC.js +0 -1531
- package/dist/pump-D0K_0uiC.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,511 +1,169 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @gabox-labs/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Kit-only TypeScript client for Gabox on Solana. A Gabox machine is a prize pool bound to a brand-new
|
|
4
|
+
Raydium LaunchLab coin. The coin trades on its LaunchLab curve until it raises the pinned amount,
|
|
5
|
+
then Raydium migrates it into a Raydium CPMM pool and it trades there.
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
Every function returns plain kit values: `Address`, `bigint`, and transaction messages your wallet
|
|
7
|
-
signs. The SDK never signs or sends anything itself.
|
|
7
|
+
Devnet today. Mainnet addresses are pinned and tested, but the program is not deployed there yet.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
npm install @gabox-labs/sdk @solana/kit
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
ESM only. Node 24 or newer, or any bundler. `@solana/kit` is a peer dependency, so your app keeps
|
|
14
|
-
one copy of it.
|
|
15
|
-
|
|
16
|
-
> **Devnet only, for now.** The program runs on Solana devnet. A mainnet client is supported by the
|
|
17
|
-
> SDK, but there is nothing to talk to there yet. See [Status](#status).
|
|
18
|
-
|
|
19
|
-
**Using an AI coding agent?** This repo ships a skill. See [For AI agents](#for-ai-agents).
|
|
9
|
+
## What it costs
|
|
20
10
|
|
|
21
|
-
|
|
11
|
+
Gabox charges nothing. No pack fee, no creator fee inside the program, no referrals. Every price
|
|
12
|
+
this SDK shows is the venue's own price with the venue's own fees already inside it:
|
|
22
13
|
|
|
23
|
-
|
|
14
|
+
| | On the curve | After graduation |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| venue | Raydium LaunchLab | Raydium CPMM |
|
|
17
|
+
| trade fee | Raydium's `trade_fee_rate` | the pool's `trade_fee_rate` |
|
|
18
|
+
| Gabox platform | 0.5% of every trade | none |
|
|
19
|
+
| coin creator | 0.5% of every trade | the pool's `creator_fee_rate` |
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
Those shares come out of Raydium's revenue, not out of an extra charge Gabox adds. The creator
|
|
22
|
+
collects theirs with `raydium.claimCreatorFee` and `raydium.collectCreatorFee`.
|
|
27
23
|
|
|
28
|
-
|
|
29
|
-
market decides what a pack costs, so the pack price follows the coin. A pack is bought at the
|
|
30
|
-
venue (Pump's bonding curve, or PumpSwap after graduation), and its tokens go into the pool's
|
|
31
|
-
vault.
|
|
24
|
+
## WSOL, not SOL
|
|
32
25
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
Both venues settle in wrapped SOL. So every builder here does the same three things around its
|
|
27
|
+
Gabox instruction: create the wallet's WSOL account, move the lamports it needs into it, and close
|
|
28
|
+
the account again afterwards. Whatever the trade did not spend, and whatever a sale paid in, comes
|
|
29
|
+
back to the wallet as SOL.
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
**Closing unwraps everything.** A wallet that already held WSOL in that account gets it back as SOL
|
|
32
|
+
too. Nothing is lost, but the balance moves. Build your own instructions if you keep a WSOL position
|
|
33
|
+
on purpose.
|
|
40
34
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
## Quick start
|
|
35
|
+
## Create a machine
|
|
44
36
|
|
|
45
37
|
```ts
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
address,
|
|
57
|
-
getSignatureFromTransaction,
|
|
58
|
-
sendAndConfirmTransactionFactory,
|
|
59
|
-
signTransactionMessageWithSigners,
|
|
60
|
-
} from '@solana/kit';
|
|
61
|
-
|
|
62
|
-
// The RPC endpoint goes here. Leave `url` out to use Solana's public devnet endpoint.
|
|
63
|
-
const gabox = createClient({
|
|
64
|
-
cluster: 'devnet',
|
|
65
|
-
url: 'https://devnet.helius-rpc.com/?api-key=…', // your provider; wsUrl is derived
|
|
66
|
-
});
|
|
67
|
-
const mint = address('…the coin…');
|
|
68
|
-
const purchaser = /* a TransactionSigner from your wallet */;
|
|
69
|
-
|
|
70
|
-
// 1. What does a pack cost, and what can it win?
|
|
71
|
-
const offer = await getOffer(gabox, mint, { user: purchaser.address });
|
|
72
|
-
console.log(offer.quoteLamports, offer.prizes, offer.maximum);
|
|
73
|
-
|
|
74
|
-
// 2. Build the purchase. Pin the draw's sequence number so you know its address.
|
|
75
|
-
const pool = await fetchPoolByMint(gabox, mint);
|
|
76
|
-
const seq = pool!.nextSeq;
|
|
77
|
-
const maxQuoteIn = (offer.quoteLamports * 102n) / 100n; // 2% slippage
|
|
78
|
-
const message = await buyPack(gabox, {
|
|
79
|
-
mint,
|
|
80
|
-
purchaser,
|
|
81
|
-
seq,
|
|
82
|
-
maxQuoteIn,
|
|
83
|
-
minMaximum: offer.maximum,
|
|
84
|
-
maxTotalDebit: maxQuoteIn + share(maxQuoteIn, 200n) + 20_000_000n,
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// 3. Sign and send with kit.
|
|
88
|
-
const transaction = await signTransactionMessageWithSigners(message);
|
|
89
|
-
const send = sendAndConfirmTransactionFactory({
|
|
90
|
-
rpc: gabox.rpc,
|
|
91
|
-
rpcSubscriptions: gabox.rpcSubscriptions,
|
|
38
|
+
const client = createClient({ cluster: 'devnet' });
|
|
39
|
+
const estimate = await seedCostEstimate(client);
|
|
40
|
+
const message = await createMachine(client, {
|
|
41
|
+
creator,
|
|
42
|
+
mintKeypair,
|
|
43
|
+
name: 'Gabox',
|
|
44
|
+
symbol: 'GBX',
|
|
45
|
+
uri: 'https://example.com/metadata.json',
|
|
46
|
+
maxSeedQuoteIn: (estimate.quoteAmount * 110n) / 100n,
|
|
47
|
+
maxSeedNativeDebit: 100_000_000n,
|
|
92
48
|
});
|
|
93
|
-
await send(transaction, { commitment: 'confirmed' });
|
|
94
|
-
console.log('bought:', getSignatureFromTransaction(transaction));
|
|
95
|
-
|
|
96
|
-
// 4. Wait for the prize.
|
|
97
|
-
const draw = await drawAddress(offer.pool, seq);
|
|
98
|
-
const resolved = await watchDraw(gabox, draw, {
|
|
99
|
-
onChange: (d) => console.log('status', d.status),
|
|
100
|
-
});
|
|
101
|
-
console.log('won', resolved.amount, 'tokens');
|
|
102
49
|
```
|
|
103
50
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
`createClient` is the one setup step. Call it once, and pass the result to every SDK function that
|
|
109
|
-
reads or writes the chain.
|
|
51
|
+
One transaction, two signers: the mint keypair and the creator. `initialize_pool` refuses to run
|
|
52
|
+
unless the same transaction also carries a LaunchLab `initialize_v2` for the same mint with the
|
|
53
|
+
pinned launch arguments, so the two cannot be separated.
|
|
110
54
|
|
|
111
|
-
|
|
112
|
-
|
|
55
|
+
The creator picks the name, the symbol, the metadata URI and the prize table. Everything else is
|
|
56
|
+
fixed: 6 decimals, 1,000,000,000 coins, 793,100,000 of them sold on the curve, 85 SOL raised on
|
|
57
|
+
mainnet or 3 SOL on devnet, graduate into a CPMM pool, no vesting, the CPMM creator fee paid in
|
|
58
|
+
WSOL. Metaplex limits the three strings to 32, 10 and 200 UTF-8 bytes.
|
|
113
59
|
|
|
114
|
-
|
|
60
|
+
`maxSeedQuoteIn` is both the slippage cap on the seed buy and the number of lamports wrapped before
|
|
61
|
+
it. `maxSeedNativeDebit` is separate and small: it caps the lamports of rent LaunchLab charges for
|
|
62
|
+
the fee vaults it creates on a coin's first trade.
|
|
115
63
|
|
|
116
|
-
|
|
117
|
-
const gabox = createClient({
|
|
118
|
-
cluster: 'devnet',
|
|
119
|
-
url: 'https://devnet.helius-rpc.com/?api-key=…',
|
|
120
|
-
// wsUrl is optional. It follows `url` with `wss://` when left out.
|
|
121
|
-
});
|
|
122
|
-
```
|
|
64
|
+
### The seed
|
|
123
65
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
66
|
+
Pool creation buys a mandatory seed: enough tokens to make a 3x top prize payable on the first pack,
|
|
67
|
+
or the full top prize when the table's top tier is below 3x. `math.seedTokens` computes it. A creator
|
|
68
|
+
can add more with `extraSeedTokens` (default `0n`), which the program adds to the same seed trade.
|
|
69
|
+
`seedCostEstimate` reports the mandatory `seedTokens`, the `extraSeedTokens` passed in, their
|
|
70
|
+
`totalSeedTokens`, and the exact cost of buying the total on a fresh curve. A table's top tier can be
|
|
71
|
+
at most 20x; seed beyond what a 20x prize needs stays in the vault as backup for the draws after a
|
|
72
|
+
top-tier hit.
|
|
130
73
|
|
|
131
|
-
|
|
132
|
-
`addressLookupTables`. If you need a custom transport, spread it and replace `rpc`:
|
|
74
|
+
## Buy a pack
|
|
133
75
|
|
|
134
76
|
```ts
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
### The URL is checked against the cluster
|
|
139
|
-
|
|
140
|
-
`cluster` has no default, and the URL must agree with it. This is on purpose: every address the
|
|
141
|
-
SDK uses exists on every cluster, so a wrong URL does not fail. It sends a real transaction to the
|
|
142
|
-
wrong network.
|
|
143
|
-
|
|
144
|
-
- `devnet` needs a URL that contains `devnet`. A URL that names no cluster is refused too.
|
|
145
|
-
- `mainnet-beta` and `localnet` refuse a URL that names a different cluster. A URL that names no
|
|
146
|
-
cluster is fine, because private endpoints and local validators often do not say.
|
|
147
|
-
|
|
148
|
-
Both `url` and `wsUrl` are checked. A mismatch throws from `createClient`, before any request.
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
## Flows
|
|
153
|
-
|
|
154
|
-
Every builder returns a `GaboxTransactionMessage`: a version 0 message with the fee payer and a
|
|
155
|
-
fresh blockhash already set. Sign it with `signTransactionMessageWithSigners` and send it with kit.
|
|
156
|
-
A blockhash lasts about a minute, so build the message when the user is ready to sign, not when the
|
|
157
|
-
page loads.
|
|
158
|
-
|
|
159
|
-
Every builder also accepts `computeUnitLimit`, `computeUnitPrice` (a priority fee, in micro-lamports
|
|
160
|
-
per unit), and `addressLookupTables`. The defaults are generous.
|
|
161
|
-
|
|
162
|
-
### Create a machine
|
|
163
|
-
|
|
164
|
-
```ts
|
|
165
|
-
import { createMachine, seedCostEstimate } from '@gabox-labs/sdk';
|
|
166
|
-
import { generateKeyPairSigner } from '@solana/kit';
|
|
167
|
-
|
|
168
|
-
const mintKeypair = await generateKeyPairSigner();
|
|
169
|
-
const seed = await seedCostEstimate(gabox, 50_000, 'balanced');
|
|
170
|
-
|
|
171
|
-
const message = await createMachine(gabox, {
|
|
172
|
-
creator, // TransactionSigner. Pays for everything.
|
|
173
|
-
mintKeypair, // Signs once, for the new coin.
|
|
174
|
-
name: 'Lucky Cat',
|
|
175
|
-
symbol: 'CAT',
|
|
176
|
-
uri: 'https://…/metadata.json',
|
|
177
|
-
feeBps: 100, // the creator's fee per pack, 0–100 bps (max 1%)
|
|
178
|
-
riskProfile: 'balanced', // 'conservative' | 'balanced' | 'jackpot'
|
|
179
|
-
jackpotBps: 50_000, // the top prize: 5× one pack
|
|
180
|
-
maxSeedLamports: (seed.lamports * 105n) / 100n,
|
|
181
|
-
});
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
One transaction, two signers: the creator and the new mint. The creator pays for the coin, the
|
|
185
|
-
pool, and the **seed**.
|
|
186
|
-
|
|
187
|
-
The seed is the inventory that backs the jackpot. The first pack must be able to pay the top prize
|
|
188
|
-
in full. A 5× jackpot needs four extra packs of tokens in the vault; a 10× jackpot needs nine. A 1×
|
|
189
|
-
jackpot needs no seed. `seedCostEstimate` tells you what that costs on a fresh Pump curve, in
|
|
190
|
-
lamports and tokens. `maxSeedLamports` is the creator's slippage cap on that buy.
|
|
191
|
-
|
|
192
|
-
- `jackpotBps` is the largest prize, in basis points of one pack. `10_000` is 1×. `50_000` is 5×.
|
|
193
|
-
- `riskProfile` decides how the odds are spread. Every profile returns 95% of a pack's value on
|
|
194
|
-
average. `conservative` keeps more of it in the common prize; `jackpot` moves more into the rare
|
|
195
|
-
ones. See `jackpotTiers(jackpotBps, profile)` to preview the table before creating.
|
|
196
|
-
|
|
197
|
-
### Price a pack
|
|
198
|
-
|
|
199
|
-
```ts
|
|
200
|
-
import { getOffer } from '@gabox-labs/sdk';
|
|
201
|
-
|
|
202
|
-
const offer = await getOffer(gabox, mint, { user: buyer.address });
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
`getOffer` reads the pool, the vault, and the venue, and returns everything a buy screen needs:
|
|
206
|
-
|
|
207
|
-
| field | meaning |
|
|
208
|
-
| -------------------------------------- | ----------------------------------------------------------------------------- |
|
|
209
|
-
| `quoteLamports` | the pack price right now: what the venue charges for one pack, venue fees included |
|
|
210
|
-
| `feeLamports` | the creator's fee, paid on top |
|
|
211
|
-
| `protocolLamports` | the protocol's 1%, paid on top |
|
|
212
|
-
| `prizes` | the prize table this pack would get: `{ amount, tickets }`, amounts in tokens |
|
|
213
|
-
| `maximum`, `minimum` | the largest and smallest prize on that table |
|
|
214
|
-
| `uncapped` | the jackpot with no inventory cap. Equal to `maximum` when the pool is healthy |
|
|
215
|
-
| `isSeeded` | `maximum === uncapped`. Show a warning when this is `false` |
|
|
216
|
-
| `venue` | `'pump'` or `'pumpswap'`: where the buy would route right now |
|
|
217
|
-
| `inventory`, `reserved`, `free` | vault balance, tokens reserved by open draws, and the difference |
|
|
218
|
-
| `maxMultiplierBps`, `averageMultiplierBps` | the table's top and ticket-weighted average multipliers |
|
|
219
|
-
|
|
220
|
-
Prizes can be capped. The table is fixed, but a prize can never exceed what the vault holds beyond
|
|
221
|
-
what open draws already reserve. When the cap bites, `maximum < uncapped` and `isSeeded` is
|
|
222
|
-
`false`. The pack still sells. It just pays less than the table says, and a buyer should see that.
|
|
223
|
-
|
|
224
|
-
`offerFromState` does the same computation from values you already fetched, with no network call.
|
|
225
|
-
|
|
226
|
-
### Buy a pack
|
|
227
|
-
|
|
228
|
-
```ts
|
|
229
|
-
import { buyPack, share } from '@gabox-labs/sdk';
|
|
230
|
-
|
|
231
|
-
const maxQuoteIn = (offer.quoteLamports * 102n) / 100n;
|
|
232
|
-
const message = await buyPack(gabox, {
|
|
77
|
+
const offer = await getOffer(client, mint, { user: purchaser.address });
|
|
78
|
+
const message = await buyPack(client, {
|
|
233
79
|
mint,
|
|
234
|
-
purchaser,
|
|
235
|
-
maxQuoteIn,
|
|
236
|
-
minMaximum: offer.maximum,
|
|
237
|
-
|
|
238
|
-
seq: pool.nextSeq, // optional, see below
|
|
239
|
-
referrer, // optional, see Referrals
|
|
240
|
-
});
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
The buyer signs three limits:
|
|
244
|
-
|
|
245
|
-
| limit | what it caps |
|
|
246
|
-
| --------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
247
|
-
| `maxQuoteIn` | the venue price, in lamports. The token count is fixed, so the price is the only thing that moves. Add your slippage. |
|
|
248
|
-
| `minMaximum` | the top prize, in tokens. Fails if inventory dropped so far that the top prize is now smaller than this. |
|
|
249
|
-
| `maxTotalDebit` | venue price + creator fee + protocol fee + the randomness request fee, all together. Both fees are ~1% of the price. |
|
|
250
|
-
|
|
251
|
-
`maxTotalDebit` does not include account rent or the transaction fee. Budget a few million lamports
|
|
252
|
-
on top; the example above adds 0.02 SOL.
|
|
253
|
-
|
|
254
|
-
**`seq` pins the draw.** Every draw has a sequence number, and its address is derived from it. Pass
|
|
255
|
-
`seq: pool.nextSeq` so you know the draw's address before the transaction lands, and so that a
|
|
256
|
-
retry after a stale blockhash cannot buy a second pack by accident. Then `drawAddress(pool, seq)`
|
|
257
|
-
gives you the address to watch.
|
|
258
|
-
|
|
259
|
-
On the PumpSwap route, `buyPack` also adds the instructions that wrap SOL into WSOL for the buyer.
|
|
260
|
-
You do not need to handle that.
|
|
261
|
-
|
|
262
|
-
### Wait for the draw
|
|
263
|
-
|
|
264
|
-
```ts
|
|
265
|
-
import { watchDraw } from '@gabox-labs/sdk';
|
|
266
|
-
|
|
267
|
-
const resolved = await watchDraw(gabox, draw, {
|
|
268
|
-
signal: AbortSignal.timeout(180_000),
|
|
269
|
-
onChange: (d) => console.log(d.status, d.attempts),
|
|
80
|
+
purchaser,
|
|
81
|
+
maxQuoteIn: (offer.quoteAmount * 102n) / 100n,
|
|
82
|
+
minMaximum: (offer.maximum * 98n) / 100n,
|
|
83
|
+
maxNativeDebit: 100_000_000n,
|
|
270
84
|
});
|
|
271
|
-
// resolved.amount: tokens won, already in the buyer's wallet
|
|
272
85
|
```
|
|
273
86
|
|
|
274
|
-
`
|
|
275
|
-
|
|
276
|
-
|
|
87
|
+
`offer.quoteAmount` is the exact price the venue will charge for one pack right now, fees included.
|
|
88
|
+
The curve math is a port of Raydium's own, not an estimate, so the `PackBought` event reports the
|
|
89
|
+
same number unless somebody trades in between.
|
|
277
90
|
|
|
278
|
-
|
|
91
|
+
`maxQuoteIn` is the slippage cap, in WSOL, and the number of lamports wrapped before the buy.
|
|
92
|
+
`maxNativeDebit` is separate: it caps the lamports the handler watches, which are the VRF request
|
|
93
|
+
and any venue account rent. Gabox adds nothing to either.
|
|
279
94
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
Selling goes through the SDK, so the sale routes to the right venue:
|
|
95
|
+
## Sell
|
|
283
96
|
|
|
284
97
|
```ts
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const grossOutput = await pump.sellQuote(gabox, mint, resolved.amount, { user: purchaser.address });
|
|
288
|
-
const message = await sellTokens(gabox, {
|
|
98
|
+
const venue = await resolveVenue(client, { mint, user: seller.address });
|
|
99
|
+
const message = await sellTokens(client, {
|
|
289
100
|
mint,
|
|
290
|
-
seller
|
|
291
|
-
amount
|
|
292
|
-
minQuoteOutput: (
|
|
101
|
+
seller,
|
|
102
|
+
amount,
|
|
103
|
+
minQuoteOutput: (venue.quoteSell(amount) * 98n) / 100n,
|
|
104
|
+
maxNativeDebit: 100_000_000n,
|
|
293
105
|
});
|
|
294
106
|
```
|
|
295
107
|
|
|
296
|
-
|
|
297
|
-
the Pump route the seller receives SOL. On the PumpSwap route the seller receives WSOL in their
|
|
298
|
-
WSOL account; add an unwrap if they want lamports.
|
|
299
|
-
|
|
300
|
-
### Fund a machine's prizes
|
|
108
|
+
The seller keeps the whole venue proceeds. `minQuoteOutput` is the venue's own floor.
|
|
301
109
|
|
|
302
|
-
|
|
110
|
+
## Which venue
|
|
303
111
|
|
|
304
|
-
|
|
305
|
-
import { fundPrizes, fundPrizesWithBuy, seedShortfall } from '@gabox-labs/sdk';
|
|
306
|
-
|
|
307
|
-
// Tokens the donor already holds:
|
|
308
|
-
await fundPrizes(gabox, { mint, funder, amount });
|
|
309
|
-
|
|
310
|
-
// Or buy them and donate in one transaction. `seedShortfall(offer)` is the amount that
|
|
311
|
-
// uncaps the top prize right now.
|
|
312
|
-
await fundPrizesWithBuy(gabox, { mint, funder, tokens: seedShortfall(offer), maxQuoteIn });
|
|
313
|
-
```
|
|
112
|
+
`resolveVenue(client, { mint, user })` reads the LaunchLab pool's `status` and follows it:
|
|
314
113
|
|
|
315
|
-
|
|
114
|
+
- `0`: the curve is still selling, so the trade routes to LaunchLab.
|
|
115
|
+
- `1`: the raise is finished and Raydium is migrating the coin. Nothing trades. This throws, and the
|
|
116
|
+
message says to retry. On devnet the move usually finishes within a minute.
|
|
117
|
+
- `2`: the coin graduated, so the trade routes to its CPMM pool.
|
|
316
118
|
|
|
317
|
-
|
|
119
|
+
A migrated CPMM pool is usually at `["pool", cpswap_config, token_0, token_1]`, but not always:
|
|
120
|
+
Raydium picks a fresh address when that one is taken. So the pool has to prove itself from its own
|
|
121
|
+
data — CPMM owns it, it carries the `PoolState` discriminator, its `pool_creator` is the coin
|
|
122
|
+
creator, its two mints are the sorted pair, and `enable_creator_fee` is true. That last flag is the
|
|
123
|
+
one that cannot be forged: plain CPMM `initialize` always leaves it false. The program checks the
|
|
124
|
+
same five things before it forwards a trade, and reads the fee tier, both vaults and the oracle out
|
|
125
|
+
of the pool account rather than deriving them.
|
|
318
126
|
|
|
319
|
-
|
|
320
|
-
the referrer 1% of the creator's fee on that pack. The buyer pays nothing extra.
|
|
127
|
+
## Creator fees
|
|
321
128
|
|
|
322
129
|
```ts
|
|
323
|
-
|
|
130
|
+
const owed = await raydium.fetchCreatorFees(client, { creator: creator.address, mint });
|
|
131
|
+
// owed.curveLamports, owed.cpmmLamports, owed.cpmmTokens
|
|
324
132
|
|
|
325
|
-
//
|
|
326
|
-
await
|
|
327
|
-
|
|
328
|
-
// Or bind and buy in one transaction. Ignored when the wallet is already bound:
|
|
329
|
-
await buyPack(gabox, { ...input, referrer: referrerAddress });
|
|
330
|
-
|
|
331
|
-
// The referrer reads and claims what a pool owes them:
|
|
332
|
-
const owed = await fetchReferralReward(gabox, poolAddress, referrer.address);
|
|
333
|
-
await claimReferral(gabox, referrer, poolAddress);
|
|
133
|
+
await raydium.claimCreatorFee(client, { creator }); // every coin on the curve, at once
|
|
134
|
+
await raydium.collectCreatorFee(client, { mint, creator }); // one graduated coin
|
|
334
135
|
```
|
|
335
136
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
```ts
|
|
342
|
-
import { drawAvailability, retryDraw, expireDraw } from '@gabox-labs/sdk';
|
|
343
|
-
|
|
344
|
-
const state = await drawAvailability(gabox, draw);
|
|
345
|
-
// { canRetry, canExpire, slotsUntilRetry, slotsUntilExpiry, attempts, status }
|
|
346
|
-
|
|
347
|
-
if (state?.canRetry) await retryDraw(gabox, { payer, pool, draw, maxVrfDebit: 5_000_000n });
|
|
348
|
-
if (state?.canExpire) await expireDraw(gabox, { payer, pool, draw });
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
- `retryDraw` asks for randomness again. Allowed 300 slots after the last attempt, up to 3 attempts
|
|
352
|
-
in total. The payer covers the request fee, capped by `maxVrfDebit`.
|
|
353
|
-
- `expireDraw` settles a draw that never received randomness, 216,000 slots (about one day) after
|
|
354
|
-
the purchase. It pays the **smallest prize** on the draw's table. It is not a refund. Tell buyers
|
|
355
|
-
this before they pay.
|
|
356
|
-
|
|
357
|
-
Use `drawAvailability` to show a countdown instead of sending a transaction that fails.
|
|
358
|
-
|
|
359
|
-
---
|
|
360
|
-
|
|
361
|
-
## Reading state
|
|
362
|
-
|
|
363
|
-
| function | returns |
|
|
364
|
-
| ----------------------------------------- | ------------------------------------------------------------- |
|
|
365
|
-
| `fetchPoolByMint(gabox, mint)` | the machine's `Pool`, or `null` |
|
|
366
|
-
| `fetchPoolAt(gabox, poolAddress)` | the same, by pool address |
|
|
367
|
-
| `fetchPoolInventory(gabox, mint)` | the pool plus live `inventory`, `reserved`, `free` |
|
|
368
|
-
| `fetchDraw(gabox, drawAddress)` | a `Draw`, or `null` once it is delivered and closed |
|
|
369
|
-
| `listPools(gabox)` | every machine |
|
|
370
|
-
| `listDraws(gabox, { pool?, purchaser? })` | open draws, filtered by machine, by buyer, or both |
|
|
371
|
-
| `listDrawsByPurchaser(gabox, wallet)` | "what am I still waiting on" |
|
|
372
|
-
| `listReferralLinksByReferrer(gabox, ref)` | every wallet bound to a referrer |
|
|
373
|
-
| `fetchEvents(gabox, signature)` | the SDK events one transaction emitted |
|
|
374
|
-
|
|
375
|
-
The `list*` functions use `getProgramAccounts`. Public RPC endpoints rate-limit that call, so cache
|
|
376
|
-
the result in your app rather than calling it on every page view.
|
|
377
|
-
|
|
378
|
-
Addresses are derived, not looked up: `poolAddress(mint)`, `drawAddress(pool, seq)`,
|
|
379
|
-
`vaultAddress(mint)`, `referralLinkAddress(wallet)`, `referralAddress(pool, referrer)`, and
|
|
380
|
-
`associatedTokenAddress(owner, mint)`.
|
|
381
|
-
|
|
382
|
-
## Events
|
|
137
|
+
LaunchLab keeps one creator fee vault per wallet per quote asset, so a single claim sweeps every coin
|
|
138
|
+
that wallet launched. A CPMM pool keeps its creator fee inside the pool account, so that one is per
|
|
139
|
+
coin. Both pay into the creator's WSOL account, and both builders close it so the creator receives
|
|
140
|
+
SOL.
|
|
383
141
|
|
|
384
|
-
|
|
142
|
+
## Wallet activity
|
|
385
143
|
|
|
386
|
-
|
|
387
|
-
|
|
144
|
+
`buyPack` keeps a `WalletActivity` account per buyer, at the PDA `findActivityPda({ purchaser })`
|
|
145
|
+
(also `activityAddress(wallet)`). It tracks `packsBought` and `nativeSpent` across every pool.
|
|
146
|
+
`nativeSpent` is what the venue charged in WSOL, which is SOL; Gabox's own rent and the VRF fee are
|
|
147
|
+
not counted. The buyer pays its rent once, on the first purchase, and `buyPack` resolves the account
|
|
148
|
+
itself. Read it with `fetchWalletActivity(client, wallet)`, which returns `null` before a wallet's
|
|
149
|
+
first purchase.
|
|
388
150
|
|
|
389
|
-
|
|
390
|
-
if (event.name === 'PackBought') console.log(event.data.venueDebit, event.data.prizes);
|
|
391
|
-
if (event.name === 'DrawResolved') console.log(event.data.amount, event.data.timedOut);
|
|
392
|
-
}
|
|
393
|
-
```
|
|
151
|
+
## Draws
|
|
394
152
|
|
|
395
|
-
|
|
396
|
-
`
|
|
397
|
-
|
|
153
|
+
Gabox delivers awards and closes draws atomically. Use `fetchEvents`, `decodeEvents` and
|
|
154
|
+
`findResolvedDraw` for final state. There is no Ready, claim or sell-prize flow. Existing base tokens
|
|
155
|
+
can be donated irrevocably with `fundPrizes`; a stalled draw uses `retryDraw` or `expireDraw`.
|
|
398
156
|
|
|
399
157
|
## Errors
|
|
400
158
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
```ts
|
|
404
|
-
import { generated } from '@gabox-labs/sdk';
|
|
405
|
-
|
|
406
|
-
try {
|
|
407
|
-
await send(transaction, { commitment: 'confirmed' });
|
|
408
|
-
} catch (error) {
|
|
409
|
-
// `message` is the GaboxTransactionMessage you built. It tells the check which instruction is ours.
|
|
410
|
-
if (generated.isGaboxV2Error(error, message, generated.GABOX_V2_ERROR__SLIPPAGE_EXCEEDED)) {
|
|
411
|
-
// ask the user to widen maxQuoteIn and rebuild
|
|
412
|
-
} else if (generated.isGaboxV2Error(error, message)) {
|
|
413
|
-
console.log(generated.getGaboxV2ErrorMessage(error.context.code));
|
|
414
|
-
} else {
|
|
415
|
-
throw error;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
`getGaboxV2ErrorMessage` returns a readable message in development builds and a placeholder when
|
|
421
|
-
`NODE_ENV` is `production`, to keep bundles small.
|
|
422
|
-
|
|
423
|
-
The ones a UI will meet:
|
|
424
|
-
|
|
425
|
-
| error | when |
|
|
426
|
-
| -------------------- | -------------------------------------------------------------------------- |
|
|
427
|
-
| `SlippageExceeded` | the venue price moved past `maxQuoteIn`, or the sale returned less than `minQuoteOutput` |
|
|
428
|
-
| `PrizeCapChanged` | the top prize fell below `minMaximum` between quote and send |
|
|
429
|
-
| `RetryTooSoon` | `retryDraw` before 300 slots passed |
|
|
430
|
-
| `RetryUnavailable` | `retryDraw` after 3 attempts, or on a draw that is no longer pending |
|
|
431
|
-
| `NotExpired` | `expireDraw` before the deadline |
|
|
432
|
-
| `InvalidReferral` | a self-referral, or a link that does not match |
|
|
433
|
-
| `ZeroAmount` | a zero `amount` or a zero `minQuoteOutput` |
|
|
434
|
-
|
|
435
|
-
The SDK also throws plain `Error`s before building, for example when a mint has no machine, when
|
|
436
|
-
`maxQuoteIn` is not positive, or when a message would exceed Solana's 1,232-byte limit.
|
|
437
|
-
|
|
438
|
-
---
|
|
439
|
-
|
|
440
|
-
## Units and conventions
|
|
441
|
-
|
|
442
|
-
- **Tokens** are in base units. Every Pump coin has 6 decimals, so `1_000_000n` is one whole token
|
|
443
|
-
and a pack (`PACK_TOKENS`) is `1_000_000n * 1_000_000n`.
|
|
444
|
-
- **SOL** is in lamports. WSOL is used on the PumpSwap route, and the SDK handles the wrapping.
|
|
445
|
-
- **Every amount is a `bigint`.** Basis points are `number`. `share(amount, bps)` computes a share.
|
|
446
|
-
- **Addresses** are kit `Address` strings. The SDK never exposes `PublicKey` or `BN`.
|
|
447
|
-
- **Async by default.** Address derivation is async, because kit's PDA derivation is.
|
|
448
|
-
|
|
449
|
-
## Constants
|
|
450
|
-
|
|
451
|
-
| constant | value | meaning |
|
|
452
|
-
| ----------------------- | ---------------------------------- | --------------------------------------------------------- |
|
|
453
|
-
| `PACK_TOKENS` | `1_000_000n * 1_000_000n` | tokens in one pack. Prefer `pool.packTokens` when you have a pool |
|
|
454
|
-
| `PROTOCOL_FEE_BPS` | `100n` | the protocol's 1% on every purchase and every sale |
|
|
455
|
-
| `MAX_FEE_BPS` | `100` | the largest creator fee: 1% of the venue price |
|
|
456
|
-
| `REFERRAL_FEE_BPS` | `100n` | the referrer's 1% of the creator fee |
|
|
457
|
-
| `RETRY_SLOTS` | `300n` | slots between randomness attempts |
|
|
458
|
-
| `MAX_ATTEMPTS` | `3` | randomness attempts per draw, counting the first |
|
|
459
|
-
| `TIMEOUT_SLOTS` | `216_000n` | slots until a draw can be expired |
|
|
460
|
-
| `TIERS`, `TICKETS` | `8`, `65_536` | rows in a prize table, and tickets per table |
|
|
461
|
-
| `GABOX_PROGRAM_ID` | `GaBoxR9nYcK1zeu8EvSJVHV3SrYpCFmvbh2MLgobMcUA` | the program |
|
|
462
|
-
|
|
463
|
-
## Entry points
|
|
464
|
-
|
|
465
|
-
| import | what |
|
|
466
|
-
| ------------------------- | ---------------------------------------------------------------------------------------- |
|
|
467
|
-
| `@gabox-labs/sdk` | everything above: the client, builders, readers, math, events, constants |
|
|
468
|
-
| `@gabox-labs/sdk/generated` | the low-level generated client: instruction builders, account and event codecs, error codes. Also available as the `generated` namespace |
|
|
469
|
-
| `@gabox-labs/sdk/pump` | the venue layer: `resolveVenue`, `curveQuote`, `sellQuote`, and the Pump/PumpSwap account lists. Also available as the `pump` namespace |
|
|
470
|
-
|
|
471
|
-
The `generated` functions take a kit `Rpc` (`gabox.rpc`), not the client.
|
|
472
|
-
|
|
473
|
-
---
|
|
474
|
-
|
|
475
|
-
## For AI agents
|
|
476
|
-
|
|
477
|
-
This repository is agent-ready.
|
|
478
|
-
|
|
479
|
-
- **[`skills/gabox-sdk/SKILL.md`](skills/gabox-sdk/SKILL.md)** teaches an agent how to integrate the
|
|
480
|
-
SDK: setup, the flows, the limits a buyer signs, and the mistakes to avoid. It follows the
|
|
481
|
-
[Agent Skills](https://agentskills.io) format, so it installs into Claude Code, Cursor, Codex,
|
|
482
|
-
and others:
|
|
483
|
-
|
|
484
|
-
```sh
|
|
485
|
-
npx skills add gabox-labs/gabox-sdk
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
- **[`skills/gabox-sdk/references/api.md`](skills/gabox-sdk/references/api.md)** is a compact
|
|
489
|
-
reference of every exported function and type.
|
|
490
|
-
- **[`llms.txt`](llms.txt)** points a model at the right files.
|
|
491
|
-
- **[`AGENTS.md`](AGENTS.md)** is for agents working on this repository itself.
|
|
492
|
-
|
|
493
|
-
## Status
|
|
494
|
-
|
|
495
|
-
- **Devnet only.** Mainnet is not live.
|
|
496
|
-
- The devnet program is being upgraded to the build this SDK targets. Until that upgrade lands,
|
|
497
|
-
transactions built by this SDK do not match the deployed program, and `fetchPoolByMint` reports
|
|
498
|
-
machines from the previous build as an "older devnet account layout". Watch the
|
|
499
|
-
[changelog](CHANGELOG.md) for the release that marks the upgrade done.
|
|
500
|
-
- The Pump bonding-curve route has an end-to-end test on devnet (`GABOX_DEVNET_E2E=1`). The
|
|
501
|
-
PumpSwap route (coins that graduated off the curve) has unit coverage only.
|
|
502
|
-
- The API is `0.x`. Breaking changes bump the minor version and are listed in the changelog.
|
|
503
|
-
|
|
504
|
-
## Contributing
|
|
505
|
-
|
|
506
|
-
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the development setup and the checks that run before
|
|
507
|
-
a release.
|
|
159
|
+
The generated client decodes the program's own errors by name. The ones a client meets most:
|
|
508
160
|
|
|
509
|
-
|
|
161
|
+
| Error | What to do |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| `InvalidVenue` | The account list did not match. Resolve the venue again and rebuild. |
|
|
164
|
+
| `SlippageExceeded` | The price moved past `maxQuoteIn`, or a cost went past `maxNativeDebit`. |
|
|
165
|
+
| `PrizeCapChanged` | The top prize fell below `minMaximum`. Refresh the offer. |
|
|
166
|
+
| `IncorrectTokenDelta` | The venue did not deliver exactly one pack. Usually a curve with less than a pack left; wait for graduation. |
|
|
167
|
+
| `InvalidLaunch` | The LaunchLab create instruction was missing or did not match the pinned shape. |
|
|
510
168
|
|
|
511
|
-
[
|
|
169
|
+
See [the API reference](skills/gabox-sdk/references/api.md).
|