@gabox-labs/sdk 0.6.0 → 0.7.1

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,110 @@
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.1] - 2026-09-18
7
+
8
+ A product correction. Paying in SOL is for buyers, not for creators.
9
+
10
+ ### Removed
11
+
12
+ - The seed-in-SOL option on `createMachine`: the creator pays the seed in the quote token. The
13
+ `payWith` input is gone, and with it the swap leg, the route safety check and the extra compute
14
+ units that creation used to ask for. A machine quoted in USDC now needs its creator to hold at
15
+ least `maxSeedQuoteIn` of USDC before the transaction runs, and `seedCostEstimate` says how much
16
+ that is.
17
+
18
+ ### Changed
19
+
20
+ - `SeedCostEstimate.solAmount` stays, and it is a display. It is what the seed is worth in SOL
21
+ through the route provider, not an amount any instruction spends. The create page shows it beside
22
+ the quote-token cost.
23
+ - `buyPack` keeps `payWith` and `sellTokens` keeps `receive`, both unchanged. Only a buyer arrives
24
+ holding SOL alone, so only a pack buy and a sale swap.
25
+
26
+ ## [0.7.0] - 2026-09-18
27
+
28
+ Any quote token Raydium enabled, a price shown in SOL, and payment in SOL through a swap that runs
29
+ in the same transaction as `buy_pack`. It matches the devnet program deployed at slot `500297753`,
30
+ and a live devnet run exercised both a SOL-quoted coin and a USDC-quoted one paid for in SOL.
31
+
32
+ ### Changed
33
+
34
+ - **Breaking.** A machine is priced in one quote asset, chosen at creation. It still defaults to
35
+ wrapped SOL, and any quote Raydium enabled on LaunchLab now works too. `createMachine` takes
36
+ `quote: { mint }` and `raise`; `initialize_pool` takes the quote's LaunchLab `GlobalConfig`
37
+ account, which is what proves the quote, and the quote's own token program.
38
+ - **Breaking.** `Pool` gained `quoteConfig` and `quoteTokenProgram`, and a new discriminator. A pool
39
+ from the first LaunchLab build now fails to decode instead of being read with shifted fields.
40
+ - **Breaking.** `raise` is the client's choice for every quote but wrapped SOL, where the program
41
+ still pins it: 85 SOL on mainnet, 3 SOL on devnet. A non-SOL pool has no default, because the same
42
+ number means a different amount in every token. `createMachine` refuses a raise below
43
+ `min_quote_fund_raising` in the quote's own config, before it builds anything.
44
+ - **Breaking.** `RaydiumClusterIds` lost `solGlobalConfig`. Nothing pins a quote config any more:
45
+ derive it from the quote mint with `raydium.launchlabGlobalConfig`, or read it with
46
+ `raydium.fetchQuoteConfig`.
47
+ - **Breaking.** `fetchCurveSettings(client, quoteConfig, ids?)` takes the quote's config address.
48
+ `newCurveBuyCost(client, tokens, { quoteConfig, raise })` and `newCurveReserves(raise, migrateFee)`
49
+ take the raise, because the starting reserves follow it.
50
+ - **Breaking.** `fetchCreatorFees` takes `quoteMint` and answers
51
+ `{ quoteMint, curveQuote, cpmmQuote, cpmmTokens }`. `curveLamports` and `cpmmLamports` are gone:
52
+ the amounts are in the quote token, which is not always SOL. `claimCreatorFee` takes `quoteMint`
53
+ too, because LaunchLab keeps one vault per wallet per quote asset.
54
+ - **Breaking.** `getLaunchInstruction` takes `quoteMint`, `quoteConfig`, `quoteTokenProgram` and
55
+ `raise`. `LaunchlabTradeAccountsInput` takes `quoteTokenProgram`, and `CpmmTradeAccountsInput`
56
+ takes `baseTokenProgram` and `quoteTokenProgram`; a migrated CPMM pool records both in its own
57
+ data, and the program checks them.
58
+ - `GaboxClient` gained `route`, and `createClient` gained a `route` option. Mainnet defaults to
59
+ `jupiterRoute()`; devnet and localnet default to `null`.
60
+ - `PackOffer` gained `quoteDecimals`, `quoteSymbol` and `solAmount`. `quoteAmount` is still the whole
61
+ pack price, now in the pool's quote token. `SeedCostEstimate` gained the same three plus `raise`.
62
+ - `resolveVenue` takes an optional `quote` binding and reads the Gabox pool for it otherwise. It also
63
+ reports `quoteTokenProgram` and `userQuoteToken`.
64
+
65
+ ### Added
66
+
67
+ - `payWith: 'sol' | 'quote'` on `buyPack` and `createMachine`, and `receive: 'sol' | 'quote'` on
68
+ `sellTokens`. Both default to `'sol'`. On a pool that is not quoted in SOL, the default prepends a
69
+ swap before `buy_pack` and appends one after `sell_tokens`, in the same transaction. The SDK never
70
+ splits the two: a message over the 1,232-byte limit fails with a clear error instead.
71
+ - `src/route/`: `Route`, `RouteProvider`, `jupiterRoute(options)` for mainnet and
72
+ `raydiumCpmmRoute(poolAddress)` for devnet, plus `routeQuoteIn`, `routeQuoteOut`, `solPriceOf` and
73
+ `assertRouteIsSafe`. Neither provider adds a package: Jupiter is plain HTTP and JSON, and the CPMM
74
+ provider reuses this SDK's own swap builders and price math.
75
+ - Exact-out first, exact-in as the fallback. Jupiter answers `NO_ROUTES_FOUND` for exact-out whenever
76
+ the best route has more than one hop, which is the normal case for a stock token. The fallback
77
+ works out the SOL that buys the amount at the exact-in price, adds a margin, and leaves the change
78
+ in the buyer's own quote account. A `Route` reports which mode it used.
79
+ - `raydium.fetchQuoteConfig`, `raydium.isQuoteSupported`, `raydium.fetchQuoteAsset` and
80
+ `raydium.fetchQuoteDisplay`: whether Raydium enabled a quote, and its token program, decimals and
81
+ symbol. The symbol comes from the Token-2022 metadata extension when the mint has one, and from
82
+ Metaplex otherwise.
83
+ - `raydium.quoteAccountFor(user, quoteMint, quoteTokenProgram)`: the account both venues settle in,
84
+ derived under the quote's own token program. A Token-2022 quote has a different ATA from a classic
85
+ one, and the program pins the one the pool records.
86
+ - `TOKEN_2022_PROGRAM_ADDRESS`, generated from Raydium's own IDL.
87
+ - `fetchAddressLookupTables(client, addresses)`: a route names its tables by address, and the message
88
+ has to carry them.
89
+ - `Route.computeUnits`. A swap runs on the same compute budget as the Gabox instruction, so a
90
+ builder with a swap leg adds the route's own figure to its limit: Jupiter's `SetComputeUnitLimit`
91
+ from its `swap-instructions` response (400,000 when absent), or the measured 75,000 of the
92
+ Raydium CPMM route. The sum is capped at the 1,400,000 ceiling; a caller's `computeUnitLimit`
93
+ still wins.
94
+ - Cluster-neutral `initializePool`. The program pins `venue` to LaunchLab's address, which differs
95
+ between the mainnet and devnet builds, so the generated builder no longer carries a default for
96
+ it and `createMachine` passes the cluster's address. `check:program` treats the two IDLs as in
97
+ sync.
98
+
99
+ ### Security
100
+
101
+ - A route is built outside this SDK and runs with the buyer's signature, so every leg is checked
102
+ before it is composed: no instruction may name the Gabox program or any Gabox account the
103
+ transaction uses, and the swap has to settle in the user's own quote associated token account,
104
+ which is the account the program binds and measures the delta in.
105
+ - A route's instructions carry account roles and no signer objects. Kit refuses to sign a message
106
+ that holds two distinct signer objects for one address, and the wallet paying for the transaction
107
+ is the same wallet a route names, so a signer object there would make every such message
108
+ unsignable. Both providers and both new test suites check it.
109
+
6
110
  ## [0.6.0] - 2026-09-18
