@suigar/sdk 2.0.0-beta.3 → 2.0.0-beta.5

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
@@ -1,17 +1,53 @@
1
1
  # @suigar/sdk
2
2
 
3
+ ## 2.0.0-beta.5
4
+
5
+ ### Patch Changes
6
+
7
+ - bf98e0a: Update PvP coinflip registry lookups so `getPvPCoinflipGames()` can skip
8
+ individual game resolution failures by default while still supporting
9
+ `rejectOnError: true` for strict rejection.
10
+ - Document the `rejectOnError` behavior in the public JSDoc and README examples.
11
+ - Clarify repo guidance and skill documentation to distinguish general PvP game
12
+ guidance from the current PvP coinflip-specific runtime surface.
13
+
14
+ ## 2.0.0-beta.4
15
+
16
+ ### Patch Changes
17
+
18
+ - 6daa819: Add BCS parser helpers and a Next.js game integration example app.
19
+ - expose parser helpers through `@suigar/sdk/utils`
20
+ - add `parseGameDetails` for decoding `BetResultEvent.game_details`
21
+ - document generated BCS event decoding and game detail parsing guidance
22
+ - add a testnet-only `examples/game-integration` app for standard and PvP Suigar transactions
23
+ - integrate Mysten dApp Kit wallet connection, signing, and execution
24
+ - add live transaction code previews and shared decoded event logging with SDK parser helpers
25
+ - add Suigar-themed responsive UI, supported coin selection, and human-readable stake handling
26
+ - update PvP coinflip join so callers only provide `gameId` and the SDK derives the join stake while using the configured price info object id
27
+
28
+ - b89d0b4: Add a public `@suigar/sdk/games` export subpath for shared game option types, and export `SuigarClient` from the package root.
29
+ - bf1f71b: Add `registryIds` to `SuigarConfig` and resolve it from the network config registry map.
30
+
31
+ Document the PvP coinflip runtime helpers more clearly by describing
32
+ registry-backed unresolved game discovery through `getPvPCoinflipGames()` and
33
+ the normalized live-game lookup behavior of `resolvePvPConflipGame()`.
34
+
35
+ - 4861f55: Add public utility exports for shared scaling constants in `@suigar/sdk/utils`, including `RANGE_POINT_LIMIT` and `DEFAULT_RANGE_SCALE`. Update the SDK example app and documentation to use the exported constants and document limbo/range scaling behavior more clearly.
36
+
3
37
  ## 2.0.0-beta.3
4
38
 
5
39
  ### Patch Changes
6
40
 
7
- - e1cdedc: - Fix exported transaction option types so `BuildGameOptions` and `BuildPvPGameOptions` no longer require the internal `config` field
41
+ - e1cdedc: Improve public transaction builder typings and refresh Sui 2.0+ integration guidance around the gRPC client.
42
+ - Fix exported transaction option types so `BuildGameOptions` and `BuildPvPGameOptions` no longer require the internal `config` field
8
43
  - Update installation and integration documentation for Sui 2.0+ by switching examples to `SuiGrpcClient`, clarifying required peer dependencies, and aligning transaction-result examples with the current client API.
9
44
 
10
45
  ## 2.0.0-beta.2
11
46
 
12
47
  ### Patch Changes
13
48
 
14
- - 128cb6c: - `suigar()` now only accepts the extension `name`.
49
+ - 128cb6c: Make SDK configuration network-resolved and expose runtime config inspection through the client extension.
50
+ - `suigar()` now only accepts the extension `name`.
15
51
  - The SDK now validates the connected client network and supports `mainnet` and `testnet`.
16
52
  - Added `client.suigar.getConfig()` to inspect the resolved network config at runtime.
17
53
  - Exported the `SuiNetwork` type and `resolveGamePackageId()` helper.
