@gabox-labs/sdk 0.8.0 → 0.9.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,54 @@
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
+ ## [Unreleased]
7
+
8
+ ## [0.9.1] - 2026-09-19
9
+
10
+ ### Changed
11
+
12
+ - `DEFAULT_TIERS` is now Common 80% at 0.5126x, Rare 15% at 2x, Epic 4% at 3.5x, Mythic 1% at
13
+ 10x. The average payout stays 9,499 bps and the mandatory seed stays 2 packs. Every win at least
14
+ doubles the pack, and the top tier halves so one hit pays 1% of the supply instead of 2%. Pools
15
+ created before this release keep the table they were created with.
16
+
17
+ ## [0.9.0] - 2026-09-19
18
+
19
+ **Breaking.** The program now sells packs in purchases of one to five, and pays a prize it cannot
20
+ deliver into an owed balance instead of failing. Every earlier devnet pool is abandoned by this
21
+ program version, so nothing this release reads existed before its deploy.
22
+
23
+ ### Added
24
+
25
+ - `buyPacks(client, { count, nonce?, maxQuoteIn, minFirstMaximum, maxNativeDebit, ... })` opens
26
+ `count` packs (1 to `MAX_BATCH_SIZE`, which is 5) in one venue trade with one draw and one
27
+ randomness request. It returns `{ message, draw, nonce, seqStart, count }`. `buyPack` stays as
28
+ the one-pack form with `minMaximum`, and returns the same shape.
29
+ - `getOffer(client, mint, { count })` prices the whole purchase and adds `count`, `perPackCaps`
30
+ (the worst-case top prize of each pack), `batchReserved` and `freeSnapshot`.
31
+ - `settle`, `settleDraw` and `ticketFor` reproduce a purchase's settlement from the oracle's
32
+ randomness, the way the program does it. `reserveFor`, `settleWith`, `perPackCaps`,
33
+ `chooseIndex`, `uncappedAmounts` and `minTier` are the pure parts.
34
+ - `claimPrize` and `claimPrizeTo` pay an owed prize; `fetchOwedDraws` lists what a wallet is owed;
35
+ `drawAvailability` reports `settled`, `owed`, `canDeliver` and `canClaim`.
36
+ - `randomNonce`, and `drawAddress(pool, purchaser, nonce)`.
37
+ - Events `PacksBought` and `PrizeClaimed`. `DrawResolved` carries `draw`, `seqStart`, `count`,
38
+ `total`, `paid` and one `results` entry per pack. `RandomnessRetried` names the draw.
39
+ - `CLAIM_PRIZE_COMPUTE_UNITS`.
40
+
41
+ ### Changed
42
+
43
+ - `drawAddress` takes the purchaser and a nonce; the pool's sequence counter is no longer in the
44
+ address. `findResolvedDraw` matches the event's own `draw` field.
45
+ - `Draw` has a new layout and discriminator: a snapshot of the tiers, the pack size and the free
46
+ inventory, plus `settled`, `randomness`, `timedOut` and `owed`. `Pool` has a new discriminator.
47
+ - `expireDraw` refuses a settled draw before sending; the program pays every pack of an expired
48
+ purchase its smallest tier.
49
+
50
+ ### Removed
51
+
52
+ - `PackBought`; `PacksBought` replaces it.
53
+
6
54
  ## [0.8.0] - 2026-09-19
7
55
 
8
56
  The platform's own fees, so the app can show them and claim them.
package/README.md CHANGED
@@ -61,7 +61,7 @@ const client = createClient({
61
61
  });
62
62
  ```
63
63
 
64
- `payWith: 'quote'` on `buyPack` skips the swap and spends the token the wallet already holds.
64
+ `payWith: 'quote'` on `buyPacks` skips the swap and spends the token the wallet already holds.
65
65
  `receive: 'quote'` does the same for a sale. A WSOL pool ignores both: its quote token is SOL.
66
66
 
67
67
  The swap has to fit in the same 1,232-byte transaction as the buy. When it does not, the builder
@@ -123,7 +123,7 @@ const message = await createMachine(client, {
123
123
 
124
124
  **The creator pays the seed, in the machine's own quote token.** There is no swap here: a machine
125
125
  quoted in USDC needs the creator to hold at least `maxSeedQuoteIn` of USDC before this transaction
126
- runs. Only a buyer arrives holding SOL alone, so only `buyPack` and `sellTokens` swap.
126
+ runs. Only a buyer arrives holding SOL alone, so only `buyPacks` and `sellTokens` swap.
127
127
 
128
128
  `raise` is how much the curve must take in before the coin graduates, in the quote's own base units.
129
129
  A WSOL pool has it pinned by the program — 85 SOL on mainnet, 3 SOL on devnet — so leave it out
@@ -145,28 +145,47 @@ can add more with `extraSeedTokens` (default `0n`), which the program adds to th
145
145
  at most 20x; seed beyond what a 20x prize needs stays in the vault as backup for the draws after a
146
146
  top-tier hit.
147
147
 
148
- ## Buy a pack
148
+ ## Buy packs
149
149
 
150
150
  ```ts