7
111
 
8
112
  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,57 @@ 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
+ This is for packs and sales only. **A machine's seed is always paid by its creator, in the
50
+ machine's own quote token**, so `createMachine` never swaps. See "Create a machine" below.
51
+
52
+ ```ts
53
+ import { createClient, raydiumCpmmRoute } from '@gabox-labs/sdk';
54
+
55
+ // Mainnet gets Jupiter by default. Devnet has no router, so name a CPMM pool for the SOL pair.
56
+ const client = createClient({
57
+ cluster: 'devnet',
58
+ route: raydiumCpmmRoute(devnetSolUsdcPool),
59
+ });
60
+ ```
61
+
62
+ `payWith: 'quote'` on `buyPack` skips the swap and spends the token the wallet already holds.
63
+ `receive: 'quote'` does the same for a sale. A WSOL pool ignores both: its quote token is SOL.
64
+
65
+ The swap has to fit in the same 1,232-byte transaction as the buy. When it does not, the builder
66
+ fails with a clear error rather than splitting the work; supply more address lookup tables, or pay
67
+ in the quote token. It also runs on the same compute budget, so a builder adds `route.computeUnits`
68
+ to its own limit and caps the total at the 1,400,000-unit ceiling. Jupiter states that number with
69
+ the route it returns; the CPMM provider uses a measured one, because it is always a single pool.
70
+ Pass `computeUnitLimit` to override it.
71
+
72
+ **Closing a WSOL account unwraps everything.** A wallet that already held WSOL in that account gets
73
+ it back as SOL too. Nothing is lost, but the balance moves. Build your own instructions if you keep
74
+ a WSOL position on purpose.
34
75
 
