@gabox-labs/sdk 0.6.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 CHANGED
@@ -3,6 +3,90 @@
3
3
  All notable changes to `@gabox-labs/sdk`. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
4
4
  and the project uses [Semantic Versioning](https://semver.org/) with the `0.x` rule from `CONTRIBUTING.md`.
5
5
 
6
+ ## [0.7.0] - 2026-09-18
7
+
8
+ Any quote token Raydium enabled, a price shown in SOL, and payment in SOL through a swap that runs
9
+ in the same transaction as `buy_pack`. It matches the devnet program deployed at slot `500297753`,
10
+ and a live devnet run exercised both a SOL-quoted coin and a USDC-quoted one paid for in SOL.
11
+
12
+ ### Changed
13
+
14
+ - **Breaking.** A machine is priced in one quote asset, chosen at creation. It still defaults to
15
+ wrapped SOL, and any quote Raydium enabled on LaunchLab now works too. `createMachine` takes
16
+ `quote: { mint }` and `raise`; `initialize_pool` takes the quote's LaunchLab `GlobalConfig`
17
+ account, which is what proves the quote, and the quote's own token program.
18
+ - **Breaking.** `Pool` gained `quoteConfig` and `quoteTokenProgram`, and a new discriminator. A pool
19
+ from the first LaunchLab build now fails to decode instead of being read with shifted fields.
20
+ - **Breaking.** `raise` is the client's choice for every quote but wrapped SOL, where the program
21
+ still pins it: 85 SOL on mainnet, 3 SOL on devnet. A non-SOL pool has no default, because the same
22
+ number means a different amount in every token. `createMachine` refuses a raise below
23
+ `min_quote_fund_raising` in the quote's own config, before it builds anything.
24
+ - **Breaking.** `RaydiumClusterIds` lost `solGlobalConfig`. Nothing pins a quote config any more:
25
+ derive it from the quote mint with `raydium.launchlabGlobalConfig`, or read it with
26
+ `raydium.fetchQuoteConfig`.
27
+ - **Breaking.** `fetchCurveSettings(client, quoteConfig, ids?)` takes the quote's config address.
28
+ `newCurveBuyCost(client, tokens, { quoteConfig, raise })` and `newCurveReserves(raise, migrateFee)`
29
+ take the raise, because the starting reserves follow it.
30
+ - **Breaking.** `fetchCreatorFees` takes `quoteMint` and answers
31
+ `{ quoteMint, curveQuote, cpmmQuote, cpmmTokens }`. `curveLamports` and `cpmmLamports` are gone:
32
+ the amounts are in the quote token, which is not always SOL. `claimCreatorFee` takes `quoteMint`
33
+ too, because LaunchLab keeps one vault per wallet per quote asset.
34
+ - **Breaking.** `getLaunchInstruction` takes `quoteMint`, `quoteConfig`, `quoteTokenProgram` and
35
+ `raise`. `LaunchlabTradeAccountsInput` takes `quoteTokenProgram`, and `CpmmTradeAccountsInput`
36
+ takes `baseTokenProgram` and `quoteTokenProgram`; a migrated CPMM pool records both in its own
37
+ data, and the program checks them.
38
+ - `GaboxClient` gained `route`, and `createClient` gained a `route` option. Mainnet defaults to
39
+ `jupiterRoute()`; devnet and localnet default to `null`.
40
+ - `PackOffer` gained `quoteDecimals`, `quoteSymbol` and `solAmount`. `quoteAmount` is still the whole
41
+ pack price, now in the pool's quote token. `SeedCostEstimate` gained the same three plus `raise`.
42
+ - `resolveVenue` takes an optional `quote` binding and reads the Gabox pool for it otherwise. It also
43
+ reports `quoteTokenProgram` and `userQuoteToken`.
44
+
45
+ ### Added
46
+
47
+ - `payWith: 'sol' | 'quote'` on `buyPack` and `createMachine`, and `receive: 'sol' | 'quote'` on
48
+ `sellTokens`. Both default to `'sol'`. On a pool that is not quoted in SOL, the default prepends a
49
+ swap before `buy_pack` and appends one after `sell_tokens`, in the same transaction. The SDK never
50
+ splits the two: a message over the 1,232-byte limit fails with a clear error instead.
51
+ - `src/route/`: `Route`, `RouteProvider`, `jupiterRoute(options)` for mainnet and
52
+ `raydiumCpmmRoute(poolAddress)` for devnet, plus `routeQuoteIn`, `routeQuoteOut`, `solPriceOf` and
53
+ `assertRouteIsSafe`. Neither provider adds a package: Jupiter is plain HTTP and JSON, and the CPMM
54
+ provider reuses this SDK's own swap builders and price math.
55
+ - Exact-out first, exact-in as the fallback. Jupiter answers `NO_ROUTES_FOUND` for exact-out whenever
56
+ the best route has more than one hop, which is the normal case for a stock token. The fallback
57
+ works out the SOL that buys the amount at the exact-in price, adds a margin, and leaves the change
58
+ in the buyer's own quote account. A `Route` reports which mode it used.
59
+ - `raydium.fetchQuoteConfig`, `raydium.isQuoteSupported`, `raydium.fetchQuoteAsset` and
60
+ `raydium.fetchQuoteDisplay`: whether Raydium enabled a quote, and its token program, decimals and
61
+ symbol. The symbol comes from the Token-2022 metadata extension when the mint has one, and from
62
+ Metaplex otherwise.
63
+ - `raydium.quoteAccountFor(user, quoteMint, quoteTokenProgram)`: the account both venues settle in,
64
+ derived under the quote's own token program. A Token-2022 quote has a different ATA from a classic
65
+ one, and the program pins the one the pool records.
66
+ - `TOKEN_2022_PROGRAM_ADDRESS`, generated from Raydium's own IDL.
67
+ - `fetchAddressLookupTables(client, addresses)`: a route names its tables by address, and the message
68
+ has to carry them.
69
+ - `Route.computeUnits`. A swap runs on the same compute budget as the Gabox instruction, so a
70
+ builder with a swap leg adds the route's own figure to its limit: Jupiter's `SetComputeUnitLimit`
71
+ from its `swap-instructions` response (400,000 when absent), or the measured 75,000 of the
72
+ Raydium CPMM route. The sum is capped at the 1,400,000 ceiling; a caller's `computeUnitLimit`
73
+ still wins.
74
+ - Cluster-neutral `initializePool`. The program pins `venue` to LaunchLab's address, which differs
75
+ between the mainnet and devnet builds, so the generated builder no longer carries a default for
76
+ it and `createMachine` passes the cluster's address. `check:program` treats the two IDLs as in
77
+ sync.
78
+
79
+ ### Security
80
+
81
+ - A route is built outside this SDK and runs with the buyer's signature, so every leg is checked
82
+ before it is composed: no instruction may name the Gabox program or any Gabox account the
83
+ transaction uses, and the swap has to settle in the user's own quote associated token account,
84
+ which is the account the program binds and measures the delta in.
85
+ - A route's instructions carry account roles and no signer objects. Kit refuses to sign a message
86
+ that holds two distinct signer objects for one address, and the wallet paying for the transaction
87
+ is the same wallet a route names, so a signer object there would make every such message
88
+ unsignable. Both providers and both new test suites check it.
89
+
6
90
  ## [0.6.0] - 2026-09-18
7
91
 
8
92
  The venue moved from Pump and PumpSwap to Raydium LaunchLab and Raydium CPMM. The program changed
package/README.md CHANGED
@@ -1,8 +1,8 @@
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
+ 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.
6
6
 
7
7
  Devnet today. Mainnet addresses are pinned and tested, but the program is not deployed there yet.
8
8
 
@@ -21,16 +21,55 @@ this SDK shows is the venue's own price with the venue's own fees already inside
21
21
  Those shares come out of Raydium's revenue, not out of an extra charge Gabox adds. The creator
22
22
  collects theirs with `raydium.claimCreatorFee` and `raydium.collectCreatorFee`.
23
23
 
24
- ## WSOL, not SOL
24
+ ## The quote asset
25
25
 
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.
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.
30
29
 
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.
30
+ ```ts
31
+ const config = await raydium.fetchQuoteConfig(client, someMint);
32
+ // null when Raydium enabled no such quote. `raydium.isQuoteSupported` is the boolean version.
33
+ ```
34
+
35
+ The quote mint may be classic SPL Token or Token-2022. The coin is always classic SPL Token.
36
+
37
+ ## Paying in SOL
38
+
39
+ Buyers pay in SOL whatever the pool is priced in.
40
+
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.
48
+
49
+ ```ts
50
+ import { createClient, raydiumCpmmRoute } from '@gabox-labs/sdk';
51
+
52
+ // Mainnet gets Jupiter by default. Devnet has no router, so name a CPMM pool for the SOL pair.
53
+ const client = createClient({
54
+ cluster: 'devnet',
55
+ route: raydiumCpmmRoute(devnetSolUsdcPool),
56
+ });
57
+ ```
58
+
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.
62
+
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.
69
+
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.
34
73
 
35
74
  ## Create a machine
36
75
 
@@ -52,14 +91,42 @@ One transaction, two signers: the mint keypair and the creator. `initialize_pool
52
91
  unless the same transaction also carries a LaunchLab `initialize_v2` for the same mint with the
53
92
  pinned launch arguments, so the two cannot be separated.
54
93
 
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.
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.
59
98
 
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.
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.
102
+
103
+ ### Another quote asset
104
+
105
+ ```ts
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,
118
+ });
119
+ ```
120
+
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.
126
+
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.
63
130
 
64
131
  ### The seed
65
132
 
@@ -84,13 +151,15 @@ const message = await buyPack(client, {
84
151
  });
85
152
  ```