151
- const offer = await getOffer(client, mint, { user: purchaser.address });
152
- const message = await buyPack(client, {
151
+ const offer = await getOffer(client, mint, { user: purchaser.address, count: 3 });
152
+ const { message, draw, nonce } = await buyPacks(client, {
153
153
  mint,
154
154
  purchaser,
155
+ count: 3,
155
156
  maxQuoteIn: (offer.quoteAmount * 102n) / 100n,
156
- minMaximum: (offer.maximum * 98n) / 100n,
157
+ minFirstMaximum: (offer.maximum * 98n) / 100n,
157
158
  maxNativeDebit: 100_000_000n,
158
159
  });
159
160
  ```
160
161
 
161
- `offer.quoteAmount` is the exact price the venue will charge for one pack right now, fees included,
162
- in the pool's quote token. The curve math is a port of Raydium's own, not an estimate, so the
163
- `PackBought` event reports the same number unless somebody trades in between. `offer.solAmount` is
164
- the same price in lamports through the route provider, with `offer.quoteDecimals` and
162
+ One purchase opens `count` packs, 1 to `MAX_BATCH_SIZE` (5): one venue trade for all of them, one
163
+ draw, one randomness request. `buyPack` is the same with `count: 1` and `minMaximum` in place of
164
+ `minFirstMaximum`. Both return the message, the draw's address and its nonce, so the caller can
165
+ watch the draw without deriving anything.
166
+
167
+ `offer.quoteAmount` is the exact price the venue will charge for the whole purchase right now, fees
168
+ included, in the pool's quote token. The curve math is a port of Raydium's own, not an estimate, so
169
+ the `PacksBought` event reports the same number unless somebody trades in between. `offer.solAmount`
170
+ is the same price in lamports through the route provider, with `offer.quoteDecimals` and
165
171
  `offer.quoteSymbol` for showing it.
166
172
 
167
- `maxQuoteIn` is the slippage cap, in the quote token, and the amount put in the buyer's quote
168
- account before the buy. `maxNativeDebit` is separate: it caps the lamports the handler watches,
169
- which are the VRF request and any venue account rent. Gabox adds nothing to either.
173
+ `offer.prizes` and `offer.maximum` are the first pack's table, capped by the vault as it is now. The
174
+ later packs settle in order: each one is capped at what the vault can pay after the packs before
175
+ it, counting the purchase's own tokens as they arrive. `offer.perPackCaps` is the worst case per
176
+ pack, the top prize it keeps if every earlier pack won its own; on a thin vault the later entries
177
+ fall towards one pack, and a screen should show that next to the first table.
178
+
179
+ The draw's address is `["draw", pool, purchaser, nonce]`. The builder draws a random nonce unless
180
+ you pass one, so purchases from several buyers, or several from one buyer sent together, never
181
+ collide. A nonce still in use fails at the program; a nonce whose draw already closed opens a new
182
+ purchase, so never reuse the nonce of a purchase that may have landed.
183
+
184
+ `maxQuoteIn` is the slippage cap for the whole purchase, in the quote token, and the amount put in
185
+ the buyer's quote account before the buy. `minFirstMaximum` is the floor on the first pack's top
186
+ prize; refresh the offer when `PrizeCapChanged` refuses it. `maxNativeDebit` is separate: it caps
187
+ the lamports the handler watches, which are the VRF request and any venue account rent. Gabox adds
188
+ nothing to any of them.
170
189
 
171
190
  ## Sell
172
191
 
@@ -245,18 +264,35 @@ that LP and pays both sides of the pair into the owner's accounts, closing the W
245
264
 
246
265
  ## Wallet activity
247
266
 
248
- `buyPack` keeps a `WalletActivity` account per buyer, at the PDA `findActivityPda({ purchaser })`
267
+ `buyPacks` keeps a `WalletActivity` account per buyer, at the PDA `findActivityPda({ purchaser })`
249
268
  (also `activityAddress(wallet)`). It tracks `packsBought` and `nativeSpent` across every pool.
250
269
  `nativeSpent` is what the venue charged in WSOL, which is SOL; Gabox's own rent, the VRF fee and a
251
- 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
252
- itself. Read it with `fetchWalletActivity(client, wallet)`, which returns `null` before a wallet's
253
- first purchase.
270
+ pack bought in any other quote token are not counted. The buyer pays its rent once, on the first
271
+ purchase, and `buyPacks` resolves the account itself. Read it with
272
+ `fetchWalletActivity(client, wallet)`, which returns `null` before a wallet's first purchase.
254
273
 
255
274
  ## Draws
256
275
 
257
- Gabox delivers awards and closes draws atomically. Use `fetchEvents`, `decodeEvents` and
258
- `findResolvedDraw` for final state. There is no Ready, claim or sell-prize flow. Existing base tokens
259
- can be donated irrevocably with `fundPrizes`; a stalled draw uses `retryDraw` or `expireDraw`.
276
+ The oracle's callback settles every pack of a purchase from one randomness and pays the total into
277
+ the purchaser's coin account, then closes the draw and returns its rent. `findResolvedDraw(client,
278
+ draw)` finds that `DrawResolved` event: `total`, one `results` entry per pack with its tier and
279
+ amount, the `randomness`, and `paid`.
280
+
281
+ `paid: false` means the callback could not use the purchaser's coin account, because it was
282
+ missing, closed, or no longer the purchaser's. The outcome is still fixed: the draw stays open with
283
+ `settled: true` and the total in `owed`, and nothing can reopen it. `claimPrize(client, { payer,
284
+ draw })` pays it to the purchaser's ATA, creating the account if needed, and anyone may send it.
285
+ `claimPrizeTo(client, { purchaser, draw, destination })` is the purchaser's own way out when they
286
+ changed their ATA's owner: it pays any coin account they own. `fetchOwedDraws(client, purchaser)`
287
+ lists what a wallet is still owed. This path exists so that a buyer cannot make the callback fail,
288
+ read its randomness, and try again; honest buyers never see it.
289
+
290
+ Anyone can check what a purchase won. `settle({ tiers, packTokens, freeSnapshot, count, pool,
291
+ seqStart, randomness })` recomputes every pack's result the way the program does, and
292
+ `settleDraw(draw)` does it from an owed draw's account alone. `drawAvailability(client, draw)` says
293
+ what can still happen to a draw. A stalled draw uses `retryDraw`, and `expireDraw` fixes it at every
294
+ pack's smallest tier after `TIMEOUT_SLOTS`. Existing base tokens can be donated irrevocably with
295
+ `fundPrizes`.
260
296
 
261
297
  ## Errors
262
298
 
@@ -266,8 +302,13 @@ The generated client decodes the program's own errors by name. The ones a client
266
302
  | --- | --- |
267
303
  | `InvalidVenue` | The account list did not match. Resolve the venue again and rebuild. |
268
304
  | `SlippageExceeded` | The price moved past `maxQuoteIn`, or a cost went past `maxNativeDebit`. |
269
- | `PrizeCapChanged` | The top prize fell below `minMaximum`. Refresh the offer. |
270
- | `IncorrectTokenDelta` | The venue did not deliver exactly one pack. Usually a curve with less than a pack left; wait for graduation. |
305
+ | `PrizeCapChanged` | The first pack's top prize fell below `minFirstMaximum`. Refresh the offer. |
306
+ | `IncorrectTokenDelta` | The venue did not deliver exactly `count` packs. Usually a curve with fewer whole packs left; buy fewer or wait for graduation. |
307
+ | `TooManyPacks` / `ZeroAmount` | `count` is above `MAX_BATCH_SIZE` or zero. The builder refuses these before sending. |
308
+ | `DrawAlreadySettled` | A retry, an expiry or a second callback reached a draw whose outcome is fixed. Nothing to do. |
309
+ | `DrawNotSettled` | A claim on a draw that is still pending. Wait for the callback. |
310
+ | `DrawExpired` | A callback arrived after the deadline; only `expireDraw` remains. |
311
+ | `WrongDestination` | `claimPrizeTo` was given an account that is not the purchaser's, or not for this coin. |
271
312
  | `InvalidLaunch` | The LaunchLab create instruction was missing or did not match the pinned shape. |
272
313
  | `InvalidQuote` | The quote mint is not one Raydium enabled, or its Token-2022 profile is one the program refuses. |
273
314