35
76
  ## Create a machine
36
77
 
@@ -52,14 +93,45 @@ One transaction, two signers: the mint keypair and the creator. `initialize_pool
52
93
  unless the same transaction also carries a LaunchLab `initialize_v2` for the same mint with the
53
94
  pinned launch arguments, so the two cannot be separated.
54
95
 
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.
96
+ The creator picks the name, the symbol, the metadata URI, the prize table and the quote asset.
97
+ Everything else is fixed: 6 decimals, 1,000,000,000 coins, 793,100,000 of them sold on the curve,
98
+ graduate into a CPMM pool, no vesting, the CPMM creator fee paid in the quote token. Metaplex limits
99
+ the three strings to 32, 10 and 200 UTF-8 bytes.
59
100
 
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.
101
+ `maxSeedQuoteIn` is the slippage cap on the seed buy, in the quote token, and the creator must
102
+ already hold that much. `maxSeedNativeDebit` is separate and small: it caps the lamports of rent
103
+ LaunchLab charges for the fee vaults it creates on a coin's first trade.
104
+
105
+ ### Another quote asset
106
+
107
+ ```ts
108
+ const estimate = await seedCostEstimate(client, undefined, { quote: { mint: usdc }, raise });
109
+ const message = await createMachine(client, {
110
+ creator,
111
+ mintKeypair,
112
+ name: 'Gabox',
113
+ symbol: 'GBX',
114
+ uri: 'https://example.com/metadata.json',
115
+ quote: { mint: usdc },
116
+ raise, // total_quote_fund_raising, in USDC base units
117
+ maxSeedQuoteIn: (estimate.quoteAmount * 110n) / 100n,
118
+ maxSeedNativeDebit: 100_000_000n,
119
+ });
120
+ ```
121
+
122
+ **The creator pays the seed, in the machine's own quote token.** There is no swap here: a machine
123
+ quoted in USDC needs the creator to hold at least `maxSeedQuoteIn` of USDC before this transaction
124
+ runs. Only a buyer arrives holding SOL alone, so only `buyPack` and `sellTokens` swap.
125
+
126
+ `raise` is how much the curve must take in before the coin graduates, in the quote's own base units.
127
+ A WSOL pool has it pinned by the program — 85 SOL on mainnet, 3 SOL on devnet — so leave it out
128
+ there. Any other quote has no default, because the same number means a different amount in every
129
+ token. LaunchLab refuses a raise below `min_quote_fund_raising` in that quote's config, and
130
+ `createMachine` checks the same thing before it builds anything.
131
+
132
+ `seedCostEstimate` reports `quoteAmount` in the quote token — what the creator actually pays —
133
+ plus `quoteDecimals`, `quoteSymbol` and the `raise` it would use. `solAmount` is what that cost is
134
+ worth in lamports through the route provider, for a display, or `null` when nothing can price it.
63
135
 
64
136
  ### The seed
65
137
 
@@ -84,13 +156,15 @@ const message = await buyPack(client, {
84
156
  });
85
157
  ```