package/README.md CHANGED
@@ -19,14 +19,53 @@ This SDK targets Sui TypeScript SDK 2.0+ only. Follow the official [Sui 2.0 migr
19
19
 
20
20
  ## What This Package Exposes
21
21
 
22
- The package root currently exposes the extension factory:
22
+ The package ships three public entrypoints:
23
+
24
+ - `@suigar/sdk` for the extension factory and runtime client class
25
+ - `@suigar/sdk/games` for game-specific public types
26
+ - `@suigar/sdk/utils` for public parser, constants, and numeric helpers
27
+
28
+ The package root exposes the extension factory and client class:
23
29
 
24
30
  ```ts
25
- import { suigar } from '@suigar/sdk';
31
+ import { suigar, SuigarClient } from '@suigar/sdk';
26
32
  ```
27
33
 
28
34
  It does not export the individual transaction builders from the package root.
29
- It also does not export `SuigarClient` as a public root symbol.
35
+ Those stay on the registered extension instance under `client.suigar.tx`.
36
+
37
+ Utility exports are available from the utils subpath:
38
+
39
+ ```ts
40
+ import {
41
+ DEFAULT_GAS_BUDGET_MIST,
42
+ DEFAULT_LIMBO_MULTIPLIER_SCALE,
43
+ DEFAULT_RANGE_SCALE,
44
+ RANGE_POINT_LIMIT,
45
+ parseFloat,
46
+ parseGameDetails,
47
+ parseI64,
48
+ toBigIntAmount,
49
+ toU8Number,
50
+ } from '@suigar/sdk/utils';
51
+ ```
52
+
53
+ Game-specific type exports are available from the dedicated `games` subpath:
54
+
55
+ ```ts
56
+ import type {
57
+ BuildCoinflipTransactionOptions,
58
+ CoinSide,
59
+ } from '@suigar/sdk/games';
60
+ import type {
61
+ BuildCreatePvPCoinflipTransactionOptions,
62
+ PvPCoinflipAction,
63
+ } from '@suigar/sdk/games';
64
+ ```
65
+
66
+ Current game-type subpath exports:
67
+
68
+ - `@suigar/sdk/games`: `CoinSide`, `PvPCoinflipAction`, `BuildCoinflipTransactionOptions`, `BuildLimboTransactionOptions`, `BuildPlinkoTransactionOptions`, `BuildRangeTransactionOptions`, `BuildWheelTransactionOptions`, `BuildCreatePvPCoinflipTransactionOptions`, `BuildJoinPvPCoinflipTransactionOptions`, `BuildCancelPvPCoinflipTransactionOptions`
30
69
 
31
70
  What you actually use at runtime is the registered extension instance:
32
71
 
@@ -35,6 +74,8 @@ const client = new SuiGrpcClient({ baseUrl, network }).$extend(suigar());
35
74
 
36
75
  client.suigar.serializeTransactionToBase64(...);
37
76
  client.suigar.getConfig();
77
+ client.suigar.getPvPCoinflipGames(...);
78
+ client.suigar.resolvePvPConflipGame(...);
38
79
  client.suigar.bcs;
39
80
  client.suigar.tx;
40
81
  ```
@@ -66,12 +107,24 @@ const base64 = await client.suigar.serializeTransactionToBase64(tx);
66
107
 
67
108
  Creates a named Sui client extension. By default, it registers under `client.suigar`.
68
109
 
110
+ ### Partner Setup
111
+
112
+ > [!IMPORTANT]
113
+ > `partner` is the partner wallet address. Configure it once when you
114
+ > register the extension so the SDK can append that wallet address to supported
115
+ > bet metadata automatically.
116
+
69
117
  ```ts
70
- const client = new SuiGrpcClient({ baseUrl, network }).$extend(suigar());
118
+ const client = new SuiGrpcClient({ baseUrl, network }).$extend(
119
+ suigar({ partner: '0xpartner_wallet_address' }),
120
+ );
71
121
 
72
122
  client.suigar;
73
123
  ```
74
124
 
125
+ Do not pass a partner slug, label, or display name here. Use the wallet
126
+ address that should receive partner attribution onchain.
127
+
75
128
  You can rename the extension:
76
129
 
77
130
  ```ts
@@ -96,13 +149,21 @@ client.games.bcs;
96
149
  Supported override areas:
97
150
 
98
151
  - `name`
152
+ - `partner`
153
+
154
+ If `partner` is configured, the SDK automatically writes that partner wallet
155
+ address into the onchain metadata vec-map. Transaction builder options may also
156
+ include `metadata`, but reserved keys such as `partner` and `referrer` are
157
+ ignored with a warning when provided manually.
99
158
 
100
159
  ## Runtime Surface
101
160
 
102
- The registered extension instance exposes three main areas:
161
+ The registered extension instance exposes the main runtime surface:
103
162
 
104
163
  - `getConfig()`
105
164
  - `serializeTransactionToBase64(transaction, options?)`
165
+ - `getPvPCoinflipGames(options?)`
166
+ - `resolvePvPConflipGame(gameId)`
106
167
  - `bcs`
107
168
  - `tx`
108
169
 
@@ -116,6 +177,7 @@ resolved package ids or supported coin mappings for the active client network.
116
177
  It includes:
117
178
 
118
179
  - `packageIds`
180
+ - `registryIds`
119
181
  - `coinTypes`
120
182
  - `priceInfoObjectIds`
121
183
 
@@ -134,6 +196,69 @@ Use this when you need a transport-safe payload for a wallet, API, or external s
134
196
  const base64 = await client.suigar.serializeTransactionToBase64(tx);
135
197
  ```
136
198
 
199
+ ### `getPvPCoinflipGames(options?)`
200
+
201
+ Lists unresolved PvP coinflip games from the configured PvP registry.
202
+
203
+ This reads the registry dynamic fields for the active network and resolves each
204
+ entry into parsed game state through `resolvePvPConflipGame()`. Registry
205
+ membership is the unresolved-state signal: once a match is joined and resolved,
206
+ the Move flow removes it from the registry and deletes the live `Game` object.
207
+
208
+ Use this when a product needs the current set of open PvP coinflip matches for
209
+ browsing or lobby views.
210
+
211
+ By default, failures to resolve an individual game are skipped so one broken or
212
+ already-deleted registry entry does not reject the full lookup. Pass
213
+ `rejectOnError: true` if you want the call to reject instead.
214
+
215
+ ```ts
216
+ const games = await client.suigar.getPvPCoinflipGames({ limit: 20 });
217
+
218
+ for (const game of games) {
219
+ console.log(game.id);
220
+ console.log(game.coinType);
221
+ }
222
+ ```
223
+
224
+ ```ts
225
+ const games = await client.suigar.getPvPCoinflipGames({
226
+ limit: 20,
227
+ rejectOnError: true,
228
+ });
229
+ ```
230
+
231
+ ### `resolvePvPConflipGame(gameId)`
232
+
233
+ Fetches a PvP coinflip game object from chain and parses it into the SDK's
234
+ normalized runtime shape.
235
+
236
+ This requires the object's `content`, decodes it with the generated
237
+ `PvPCoinflipGame` parser, and normalizes the generic coin type into a standard
238
+ struct tag string.
239
+
240
+ Use this when a product needs the live onchain match state for a specific
241
+ pending match before rendering join or cancel actions, or inspecting the stake
242
+ and privacy flag for a game.
243
+
244
+ ```ts
245
+ const game = await client.suigar.resolvePvPConflipGame('0xGAME_ID');
246
+
247
+ console.log(game.creator);
248
+ console.log(game.coinType);
249
+ console.log(game.stake_per_player);
250
+ console.log(game.is_private);
251
+ ```
252
+
253
+ > [!NOTE]
254
+ >
255
+ > - it throws if the object response does not include decodable `content`
256
+ > - the PvP join builder uses this internally to derive the required join stake
257
+ > - after a game is joined and resolved, the live `Game` object is removed from the registry and deleted, so inspect `PvPCoinflipGameResolved` to read the final result
258
+
259
+ > [!TIP]
260
+ > Prefer this helper over manual object parsing when you only need the parsed state for a live PvP coinflip game object.
261
+
137
262
  ## `tx`
138
263
 
139
264
  Transaction builders live under `client.suigar.tx`.
@@ -176,6 +301,8 @@ Shared behavior:
176
301
  - `betCount` defaults to `1`
177
302
  - `sender` overrides the transaction sender
178
303
  - `metadata` is encoded into `keys` and `values` byte arrays
304
+ - `partner` configured via `suigar({ partner })` is appended automatically to metadata as the partner wallet address
305
+ - `metadata.partner` and `metadata.referrer` are reserved and ignored with a warning
179
306
  - the SDK resolves the price info object from the configured supported-coin mapping
180
307
  - the reward object is transferred back to `owner`
181
308
 
@@ -201,17 +328,25 @@ const rangeTx = client.suigar.tx.createBetTransaction('range', {
201
328
  owner: '0x123',
202
329
  coinType: '0x2::sui::SUI',
203
330
  stake: 1_000_000_000n,
204
- leftPoint: 0.95,
205
- rightPoint: 1.05,
331
+ leftPoint: 25,
332
+ rightPoint: 75,
206
333
  outOfRange: false,
207
334
  });
208
335
  ```
209
336
 
210
- Notes:
337
+ > [!NOTE]
338
+ >
339
+ > - limbo converts `targetMultiplier` with `Math.round(targetMultiplier * scale)`
340
+ > - with the default limbo scale `100`, exposed as `DEFAULT_LIMBO_MULTIPLIER_SCALE`, a target multiplier of `2.5` becomes `250` onchain
341
+ > - range converts each point with `Math.round(value * scale)`
342
+ > - range points are bounded by the contract limit exposed as `RANGE_POINT_LIMIT`
343
+ > - with the default range scale `1_000_000`, exposed as `DEFAULT_RANGE_SCALE`, valid UI values are `0` to `100`
344
+ > - plinko and wheel `configId` must fit in `u8`
211
345
 
212
- - limbo converts `targetMultiplier` with `Math.round(targetMultiplier * scale)`
213
- - range converts each point with `Math.round(value * scale)`
214
- - plinko and wheel `configId` must fit in `u8`
346
+ > [!TIP]
347
+ >
348
+ > - if you set `scale` to `10_000_000`, valid UI values become `0` to `10`
349
+ > - do not pre-scale range points before passing them to the SDK; pass the human value and let the SDK scale it once
215
350
 
216
351
  ### PvP Coinflip
217
352
 
@@ -240,8 +375,6 @@ const tx = client.suigar.tx.createPvPCoinflipTransaction('join', {
240
375
  owner: '0x123',
241
376
  coinType: '0x2::sui::SUI',
242
377
  gameId: '0xGAME_ID',
243
- extraObjectId: '0xEXTRA_OBJECT_ID',
244
- stake: 1_000_000_000n,
245
378
  });
246
379
  ```
247
380
 
@@ -255,11 +388,14 @@ const tx = client.suigar.tx.createPvPCoinflipTransaction('cancel', {
255
388
  });
256
389
  ```
257
390
 
391
+ Join derives the stake from `gameId` and uses the configured price info object
392
+ id for `coinType`.
393
+
258
394
  PvP shared options:
259
395
 
260
396
  - `owner: string`
261
397
  - `coinType: string`
262
- - `metadata?: ...`
398
+ - `metadata?: Record<string, string | number | boolean | bigint | Uint8Array | number[] | null | undefined>`
263
399
  - `gasBudget?: number | bigint`
264
400
  - `sender?: string`
265
401
  - `allowGasCoinShortcut?: boolean`
@@ -267,7 +403,7 @@ PvP shared options:
267
403
  Action-specific options:
268
404
 
269
405
  - `create`: `stake`, `side`, `isPrivate?`
270
- - `join`: `gameId`, `extraObjectId`, `stake`
406
+ - `join`: `gameId`
271
407
  - `cancel`: `gameId`
272
408
 
273
409
  ## `bcs`
@@ -276,12 +412,41 @@ BCS helpers live under `client.suigar.bcs`.
276
412
 
277
413
  Current exposed helpers:
278
414
 
415
+ - `PvPCoinflipGame`
279
416
  - `BetResultEvent`
280
417
  - `PvPCoinflipGameCreated`
281
418
  - `PvPCoinflipGameResolved`
282
419
  - `PvPCoinflipGameCancelled`
283
420
 
284
- These are generated Move event decoders. Use them to parse Suigar event payloads from transaction results.
421
+ These are generated Move event decoders. Use them to parse Suigar event payloads from transaction results. The `@suigar/sdk/utils` subpath also exposes parser helpers for generated BCS values:
422
+
423
+ - `PvPCoinflipGame` parses a PvP coinflip game object's `content`
424
+ - `parseI64(float.exp)` converts a generated Move `i64` exponent to a JavaScript number
425
+ - `parseFloat(float)` converts a generated Move `Float` struct to a JavaScript number
426
+ - `parseGameDetails(game_details)` decodes `BetResultEvent.game_details` entries into the expected string, number, and boolean values
427
+
428
+ ### Parse PvP Coinflip Game Object Data
429
+
430
+ Use the BCS helper directly when you already fetched the object with `content`:
431
+
432
+ ```ts
433
+ const { object } = await client.core.getObject({
434
+ objectId: '0xGAME_ID',
435
+ include: { content: true },
436
+ });
437
+
438
+ if (!object.content) {
439
+ throw new Error('Missing game content');
440
+ }
441
+
442
+ const parsed = client.suigar.bcs.PvPCoinflipGame.parse(object.content);
443
+ ```
444
+
445
+ If you only need the parsed game object, prefer the convenience method:
446
+
447
+ ```ts
448
+ const parsed = await client.suigar.resolvePvPConflipGame('0xGAME_ID');
449
+ ```
285
450
 
286
451
  ### Parse Standard Bet Result Data
287
452
 
@@ -333,27 +498,32 @@ Parsed fields include:
333
498
  - `game_details`
334
499
  - `metadata`
335
500
 
336
- `game_details` and `metadata` decode as `VecMap<string, vector<u8>>`-shaped data, so values come back as byte arrays.
501
+ `game_details` and `metadata` decode as `VecMap<string, vector<u8>>`-shaped data, so values come back as byte arrays. Use `parseGameDetails` from `@suigar/sdk/utils` to decode `game_details` with the SDK's known game-detail schemas.
337
502
 
338
503
  ```ts
339
- const textDecoder = new TextDecoder();
504
+ import { parseGameDetails } from '@suigar/sdk/utils';
340
505
 
341
- const metadata = new Map(
342
- decoded.metadata.contents.map(({ key, value }) => [
343
- key,
344
- textDecoder.decode(new Uint8Array(value)),
345
- ]),
346
- );
506
+ const decoded = client.suigar.bcs.BetResultEvent.parse(event.bcs);
507
+ const gameDetails = parseGameDetails(decoded.game_details);
347
508
  ```
348
509
 
349
- Important:
510
+ `parseGameDetails` preserves the onchain keys and only changes the value representation. For example, coinflip details keep keys such as `player_bet` and `coin_outcome`; range details keep keys such as `roll_value`, `win`, and `payout_multiplier`.
511
+
512
+ When the extension is configured with `partner`, decoded event `metadata` will
513
+ contain that partner wallet address under the `partner` entry.
350
514
 
351
- - execute or wait for the transaction with `include: { events: true }`
352
- - unwrap the core API union with `result.$kind`, `result.Transaction`, and `result.FailedTransaction`
353
- - parse emitted events from the unwrapped transaction result
354
- - use `event.bcs` for consistent decoding across transports
355
- - `waitForTransaction({ result, include: { effects: true, events: true } })` is useful when you want the finalized transaction result before decoding
356
- - these helpers decode the event payload itself, not a full transaction response
515
+ > [!IMPORTANT]
516
+ >
517
+ > - execute or wait for the transaction with `include: { events: true }`
518
+ > - unwrap the core API union with `result.$kind`, `result.Transaction`, and `result.FailedTransaction`
519
+ > - parse emitted events from the unwrapped transaction result
520
+ > - use `event.bcs` for consistent decoding across transports
521
+ > - use `parseGameDetails(decoded.game_details)` instead of hand-decoding standard game detail byte arrays
522
+
523
+ > [!TIP]
524
+ >
525
+ > - `waitForTransaction({ result, include: { effects: true, events: true } })` is useful when you want the finalized transaction result before decoding
526
+ > - these helpers decode the event payload itself, not a full transaction response
357
527
 
358
528
  ### Parse PvP Coinflip Event Data
359
529
 
@@ -370,3 +540,24 @@ npm run build
370
540
  npm run typecheck
371
541
  npm test
372
542
  ```
543
+
544
+ ## Example App
545
+
546
+ This repository now includes a Next.js integration example in [examples/game-integration](/Users/lucas/Documents/Github/suigar-sdk/examples/game-integration).
547
+
548
+ It demonstrates:
549
+
550
+ - standard game transactions through `client.suigar.tx.createBetTransaction(...)`
551
+ - PvP coinflip create, join, and cancel flows through `client.suigar.tx.createPvPCoinflipTransaction(...)`, exposed in the example through a PvP coinflip action selector
552
+ - wallet connection and execution with `@mysten/dapp-kit-core` and `@mysten/dapp-kit-react`
553
+ - supported coin selection from `client.suigar.getConfig()`
554
+ - connected-wallet balance display for each supported coin in the example app
555
+ - decoding `BetResultEvent` and PvP events into a persistent event log
556
+ - parsing `BetResultEvent.game_details` with `parseGameDetails`
557
+
558
+ Run it from the repo root with:
559
+
560
+ ```bash
561
+ npm --prefix examples/game-integration install
562
+ npm --prefix examples/game-integration run dev
563
+ ```