86
153
 
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.
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.
90
159
 
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.
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.
94
163
 
95
164
  ## Sell
96
165
 
@@ -105,7 +174,9 @@ const message = await sellTokens(client, {
105
174
  });
106
175
  ```
107
176
 
108
- The seller keeps the whole venue proceeds. `minQuoteOutput` is the venue's own floor.
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.
109
180
 
110
181
  ## Which venue
111
182
 
@@ -121,30 +192,37 @@ Raydium picks a fresh address when that one is taken. So the pool has to prove i
121
192
  data — CPMM owns it, it carries the `PoolState` discriminator, its `pool_creator` is the coin
122
193
  creator, its two mints are the sorted pair, and `enable_creator_fee` is true. That last flag is the
123
194
  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.
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.
197
+
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.
126
200
 
127
201
  ## Creator fees
128
202
 
129
203
  ```ts
130
204
  const owed = await raydium.fetchCreatorFees(client, { creator: creator.address, mint });
131
- // owed.curveLamports, owed.cpmmLamports, owed.cpmmTokens
205
+ // owed.quoteMint, owed.curveQuote, owed.cpmmQuote, owed.cpmmTokens
132
206
 
133
- await raydium.claimCreatorFee(client, { creator }); // every coin on the curve, at once
207
+ await raydium.claimCreatorFee(client, { creator }); // every SOL coin on the curve, at once
134
208
  await raydium.collectCreatorFee(client, { mint, creator }); // one graduated coin
135
209
  ```
136
210
 
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.
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.
216
+
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.
141
219
 
142
220
  ## Wallet activity
143
221
 
144
222
  `buyPack` keeps a `WalletActivity` account per buyer, at the PDA `findActivityPda({ purchaser })`
145
223
  (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
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
148
226
  itself. Read it with `fetchWalletActivity(client, wallet)`, which returns `null` before a wallet's
149
227
  first purchase.
150
228
 
@@ -165,5 +243,6 @@ The generated client decodes the program's own errors by name. The ones a client
165
243
  | `PrizeCapChanged` | The top prize fell below `minMaximum`. Refresh the offer. |
166
244
  | `IncorrectTokenDelta` | The venue did not deliver exactly one pack. Usually a curve with less than a pack left; wait for graduation. |
167
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. |
168
247
 
169
248
  See [the API reference](skills/gabox-sdk/references/api.md).