86
158
 
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.
159
+ `offer.quoteAmount` is the exact price the venue will charge for one pack right now, fees included,
160
+ in the pool's quote token. The curve math is a port of Raydium's own, not an estimate, so the
161
+ `PackBought` event reports the same number unless somebody trades in between. `offer.solAmount` is
162
+ the same price in lamports through the route provider, with `offer.quoteDecimals` and
163
+ `offer.quoteSymbol` for showing it.
90
164
 
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.
165
+ `maxQuoteIn` is the slippage cap, in the quote token, and the amount put in the buyer's quote
166
+ account before the buy. `maxNativeDebit` is separate: it caps the lamports the handler watches,
167
+ which are the VRF request and any venue account rent. Gabox adds nothing to either.
94
168
 
95
169
  ## Sell
96
170
 
@@ -105,7 +179,9 @@ const message = await sellTokens(client, {
105
179
  });
106
180
  ```
107
181
 
108
- The seller keeps the whole venue proceeds. `minQuoteOutput` is the venue's own floor.
182
+ The seller keeps the whole venue proceeds. `minQuoteOutput` is the venue's own floor, in the quote
183
+ token. On a pool that is not quoted in SOL, `receive: 'sol'` (the default) swaps that floor into SOL
184
+ in the same transaction; anything the venue paid above the floor stays in the quote account.
109
185
 
110
186
  ## Which venue
111
187
 
@@ -121,30 +197,37 @@ Raydium picks a fresh address when that one is taken. So the pool has to prove i
121
197
  data — CPMM owns it, it carries the `PoolState` discriminator, its `pool_creator` is the coin
122
198
  creator, its two mints are the sorted pair, and `enable_creator_fee` is true. That last flag is the
123
199
  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.
200
+ same five things before it forwards a trade, and reads the fee tier, both vaults, both token
201
+ programs and the oracle out of the pool account rather than deriving them.
202
+
203
+ `resolveVenue` needs the pool's quote asset. It reads the Gabox pool for it, or takes a
204
+ `quote: { mint, config, tokenProgram }` when the caller already has one.
126
205
 
127
206
  ## Creator fees
128
207
 
129
208
  ```ts
130
209
  const owed = await raydium.fetchCreatorFees(client, { creator: creator.address, mint });
131
- // owed.curveLamports, owed.cpmmLamports, owed.cpmmTokens
210
+ // owed.quoteMint, owed.curveQuote, owed.cpmmQuote, owed.cpmmTokens
132
211
 
133
- await raydium.claimCreatorFee(client, { creator }); // every coin on the curve, at once
212
+ await raydium.claimCreatorFee(client, { creator }); // every SOL coin on the curve, at once
134
213
  await raydium.collectCreatorFee(client, { mint, creator }); // one graduated coin
135
214
  ```
136
215
 
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.
216
+ LaunchLab keeps one creator fee vault per wallet **per quote asset**, so a single claim sweeps every
217
+ coin that wallet launched against that quote. A creator with a SOL machine and a USDC machine claims
218
+ twice: `claimCreatorFee(client, { creator, quoteMint })`, and `fetchCreatorFees` takes the same
219
+ argument. A CPMM pool keeps its creator fee inside the pool account, so that one is per coin and
220
+ reads the quote off the Gabox pool itself.
221
+
222
+ Both pay into the creator's account for the quote mint. When that is WSOL the builders close it, so
223
+ the creator receives SOL; any other quote arrives as that token.
141
224
 
142
225
  ## Wallet activity
143
226
 
144
227
  `buyPack` keeps a `WalletActivity` account per buyer, at the PDA `findActivityPda({ purchaser })`
145
228
  (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
229
+ `nativeSpent` is what the venue charged in WSOL, which is SOL; Gabox's own rent, the VRF fee and a
230
+ 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
231
  itself. Read it with `fetchWalletActivity(client, wallet)`, which returns `null` before a wallet's
149
232
  first purchase.
150
233
 
@@ -165,5 +248,6 @@ The generated client decodes the program's own errors by name. The ones a client
165
248
  | `PrizeCapChanged` | The top prize fell below `minMaximum`. Refresh the offer. |
166
249
  | `IncorrectTokenDelta` | The venue did not deliver exactly one pack. Usually a curve with less than a pack left; wait for graduation. |
167
250
  | `InvalidLaunch` | The LaunchLab create instruction was missing or did not match the pinned shape. |
251
+ | `InvalidQuote` | The quote mint is not one Raydium enabled, or its Token-2022 profile is one the program refuses. |
168
252
 
169
253
  See [the API reference](skills/gabox-sdk/references/api.md).