@gabox-labs/sdk 0.2.0 → 0.7.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 +310 -0
- package/README.md +173 -438
- package/dist/{gaboxV2-CV2XltqC.js → gabox-DGTCh34U.js} +575 -1584
- package/dist/gabox-DGTCh34U.js.map +1 -0
- package/dist/generated/index.d.ts +384 -752
- package/dist/generated/index.js +116 -338
- package/dist/generated/index.js.map +1 -1
- package/dist/index-C4at2cZ_.d.ts +1184 -0
- package/dist/index.d.ts +474 -432
- package/dist/index.js +1186 -1374
- 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-CU-tZzIk.js +3282 -0
- package/dist/raydium-CU-tZzIk.js.map +1 -0
- package/llms.txt +7 -3
- package/package.json +11 -16
- package/skills/gabox-sdk/SKILL.md +57 -146
- package/skills/gabox-sdk/references/api.md +155 -145
- 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,513 +1,248 @@
|
|
|
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 its target, then
|
|
5
|
+
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).
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## What is a machine?
|
|
9
|
+
## What it costs
|
|
24
10
|
|
|
25
|
-
|
|
26
|
-
|
|
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:
|
|
27
13
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
venue
|
|
31
|
-
|
|
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` |
|
|
32
20
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
one prize, and the tokens are sent straight to the buyer's wallet. The buyer signs once, at
|
|
36
|
-
purchase. Keeping the prize needs nothing else. Selling it later is one more transaction.
|
|
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`.
|
|
37
23
|
|
|
38
|
-
|
|
39
|
-
tokens that back the table's top prize at creation, and earns a fee on every pack.
|
|
24
|
+
## The quote asset
|
|
40
25
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
26
|
+
A machine is priced in one quote asset, fixed when the pool is created. It defaults to wrapped SOL.
|
|
27
|
+
Any quote Raydium enabled on LaunchLab works: USDC, a stock token, anything Raydium wrote a
|
|
28
|
+
`GlobalConfig` for. There is no list in the program or in this SDK; the account itself is the proof.
|
|
44
29
|
|
|
45
30
|
```ts
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
drawAddress,
|
|
49
|
-
fetchPoolByMint,
|
|
50
|
-
getOffer,
|
|
51
|
-
buyPack,
|
|
52
|
-
share,
|
|
53
|
-
watchDraw,
|
|
54
|
-
} from '@gabox-labs/sdk';
|
|
55
|
-
import {
|
|
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,
|
|
92
|
-
});
|
|
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');
|
|
31
|
+
const config = await raydium.fetchQuoteConfig(client, someMint);
|
|
32
|
+
// null when Raydium enabled no such quote. `raydium.isQuoteSupported` is the boolean version.
|
|
102
33
|
```
|
|
103
34
|
|
|
104
|
-
|
|
35
|
+
The quote mint may be classic SPL Token or Token-2022. The coin is always classic SPL Token.
|
|
105
36
|
|
|
106
|
-
##
|
|
37
|
+
## Paying in SOL
|
|
107
38
|
|
|
108
|
-
|
|
109
|
-
reads or writes the chain.
|
|
39
|
+
Buyers pay in SOL whatever the pool is priced in.
|
|
110
40
|
|
|
111
|
-
|
|
112
|
-
|
|
41
|
+
- **A WSOL pool.** Every builder creates the wallet's WSOL account, moves the lamports it needs into
|
|
42
|
+
it, and closes the account again afterwards. Whatever the trade did not spend, and whatever a sale
|
|
43
|
+
paid in, comes back as SOL.
|
|
44
|
+
- **Any other pool.** A route provider swaps SOL into the quote token **in the same transaction** as
|
|
45
|
+
the Gabox instruction, and back again after a sale. One signature, one transaction; the SDK never
|
|
46
|
+
splits the two, because a swap that settled on its own would leave the buyer holding a token they
|
|
47
|
+
never asked for.
|
|
113
48
|
|
|
114
|
-
|
|
49
|
+
```ts
|
|
50
|
+
import { createClient, raydiumCpmmRoute } from '@gabox-labs/sdk';
|
|
115
51
|
|
|
116
|
-
//
|
|
117
|
-
const
|
|
52
|
+
// Mainnet gets Jupiter by default. Devnet has no router, so name a CPMM pool for the SOL pair.
|
|
53
|
+
const client = createClient({
|
|
118
54
|
cluster: 'devnet',
|
|
119
|
-
|
|
120
|
-
// wsUrl is optional. It follows `url` with `wss://` when left out.
|
|
55
|
+
route: raydiumCpmmRoute(devnetSolUsdcPool),
|
|
121
56
|
});
|
|
122
57
|
```
|
|
123
58
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
| `url` | no | the cluster's public endpoint. `http://127.0.0.1:8899` for `localnet` |
|
|
128
|
-
| `wsUrl` | no | `url` with `https` → `wss`. The cluster's default WebSocket endpoint when `url` is also left out |
|
|
129
|
-
| `addressLookupTables` | no | the shared lookup table on `devnet`; none on other clusters. Pass `{}` to turn compression off |
|
|
130
|
-
|
|
131
|
-
The client is a plain object with `cluster`, `url`, `wsUrl`, `rpc`, `rpcSubscriptions`, and
|
|
132
|
-
`addressLookupTables`. If you need a custom transport, spread it and replace `rpc`:
|
|
133
|
-
|
|
134
|
-
```ts
|
|
135
|
-
const gabox = { ...createClient({ cluster: 'devnet' }), rpc: myRpc };
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### The URL is checked against the cluster
|
|
59
|
+
`payWith: 'quote'` on `buyPack` and `createMachine` skips the swap and spends the token the wallet
|
|
60
|
+
already holds. `receive: 'quote'` does the same for a sale. A WSOL pool ignores both: its quote
|
|
61
|
+
token is SOL.
|
|
139
62
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
63
|
+
The swap has to fit in the same 1,232-byte transaction as the buy. When it does not, the builder
|
|
64
|
+
fails with a clear error rather than splitting the work; supply more address lookup tables, or pay
|
|
65
|
+
in the quote token. It also runs on the same compute budget, so a builder adds `route.computeUnits`
|
|
66
|
+
to its own limit and caps the total at the 1,400,000-unit ceiling. Jupiter states that number with
|
|
67
|
+
the route it returns; the CPMM provider uses a measured one, because it is always a single pool.
|
|
68
|
+
Pass `computeUnitLimit` to override it.
|
|
143
69
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
70
|
+
**Closing a WSOL account unwraps everything.** A wallet that already held WSOL in that account gets
|
|
71
|
+
it back as SOL too. Nothing is lost, but the balance moves. Build your own instructions if you keep
|
|
72
|
+
a WSOL position on purpose.
|
|
147
73
|
|
|
148
|
-
|
|
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
|
|
74
|
+
## Create a machine
|
|
163
75
|
|
|
164
76
|
```ts
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
symbol: 'CAT',
|
|
176
|
-
uri: 'https://…/metadata.json',
|
|
177
|
-
feeBps: 100, // the creator's fee per pack, 0–100 bps (max 1%)
|
|
178
|
-
tiers: DEFAULT_TIERS, // optional; the default is a 20× top prize
|
|
179
|
-
maxSeedLamports: (seed.lamports * 105n) / 100n,
|
|
77
|
+
const client = createClient({ cluster: 'devnet' });
|
|
78
|
+
const estimate = await seedCostEstimate(client);
|
|
79
|
+
const message = await createMachine(client, {
|
|
80
|
+
creator,
|
|
81
|
+
mintKeypair,
|
|
82
|
+
name: 'Gabox',
|
|
83
|
+
symbol: 'GBX',
|
|
84
|
+
uri: 'https://example.com/metadata.json',
|
|
85
|
+
maxSeedQuoteIn: (estimate.quoteAmount * 110n) / 100n,
|
|
86
|
+
maxSeedNativeDebit: 100_000_000n,
|
|
180
87
|
});
|
|
181
88
|
```
|
|
182
89
|
|
|
183
|
-
One transaction, two signers: the
|
|
184
|
-
|
|
90
|
+
One transaction, two signers: the mint keypair and the creator. `initialize_pool` refuses to run
|
|
91
|
+
unless the same transaction also carries a LaunchLab `initialize_v2` for the same mint with the
|
|
92
|
+
pinned launch arguments, so the two cannot be separated.
|
|
185
93
|
|
|
186
|
-
The
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
94
|
+
The creator picks the name, the symbol, the metadata URI, the prize table and the quote asset.
|
|
95
|
+
Everything else is fixed: 6 decimals, 1,000,000,000 coins, 793,100,000 of them sold on the curve,
|
|
96
|
+
graduate into a CPMM pool, no vesting, the CPMM creator fee paid in the quote token. Metaplex limits
|
|
97
|
+
the three strings to 32, 10 and 200 UTF-8 bytes.
|
|
190
98
|
|
|
191
|
-
`
|
|
192
|
-
creator
|
|
193
|
-
|
|
194
|
-
cannot exceed one pack, each live tier must pay at least one token, and the largest prize must be at
|
|
195
|
-
least one pack. `seedCostEstimate(gabox, tiers)` previews the exact custom table before creating.
|
|
99
|
+
`maxSeedQuoteIn` is both the slippage cap on the seed buy and the amount of the quote token put in
|
|
100
|
+
the creator's quote account before it. `maxSeedNativeDebit` is separate and small: it caps the
|
|
101
|
+
lamports of rent LaunchLab charges for the fee vaults it creates on a coin's first trade.
|
|
196
102
|
|
|
197
|
-
###
|
|
103
|
+
### Another quote asset
|
|
198
104
|
|
|
199
105
|
```ts
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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, {
|
|
233
|
-
mint,
|
|
234
|
-
purchaser, // TransactionSigner. The only signer.
|
|
235
|
-
maxQuoteIn,
|
|
236
|
-
minMaximum: offer.maximum,
|
|
237
|
-
maxTotalDebit: maxQuoteIn + share(maxQuoteIn, 200n) + 20_000_000n,
|
|
238
|
-
seq: pool.nextSeq, // optional, see below
|
|
239
|
-
referrer, // optional, see Referrals
|
|
106
|
+
const estimate = await seedCostEstimate(client, undefined, { quote: { mint: usdc }, raise });
|
|
107
|
+
const message = await createMachine(client, {
|
|
108
|
+
creator,
|
|
109
|
+
mintKeypair,
|
|
110
|
+
name: 'Gabox',
|
|
111
|
+
symbol: 'GBX',
|
|
112
|
+
uri: 'https://example.com/metadata.json',
|
|
113
|
+
quote: { mint: usdc },
|
|
114
|
+
raise, // total_quote_fund_raising, in USDC base units
|
|
115
|
+
payWith: 'sol', // the default: the seed is bought with a swap
|
|
116
|
+
maxSeedQuoteIn: (estimate.quoteAmount * 110n) / 100n,
|
|
117
|
+
maxSeedNativeDebit: 100_000_000n,
|
|
240
118
|
});
|
|
241
119
|
```
|
|
242
120
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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. |
|
|
121
|
+
`raise` is how much the curve must take in before the coin graduates, in the quote's own base units.
|
|
122
|
+
A WSOL pool has it pinned by the program — 85 SOL on mainnet, 3 SOL on devnet — so leave it out
|
|
123
|
+
there. Any other quote has no default, because the same number means a different amount in every
|
|
124
|
+
token. LaunchLab refuses a raise below `min_quote_fund_raising` in that quote's config, and
|
|
125
|
+
`createMachine` checks the same thing before it builds anything.
|
|
250
126
|
|
|
251
|
-
`
|
|
252
|
-
|
|
127
|
+
`seedCostEstimate` reports `quoteAmount` in the quote token, `quoteDecimals`, `quoteSymbol`, the
|
|
128
|
+
`raise` it would use, and `solAmount`: the same cost in lamports through the route provider, or
|
|
129
|
+
`null` when nothing can price it.
|
|
253
130
|
|
|
254
|
-
|
|
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.
|
|
131
|
+
### The seed
|
|
258
132
|
|
|
259
|
-
|
|
260
|
-
|
|
133
|
+
Pool creation buys a mandatory seed: enough tokens to make a 3x top prize payable on the first pack,
|
|
134
|
+
or the full top prize when the table's top tier is below 3x. `math.seedTokens` computes it. A creator
|
|
135
|
+
can add more with `extraSeedTokens` (default `0n`), which the program adds to the same seed trade.
|
|
136
|
+
`seedCostEstimate` reports the mandatory `seedTokens`, the `extraSeedTokens` passed in, their
|
|
137
|
+
`totalSeedTokens`, and the exact cost of buying the total on a fresh curve. A table's top tier can be
|
|
138
|
+
at most 20x; seed beyond what a 20x prize needs stays in the vault as backup for the draws after a
|
|
139
|
+
top-tier hit.
|
|
261
140
|
|
|
262
|
-
|
|
141
|
+
## Buy a pack
|
|
263
142
|
|
|
264
143
|
```ts
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
144
|
+
const offer = await getOffer(client, mint, { user: purchaser.address });
|
|
145
|
+
const message = await buyPack(client, {
|
|
146
|
+
mint,
|
|
147
|
+
purchaser,
|
|
148
|
+
maxQuoteIn: (offer.quoteAmount * 102n) / 100n,
|
|
149
|
+
minMaximum: (offer.maximum * 98n) / 100n,
|
|
150
|
+
maxNativeDebit: 100_000_000n,
|
|
270
151
|
});
|
|
271
|
-
// resolved.amount: tokens won, already in the buyer's wallet
|
|
272
152
|
```
|
|
273
153
|
|
|
274
|
-
`
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
154
|
+
`offer.quoteAmount` is the exact price the venue will charge for one pack right now, fees included,
|
|
155
|
+
in the pool's quote token. The curve math is a port of Raydium's own, not an estimate, so the
|
|
156
|
+
`PackBought` event reports the same number unless somebody trades in between. `offer.solAmount` is
|
|
157
|
+
the same price in lamports through the route provider, with `offer.quoteDecimals` and
|
|
158
|
+
`offer.quoteSymbol` for showing it.
|
|
279
159
|
|
|
280
|
-
|
|
160
|
+
`maxQuoteIn` is the slippage cap, in the quote token, and the amount put in the buyer's quote
|
|
161
|
+
account before the buy. `maxNativeDebit` is separate: it caps the lamports the handler watches,
|
|
162
|
+
which are the VRF request and any venue account rent. Gabox adds nothing to either.
|
|
281
163
|
|
|
282
|
-
|
|
164
|
+
## Sell
|
|
283
165
|
|
|
284
166
|
```ts
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const grossOutput = await pump.sellQuote(gabox, mint, resolved.amount, { user: purchaser.address });
|
|
288
|
-
const message = await sellTokens(gabox, {
|
|
167
|
+
const venue = await resolveVenue(client, { mint, user: seller.address });
|
|
168
|
+
const message = await sellTokens(client, {
|
|
289
169
|
mint,
|
|
290
|
-
seller
|
|
291
|
-
amount
|
|
292
|
-
minQuoteOutput: (
|
|
170
|
+
seller,
|
|
171
|
+
amount,
|
|
172
|
+
minQuoteOutput: (venue.quoteSell(amount) * 98n) / 100n,
|
|
173
|
+
maxNativeDebit: 100_000_000n,
|
|
293
174
|
});
|
|
294
175
|
```
|
|
295
176
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
177
|
+
The seller keeps the whole venue proceeds. `minQuoteOutput` is the venue's own floor, in the quote
|
|
178
|
+
token. On a pool that is not quoted in SOL, `receive: 'sol'` (the default) swaps that floor into SOL
|
|
179
|
+
in the same transaction; anything the venue paid above the floor stays in the quote account.
|
|
299
180
|
|
|
300
|
-
|
|
181
|
+
## Which venue
|
|
301
182
|
|
|
302
|
-
|
|
183
|
+
`resolveVenue(client, { mint, user })` reads the LaunchLab pool's `status` and follows it:
|
|
303
184
|
|
|
304
|
-
|
|
305
|
-
|
|
185
|
+
- `0`: the curve is still selling, so the trade routes to LaunchLab.
|
|
186
|
+
- `1`: the raise is finished and Raydium is migrating the coin. Nothing trades. This throws, and the
|
|
187
|
+
message says to retry. On devnet the move usually finishes within a minute.
|
|
188
|
+
- `2`: the coin graduated, so the trade routes to its CPMM pool.
|
|
306
189
|
|
|
307
|
-
|
|
308
|
-
|
|
190
|
+
A migrated CPMM pool is usually at `["pool", cpswap_config, token_0, token_1]`, but not always:
|
|
191
|
+
Raydium picks a fresh address when that one is taken. So the pool has to prove itself from its own
|
|
192
|
+
data — CPMM owns it, it carries the `PoolState` discriminator, its `pool_creator` is the coin
|
|
193
|
+
creator, its two mints are the sorted pair, and `enable_creator_fee` is true. That last flag is the
|
|
194
|
+
one that cannot be forged: plain CPMM `initialize` always leaves it false. The program checks the
|
|
195
|
+
same five things before it forwards a trade, and reads the fee tier, both vaults, both token
|
|
196
|
+
programs and the oracle out of the pool account rather than deriving them.
|
|
309
197
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
await fundPrizesWithBuy(gabox, { mint, funder, tokens: seedShortfall(offer), maxQuoteIn });
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
Donations cannot be withdrawn.
|
|
316
|
-
|
|
317
|
-
### Referrals
|
|
318
|
-
|
|
319
|
-
A wallet can bind itself to a referrer, once and permanently. After that, every pack it buys pays
|
|
320
|
-
the referrer 1% of the creator's fee on that pack. The buyer pays nothing extra.
|
|
321
|
-
|
|
322
|
-
```ts
|
|
323
|
-
import { bindReferrer, claimReferral, fetchReferralReward } from '@gabox-labs/sdk';
|
|
198
|
+
`resolveVenue` needs the pool's quote asset. It reads the Gabox pool for it, or takes a
|
|
199
|
+
`quote: { mint, config, tokenProgram }` when the caller already has one.
|
|
324
200
|
|
|
325
|
-
|
|
326
|
-
await bindReferrer(gabox, referee, referrerAddress);
|
|
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);
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
### Stuck draws
|
|
337
|
-
|
|
338
|
-
Randomness can fail to arrive. Two permissionless transactions keep a draw moving. Anyone can send
|
|
339
|
-
them.
|
|
201
|
+
## Creator fees
|
|
340
202
|
|
|
341
203
|
```ts
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const state = await drawAvailability(gabox, draw);
|
|
345
|
-
// { canRetry, canExpire, slotsUntilRetry, slotsUntilExpiry, attempts, status }
|
|
204
|
+
const owed = await raydium.fetchCreatorFees(client, { creator: creator.address, mint });
|
|
205
|
+
// owed.quoteMint, owed.curveQuote, owed.cpmmQuote, owed.cpmmTokens
|
|
346
206
|
|
|
347
|
-
|
|
348
|
-
|
|
207
|
+
await raydium.claimCreatorFee(client, { creator }); // every SOL coin on the curve, at once
|
|
208
|
+
await raydium.collectCreatorFee(client, { mint, creator }); // one graduated coin
|
|
349
209
|
```
|
|
350
210
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
path must pay it. Tell buyers this before they pay.
|
|
211
|
+
LaunchLab keeps one creator fee vault per wallet **per quote asset**, so a single claim sweeps every
|
|
212
|
+
coin that wallet launched against that quote. A creator with a SOL machine and a USDC machine claims
|
|
213
|
+
twice: `claimCreatorFee(client, { creator, quoteMint })`, and `fetchCreatorFees` takes the same
|
|
214
|
+
argument. A CPMM pool keeps its creator fee inside the pool account, so that one is per coin and
|
|
215
|
+
reads the quote off the Gabox pool itself.
|
|
357
216
|
|
|
358
|
-
|
|
217
|
+
Both pay into the creator's account for the quote mint. When that is WSOL the builders close it, so
|
|
218
|
+
the creator receives SOL; any other quote arrives as that token.
|
|
359
219
|
|
|
360
|
-
|
|
220
|
+
## Wallet activity
|
|
361
221
|
|
|
362
|
-
|
|
222
|
+
`buyPack` keeps a `WalletActivity` account per buyer, at the PDA `findActivityPda({ purchaser })`
|
|
223
|
+
(also `activityAddress(wallet)`). It tracks `packsBought` and `nativeSpent` across every pool.
|
|
224
|
+
`nativeSpent` is what the venue charged in WSOL, which is SOL; Gabox's own rent, the VRF fee and a
|
|
225
|
+
pack bought in any other quote token are not counted. The buyer pays its rent once, on the first purchase, and `buyPack` resolves the account
|
|
226
|
+
itself. Read it with `fetchWalletActivity(client, wallet)`, which returns `null` before a wallet's
|
|
227
|
+
first purchase.
|
|
363
228
|
|
|
364
|
-
|
|
365
|
-
| ----------------------------------------- | ------------------------------------------------------------- |
|
|
366
|
-
| `fetchPoolByMint(gabox, mint)` | the machine's `Pool`, or `null` |
|
|
367
|
-
| `fetchPoolAt(gabox, poolAddress)` | the same, by pool address |
|
|
368
|
-
| `fetchPoolInventory(gabox, mint)` | the pool plus live `inventory`, `reserved`, `free` |
|
|
369
|
-
| `fetchDraw(gabox, drawAddress)` | a `Draw`, or `null` once it is delivered and closed |
|
|
370
|
-
| `listPools(gabox)` | every machine |
|
|
371
|
-
| `listDraws(gabox, { pool?, purchaser? })` | open draws, filtered by machine, by buyer, or both |
|
|
372
|
-
| `listDrawsByPurchaser(gabox, wallet)` | "what am I still waiting on" |
|
|
373
|
-
| `listReferralLinksByReferrer(gabox, ref)` | every wallet bound to a referrer |
|
|
374
|
-
| `fetchEvents(gabox, signature)` | the SDK events one transaction emitted |
|
|
229
|
+
## Draws
|
|
375
230
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
Addresses are derived, not looked up: `poolAddress(mint)`, `drawAddress(pool, seq)`,
|
|
380
|
-
`vaultAddress(mint)`, `referralLinkAddress(wallet)`, `referralAddress(pool, referrer)`, and
|
|
381
|
-
`associatedTokenAddress(owner, mint)`.
|
|
382
|
-
|
|
383
|
-
## Events
|
|
384
|
-
|
|
385
|
-
Every transaction emits typed events. Decode them from a confirmed signature:
|
|
386
|
-
|
|
387
|
-
```ts
|
|
388
|
-
import { fetchEvents } from '@gabox-labs/sdk';
|
|
389
|
-
|
|
390
|
-
for (const event of await fetchEvents(gabox, signature)) {
|
|
391
|
-
if (event.name === 'PackBought') console.log(event.data.venueDebit, event.data.prizes);
|
|
392
|
-
if (event.name === 'DrawResolved') console.log(event.data.amount, event.data.timedOut);
|
|
393
|
-
}
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
Event names: `PoolCreated`, `PackBought`, `DrawResolved`, `TokensSold`, `PrizesFunded`,
|
|
397
|
-
`RandomnessRetried`, `PrizeRedeemed`. `decodeEvents(logs)` does the same from log lines you already
|
|
398
|
-
have.
|
|
231
|
+
Gabox delivers awards and closes draws atomically. Use `fetchEvents`, `decodeEvents` and
|
|
232
|
+
`findResolvedDraw` for final state. There is no Ready, claim or sell-prize flow. Existing base tokens
|
|
233
|
+
can be donated irrevocably with `fundPrizes`; a stalled draw uses `retryDraw` or `expireDraw`.
|
|
399
234
|
|
|
400
235
|
## Errors
|
|
401
236
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
```ts
|
|
405
|
-
import { generated } from '@gabox-labs/sdk';
|
|
406
|
-
|
|
407
|
-
try {
|
|
408
|
-
await send(transaction, { commitment: 'confirmed' });
|
|
409
|
-
} catch (error) {
|
|
410
|
-
// `message` is the GaboxTransactionMessage you built. It tells the check which instruction is ours.
|
|
411
|
-
if (generated.isGaboxV2Error(error, message, generated.GABOX_V2_ERROR__SLIPPAGE_EXCEEDED)) {
|
|
412
|
-
// ask the user to widen maxQuoteIn and rebuild
|
|
413
|
-
} else if (generated.isGaboxV2Error(error, message)) {
|
|
414
|
-
console.log(generated.getGaboxV2ErrorMessage(error.context.code));
|
|
415
|
-
} else {
|
|
416
|
-
throw error;
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
`getGaboxV2ErrorMessage` returns a readable message in development builds and a placeholder when
|
|
422
|
-
`NODE_ENV` is `production`, to keep bundles small.
|
|
423
|
-
|
|
424
|
-
The ones a UI will meet:
|
|
425
|
-
|
|
426
|
-
| error | when |
|
|
427
|
-
| -------------------- | -------------------------------------------------------------------------- |
|
|
428
|
-
| `SlippageExceeded` | the venue price moved past `maxQuoteIn`, or the sale returned less than `minQuoteOutput` |
|
|
429
|
-
| `PrizeCapChanged` | the top prize fell below `minMaximum` between quote and send |
|
|
430
|
-
| `RetryTooSoon` | `retryDraw` before 300 slots passed |
|
|
431
|
-
| `RetryUnavailable` | `retryDraw` after 3 attempts, or on a draw that is no longer pending |
|
|
432
|
-
| `NotExpired` | `expireDraw` before the deadline |
|
|
433
|
-
| `NotPending` | `expireDraw` on a draw whose randomness has already resolved |
|
|
434
|
-
| `InvalidReferral` | a self-referral, or a link that does not match |
|
|
435
|
-
| `ZeroAmount` | a zero `amount` or a zero `minQuoteOutput` |
|
|
436
|
-
|
|
437
|
-
The SDK also throws plain `Error`s before building, for example when a mint has no machine, when
|
|
438
|
-
`maxQuoteIn` is not positive, or when a message would exceed Solana's 1,232-byte limit.
|
|
439
|
-
|
|
440
|
-
---
|
|
441
|
-
|
|
442
|
-
## Units and conventions
|
|
443
|
-
|
|
444
|
-
- **Tokens** are in base units. Every Pump coin has 6 decimals, so `1_000_000n` is one whole token
|
|
445
|
-
and a pack (`PACK_TOKENS`) is `1_000_000n * 1_000_000n`.
|
|
446
|
-
- **SOL** is in lamports. WSOL is used on the PumpSwap route, and the SDK handles the wrapping.
|
|
447
|
-
- **Every amount is a `bigint`.** Basis points are `number`. `share(amount, bps)` computes a share.
|
|
448
|
-
- **Addresses** are kit `Address` strings. The SDK never exposes `PublicKey` or `BN`.
|
|
449
|
-
- **Async by default.** Address derivation is async, because kit's PDA derivation is.
|
|
450
|
-
|
|
451
|
-
## Constants
|
|
452
|
-
|
|
453
|
-
| constant | value | meaning |
|
|
454
|
-
| ----------------------- | ---------------------------------- | --------------------------------------------------------- |
|
|
455
|
-
| `PACK_TOKENS` | `1_000_000n * 1_000_000n` | tokens in one pack. Prefer `pool.packTokens` when you have a pool |
|
|
456
|
-
| `PROTOCOL_FEE_BPS` | `100n` | the protocol's 1% on every purchase and every sale |
|
|
457
|
-
| `MAX_FEE_BPS` | `100` | the largest creator fee: 1% of the venue price |
|
|
458
|
-
| `REFERRAL_FEE_BPS` | `100n` | the referrer's 1% of the creator fee |
|
|
459
|
-
| `RETRY_SLOTS` | `300n` | slots between randomness attempts |
|
|
460
|
-
| `MAX_ATTEMPTS` | `3` | randomness attempts per draw, counting the first |
|
|
461
|
-
| `TIMEOUT_SLOTS` | `216_000n` | slots until a draw can be expired |
|
|
462
|
-
| `TIERS`, `TICKETS` | `8`, `65_536` | rows in a prize table, and tickets per table |
|
|
463
|
-
| `GABOX_PROGRAM_ID` | `GaBoxR9nYcK1zeu8EvSJVHV3SrYpCFmvbh2MLgobMcUA` | the program |
|
|
464
|
-
|
|
465
|
-
## Entry points
|
|
466
|
-
|
|
467
|
-
| import | what |
|
|
468
|
-
| ------------------------- | ---------------------------------------------------------------------------------------- |
|
|
469
|
-
| `@gabox-labs/sdk` | everything above: the client, builders, readers, math, events, constants |
|
|
470
|
-
| `@gabox-labs/sdk/generated` | the low-level generated client: instruction builders, account and event codecs, error codes. Also available as the `generated` namespace |
|
|
471
|
-
| `@gabox-labs/sdk/pump` | the venue layer: `resolveVenue`, `curveQuote`, `sellQuote`, and the Pump/PumpSwap account lists. Also available as the `pump` namespace |
|
|
472
|
-
|
|
473
|
-
The `generated` functions take a kit `Rpc` (`gabox.rpc`), not the client.
|
|
474
|
-
|
|
475
|
-
---
|
|
476
|
-
|
|
477
|
-
## For AI agents
|
|
478
|
-
|
|
479
|
-
This repository is agent-ready.
|
|
480
|
-
|
|
481
|
-
- **[`skills/gabox-sdk/SKILL.md`](skills/gabox-sdk/SKILL.md)** teaches an agent how to integrate the
|
|
482
|
-
SDK: setup, the flows, the limits a buyer signs, and the mistakes to avoid. It follows the
|
|
483
|
-
[Agent Skills](https://agentskills.io) format, so it installs into Claude Code, Cursor, Codex,
|
|
484
|
-
and others:
|
|
485
|
-
|
|
486
|
-
```sh
|
|
487
|
-
npx skills add gabox-labs/gabox-sdk
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
- **[`skills/gabox-sdk/references/api.md`](skills/gabox-sdk/references/api.md)** is a compact
|
|
491
|
-
reference of every exported function and type.
|
|
492
|
-
- **[`llms.txt`](llms.txt)** points a model at the right files.
|
|
493
|
-
- **[`AGENTS.md`](AGENTS.md)** is for agents working on this repository itself.
|
|
494
|
-
|
|
495
|
-
## Status
|
|
496
|
-
|
|
497
|
-
- **Devnet only.** Mainnet is not live.
|
|
498
|
-
- The devnet program revision this SDK targets is live and verified at slot `497869792`; see the
|
|
499
|
-
[0.2.0 changelog](CHANGELOG.md).
|
|
500
|
-
Machines from the previous account layout remain incompatible: `fetchPoolByMint` excludes them,
|
|
501
|
-
and direct reads report an "older devnet account layout" migration requirement.
|
|
502
|
-
- The Pump bonding-curve route has an end-to-end test on devnet (`GABOX_DEVNET_E2E=1`). The
|
|
503
|
-
PumpSwap route (coins that graduated off the curve) has unit coverage only.
|
|
504
|
-
- The API is `0.x`. Breaking changes bump the minor version and are listed in the changelog.
|
|
505
|
-
|
|
506
|
-
## Contributing
|
|
507
|
-
|
|
508
|
-
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the development setup and the checks that run before
|
|
509
|
-
a release.
|
|
237
|
+
The generated client decodes the program's own errors by name. The ones a client meets most:
|
|
510
238
|
|
|
511
|
-
|
|
239
|
+
| Error | What to do |
|
|
240
|
+
| --- | --- |
|
|
241
|
+
| `InvalidVenue` | The account list did not match. Resolve the venue again and rebuild. |
|
|
242
|
+
| `SlippageExceeded` | The price moved past `maxQuoteIn`, or a cost went past `maxNativeDebit`. |
|
|
243
|
+
| `PrizeCapChanged` | The top prize fell below `minMaximum`. Refresh the offer. |
|
|
244
|
+
| `IncorrectTokenDelta` | The venue did not deliver exactly one pack. Usually a curve with less than a pack left; wait for graduation. |
|
|
245
|
+
| `InvalidLaunch` | The LaunchLab create instruction was missing or did not match the pinned shape. |
|
|
246
|
+
| `InvalidQuote` | The quote mint is not one Raydium enabled, or its Token-2022 profile is one the program refuses. |
|
|
512
247
|
|
|
513
|
-
[
|
|
248
|
+
See [the API reference](skills/gabox-sdk/references/api.md).
|