@suigar/sdk 2.0.0-beta.7 → 2.0.0-beta.8

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,5 +1,19 @@
1
1
  # @suigar/sdk
2
2
 
3
+ ## 2.0.0-beta.8
4
+
5
+ ### Patch Changes
6
+
7
+ - 0292edb: Rename transaction builder option `owner` to `playerAddress` and remove the separate `sender` option so all game transactions use a single explicit player address.
8
+ - 20311be: Improve the public JSDoc for `parseGameDetails`, `toBigInt`, and `toU8` so the
9
+ generated API surface explains their coercion, validation, and decoding
10
+ behavior more clearly.
11
+ - a2aa324: Update PvP coinflip lookup helpers to use bulk object reads for unresolved lobby discovery and support forwarded lookup options.
12
+ - Make `getPvPCoinflipGames()` parse bulk `client.core.getObjects()` results instead of resolving each game individually.
13
+ - Skip per-object fetch or parse failures by default and continue supporting strict rejection with `throwOnError: true`.
14
+ - Forward supported lookup options such as `signal` through `getPvPCoinflipGames()` and `resolvePvPConflipGame(gameId, options?)`.
15
+ - Update tests, README guidance, and repo-local PvP skill documentation to match the current client behavior.
16
+
3
17
  ## 2.0.0-beta.7
4
18
 
5
19
  ### Patch Changes
package/README.md CHANGED
@@ -92,7 +92,7 @@ const client = new SuiGrpcClient({
92
92
  }).$extend(suigar());
93
93
 
94
94
  const tx = client.suigar.tx.createBetTransaction('coinflip', {
95
- owner: '0x123',
95
+ playerAddress: '0x123',
96
96
  coinType: '0x2::sui::SUI',
97
97
  stake: 1_000_000_000n,
98
98
  side: 'heads',
@@ -200,17 +200,20 @@ const base64 = await client.suigar.serializeTransactionToBase64(tx);
200
200
  Lists unresolved PvP coinflip games from the configured PvP registry.
201
201
 
202
202
  This reads the registry dynamic fields for the active network and resolves each
203
- entry into parsed game state through `resolvePvPConflipGame()`. Registry
203
+ entry into parsed game state through a bulk `client.core.getObjects()` lookup. Registry
204
204
  membership is the unresolved-state signal: once a match is joined and resolved,
205
205
  the Move flow removes it from the registry and deletes the live `Game` object.
206
206
 
207
207
  Use this when a product needs the current set of open PvP coinflip matches for
208
208
  browsing or lobby views.
209
209
 
210
- By default, failures to resolve an individual game are skipped so one broken or
210
+ By default, per-object fetch or parse failures are skipped so one broken or
211
211
  already-deleted registry entry does not reject the full lookup. Pass
212
212
  `throwOnError: true` if you want the call to reject instead.
213
213
 
214
+ Any supported `listDynamicFields()` options such as `limit`, `cursor`, or
215
+ `signal` can be passed through `options`.
216
+
214
217
  ```ts
215
218
  const games = await client.suigar.getPvPCoinflipGames({ limit: 20 });
216
219
 
@@ -227,14 +230,15 @@ const games = await client.suigar.getPvPCoinflipGames({
227
230
  });
228
231
  ```
229
232
 
230
- ### `resolvePvPConflipGame(gameId)`
233
+ ### `resolvePvPConflipGame(gameId, options?)`
231
234
 
232
235
  Fetches a PvP coinflip game object from chain and parses it into the SDK's
233
236
  normalized runtime shape.
234
237
 
235
238
  This requires the object's `content`, decodes it with the generated
236
239
  `PvPCoinflipGame` parser, and normalizes the generic coin type into a standard
237
- struct tag string.
240
+ struct tag string. You can optionally pass through `getObject()` options such as
241
+ `signal`.
238
242
 
239
243
  Use this when a product needs the live onchain match state for a specific
240
244
  pending match before rendering join or cancel actions, or inspecting the stake
@@ -249,6 +253,14 @@ console.log(game.stake_per_player);
249
253
  console.log(game.is_private);
250
254
  ```
251
255
 
256
+ ```ts
257
+ const controller = new AbortController();
258
+
259
+ const game = await client.suigar.resolvePvPConflipGame('0xGAME_ID', {
260
+ signal: controller.signal,
261
+ });
262
+ ```
263
+
252
264
  > **Note:**
253
265
  >
254
266
  > - it throws if the object response does not include decodable `content`
@@ -274,7 +286,7 @@ Use `createBetTransaction(gameId, options)` for:
274
286
 
275
287
  ```ts
276
288
  const tx = client.suigar.tx.createBetTransaction('coinflip', {
277
- owner: '0x123',
289
+ playerAddress: '0x123',
278
290
  coinType: '0x2::sui::SUI',
279
291
  stake: 1_000_000_000n,
280
292
  side: 'tails',
@@ -283,14 +295,13 @@ const tx = client.suigar.tx.createBetTransaction('coinflip', {
283
295
 
284
296
  Shared option shape:
285
297
 
286
- - `owner: string`
298
+ - `playerAddress: string`
287
299
  - `coinType: string`
288
300
  - `stake: number | bigint`
289
301
  - `cashStake?: number | bigint`
290
302
  - `betCount?: number | bigint`
291
303
  - `metadata?: Record<string, string | number | boolean | bigint | Uint8Array | number[] | null | undefined>`
292
304
  - `gasBudget?: number | bigint`
293
- - `sender?: string`
294
305
  - `allowGasCoinShortcut?: boolean`
295
306
 
296
307
  Shared behavior:
@@ -298,12 +309,11 @@ Shared behavior:
298
309
  - `stake` is the logical stake passed into the Move call
299
310
  - `cashStake` controls the withdrawn balance and defaults to `stake`
300
311
  - `betCount` defaults to `1`
301
- - `sender` overrides the transaction sender
302
312
  - `metadata` is encoded into `keys` and `values` byte arrays
303
313
  - `partner` configured via `suigar({ partner })` is appended automatically to metadata as the partner wallet address
304
314
  - `metadata.partner` and `metadata.referrer` are reserved and ignored with a warning
305
315
  - the SDK resolves the price info object from the configured supported-coin mapping
306
- - the reward object is transferred back to `owner`
316
+ - the reward object is transferred back to `playerAddress`
307
317
 
308
318
  Per-game options:
309
319
 
@@ -317,14 +327,14 @@ Examples:
317
327
 
318
328
  ```ts
319
329
  const limboTx = client.suigar.tx.createBetTransaction('limbo', {
320
- owner: '0x123',
330
+ playerAddress: '0x123',
321
331
  coinType: '0x2::sui::SUI',
322
332
  stake: 1_000_000_000n,
323
333
  targetMultiplier: 2.5,
324
334
  });
325
335
 
326
336
  const rangeTx = client.suigar.tx.createBetTransaction('range', {
327
- owner: '0x123',
337
+ playerAddress: '0x123',
328
338
  coinType: '0x2::sui::SUI',
329
339
  stake: 1_000_000_000n,
330
340
  leftPoint: 25,
@@ -359,7 +369,7 @@ Create:
359
369
 
360
370
  ```ts
361
371
  const tx = client.suigar.tx.createPvPCoinflipTransaction('create', {
362
- owner: '0x123',
372
+ playerAddress: '0x123',
363
373
  coinType: '0x2::sui::SUI',
364
374
  stake: 1_000_000_000n,
365
375
  side: 'heads',
@@ -371,7 +381,7 @@ Join:
371
381
 
372
382
  ```ts
373
383
  const tx = client.suigar.tx.createPvPCoinflipTransaction('join', {
374
- owner: '0x123',
384
+ playerAddress: '0x123',
375
385
  coinType: '0x2::sui::SUI',
376
386
  gameId: '0xGAME_ID',
377
387
  });
@@ -381,7 +391,7 @@ Cancel:
381
391
 
382
392
  ```ts
383
393
  const tx = client.suigar.tx.createPvPCoinflipTransaction('cancel', {
384
- owner: '0x123',
394
+ playerAddress: '0x123',
385
395
  coinType: '0x2::sui::SUI',
386
396
  gameId: '0xGAME_ID',
387
397
  });
@@ -392,11 +402,10 @@ id for `coinType`.
392
402
 
393
403
  PvP shared options:
394
404
 
395
- - `owner: string`
405
+ - `playerAddress: string`
396
406
  - `coinType: string`
397
407
  - `metadata?: Record<string, string | number | boolean | bigint | Uint8Array | number[] | null | undefined>`
398
408
  - `gasBudget?: number | bigint`
399
- - `sender?: string`
400
409
  - `allowGasCoinShortcut?: boolean`
401
410
 
402
411
  Action-specific options:
@@ -542,7 +551,7 @@ npm test
542
551
 
543
552
  ## Example App
544
553
 
545
- This repository now includes a Next.js integration example in [examples/game-integration](/Users/lucas/Documents/Github/suigar-sdk/examples/game-integration).
554
+ This repository includes a Next.js integration example in [examples/game-integration](examples/game-integration).
546
555
 
547
556
  It demonstrates:
548
557
 
@@ -1,3 +1,5 @@
1
+ import { Transaction } from '@mysten/sui/transactions';
2
+
1
3
  declare const GAMES: readonly ["coinflip", "limbo", "plinko", "pvp-coinflip", "range", "wheel"];
2
4
  type Game = (typeof GAMES)[number];
3
5
  type StandardGame = Exclude<Game, PvPGame>;
@@ -26,22 +28,27 @@ type SuigarConfig = {
26
28
  priceInfoObjectIds: SuigarPriceInfoObjectId;
27
29
  };
28
30
 
29
- type SharedBetTransactionOptions = {
31
+ type WithGasBudget = {
32
+ gasBudget?: Parameters<Transaction['setGasBudgetIfNotSet']>[0];
33
+ };
34
+ type WithThrowOnError<T = object> = T & {
35
+ throwOnError?: boolean;
36
+ };
37
+ type BaseTransactionOptions = WithGasBudget & {
30
38
  config: SuigarConfig;
31
- owner: string;
39
+ playerAddress: string;
40
+ };
41
+ type CoinTransactionOptions = {
32
42
  coinType: string;
33
- stake: number | bigint;
34
- cashStake?: number | bigint;
35
- betCount?: number | bigint;
36
43
  metadata?: BetMetadataInput;
37
- gasBudget?: number | bigint;
38
- sender?: string;
39
44
  allowGasCoinShortcut?: boolean;
40
45
  };
41
-
42
- type WithThrowOnError<T = object> = T & {
43
- throwOnError?: boolean;
46
+ type StakeTransactionOptions = {
47
+ stake: number | bigint;
48
+ cashStake?: number | bigint;
49
+ betCount?: number | bigint;
44
50
  };
51
+ type SharedBetTransactionOptions = BaseTransactionOptions & CoinTransactionOptions & StakeTransactionOptions;
45
52
  type BuildCoinflipTransactionOptions = SharedBetTransactionOptions & {
46
53
  side: CoinSide;
47
54
  };
@@ -62,17 +69,9 @@ type BuildWheelTransactionOptions = SharedBetTransactionOptions & {
62
69
  configId: number;
63
70
  };
64
71
  type PvPCoinflipAction = 'create' | 'join' | 'cancel';
65
- type SharedPvPCoinflipTransactionOptions = {
66
- config: SuigarConfig;
67
- owner: string;
68
- coinType: string;
69
- metadata?: BetMetadataInput;
70
- gasBudget?: number | bigint;
71
- sender?: string;
72
- allowGasCoinShortcut?: boolean;
73
- };
72
+ type SharedPvPCoinflipTransactionOptions = BaseTransactionOptions & CoinTransactionOptions;
74
73
  type BuildCreatePvPCoinflipTransactionOptions = SharedPvPCoinflipTransactionOptions & {
75
- stake: number | bigint;
74
+ stake: StakeTransactionOptions['stake'];
76
75
  side: CoinSide;
77
76
  isPrivate?: boolean;
78
77
  };
@@ -1,3 +1,5 @@
1
+ import { Transaction } from '@mysten/sui/transactions';
2
+
1
3
  declare const GAMES: readonly ["coinflip", "limbo", "plinko", "pvp-coinflip", "range", "wheel"];
2
4
  type Game = (typeof GAMES)[number];
3
5
  type StandardGame = Exclude<Game, PvPGame>;
@@ -26,22 +28,27 @@ type SuigarConfig = {
26
28
  priceInfoObjectIds: SuigarPriceInfoObjectId;
27
29
  };
28
30
 
29
- type SharedBetTransactionOptions = {
31
+ type WithGasBudget = {
32
+ gasBudget?: Parameters<Transaction['setGasBudgetIfNotSet']>[0];
33
+ };
34
+ type WithThrowOnError<T = object> = T & {
35
+ throwOnError?: boolean;
36
+ };
37
+ type BaseTransactionOptions = WithGasBudget & {
30
38
  config: SuigarConfig;
31
- owner: string;
39
+ playerAddress: string;
40
+ };
41
+ type CoinTransactionOptions = {
32
42
  coinType: string;
33
- stake: number | bigint;
34
- cashStake?: number | bigint;
35
- betCount?: number | bigint;
36
43
  metadata?: BetMetadataInput;
37
- gasBudget?: number | bigint;
38
- sender?: string;
39
44
  allowGasCoinShortcut?: boolean;
40
45
  };
41
-
42
- type WithThrowOnError<T = object> = T & {
43
- throwOnError?: boolean;
46
+ type StakeTransactionOptions = {
47
+ stake: number | bigint;
48
+ cashStake?: number | bigint;
49
+ betCount?: number | bigint;
44
50
  };
51
+ type SharedBetTransactionOptions = BaseTransactionOptions & CoinTransactionOptions & StakeTransactionOptions;
45
52
  type BuildCoinflipTransactionOptions = SharedBetTransactionOptions & {
46
53
  side: CoinSide;
47
54
  };
@@ -62,17 +69,9 @@ type BuildWheelTransactionOptions = SharedBetTransactionOptions & {
62
69
  configId: number;
63
70
  };
64
71
  type PvPCoinflipAction = 'create' | 'join' | 'cancel';
65
- type SharedPvPCoinflipTransactionOptions = {
66
- config: SuigarConfig;
67
- owner: string;
68
- coinType: string;
69
- metadata?: BetMetadataInput;
70
- gasBudget?: number | bigint;
71
- sender?: string;
72
- allowGasCoinShortcut?: boolean;
73
- };
72
+ type SharedPvPCoinflipTransactionOptions = BaseTransactionOptions & CoinTransactionOptions;
74
73
  type BuildCreatePvPCoinflipTransactionOptions = SharedPvPCoinflipTransactionOptions & {
75
- stake: number | bigint;
74
+ stake: StakeTransactionOptions['stake'];
76
75
  side: CoinSide;
77
76
  isPrivate?: boolean;
78
77
  };
package/dist/games.d.cts CHANGED
@@ -1 +1,2 @@
1
- export { h as BuildCancelPvPCoinflipTransactionOptions, B as BuildCoinflipTransactionOptions, i as BuildCreatePvPCoinflipTransactionOptions, j as BuildJoinPvPCoinflipTransactionOptions, b as BuildLimboTransactionOptions, c as BuildPlinkoTransactionOptions, d as BuildRangeTransactionOptions, a as BuildWheelTransactionOptions, C as CoinSide, P as PvPCoinflipAction } from './games--Haw_z7M.cjs';
1
+ export { h as BuildCancelPvPCoinflipTransactionOptions, B as BuildCoinflipTransactionOptions, i as BuildCreatePvPCoinflipTransactionOptions, j as BuildJoinPvPCoinflipTransactionOptions, b as BuildLimboTransactionOptions, c as BuildPlinkoTransactionOptions, d as BuildRangeTransactionOptions, a as BuildWheelTransactionOptions, C as CoinSide, P as PvPCoinflipAction } from './games-BccpPyWd.cjs';
2
+ import '@mysten/sui/transactions';
package/dist/games.d.ts CHANGED
@@ -1 +1,2 @@
1
- export { h as BuildCancelPvPCoinflipTransactionOptions, B as BuildCoinflipTransactionOptions, i as BuildCreatePvPCoinflipTransactionOptions, j as BuildJoinPvPCoinflipTransactionOptions, b as BuildLimboTransactionOptions, c as BuildPlinkoTransactionOptions, d as BuildRangeTransactionOptions, a as BuildWheelTransactionOptions, C as CoinSide, P as PvPCoinflipAction } from './games--Haw_z7M.js';
1
+ export { h as BuildCancelPvPCoinflipTransactionOptions, B as BuildCoinflipTransactionOptions, i as BuildCreatePvPCoinflipTransactionOptions, j as BuildJoinPvPCoinflipTransactionOptions, b as BuildLimboTransactionOptions, c as BuildPlinkoTransactionOptions, d as BuildRangeTransactionOptions, a as BuildWheelTransactionOptions, C as CoinSide, P as PvPCoinflipAction } from './games-BccpPyWd.js';
2
+ import '@mysten/sui/transactions';
package/dist/index.cjs CHANGED
@@ -413,20 +413,18 @@ var Float = new MoveStruct({ name: `${$moduleName2}::Float`, fields: {
413
413
  function createBaseGameTransaction({
414
414
  config,
415
415
  game,
416
- owner,
417
- sender,
416
+ playerAddress,
418
417
  gasBudget
419
418
  }) {
420
419
  assertConfiguredBetGame(config, game);
421
420
  const tx = new transactions.Transaction();
422
- tx.setSenderIfNotSet(utils.normalizeSuiAddress(sender ?? owner));
421
+ tx.setSenderIfNotSet(utils.normalizeSuiAddress(playerAddress));
423
422
  tx.setGasBudgetIfNotSet(gasBudget ?? DEFAULT_GAS_BUDGET_MIST);
424
423
  return tx;
425
424
  }
426
425
  function buildSharedStandardGameBetCall({
427
426
  config,
428
- owner,
429
- sender,
427
+ playerAddress,
430
428
  coinType,
431
429
  stake,
432
430
  cashStake,
@@ -437,7 +435,7 @@ function buildSharedStandardGameBetCall({
437
435
  buildRewardCoin
438
436
  }) {
439
437
  return (tx) => {
440
- const normalizedOwner = utils.normalizeSuiAddress(sender ?? owner);
438
+ const normalizedPlayerAddress = utils.normalizeSuiAddress(playerAddress);
441
439
  const normalizedCoinType = utils.normalizeStructTag(coinType);
442
440
  const resolvedStake = toBigInt(stake);
443
441
  const resolvedCashStake = toBigInt(cashStake ?? stake);
@@ -455,7 +453,7 @@ function buildSharedStandardGameBetCall({
455
453
  const rewardCoin = buildRewardCoin({
456
454
  tx,
457
455
  config,
458
- owner: normalizedOwner,
456
+ playerAddress: normalizedPlayerAddress,
459
457
  coinType: normalizedCoinType,
460
458
  stake: resolvedStake,
461
459
  cashStake: resolvedCashStake,
@@ -464,7 +462,7 @@ function buildSharedStandardGameBetCall({
464
462
  priceInfoObjectId,
465
463
  betCoin
466
464
  });
467
- tx.transferObjects([rewardCoin], tx.pure.address(normalizedOwner));
465
+ tx.transferObjects([rewardCoin], tx.pure.address(normalizedPlayerAddress));
468
466
  return rewardCoin;
469
467
  };
470
468
  }
@@ -1019,39 +1017,53 @@ var SuigarClient = class {
1019
1017
  * Lists unresolved PvP coinflip games from the configured registry and resolves
1020
1018
  * each entry into parsed onchain game state.
1021
1019
  *
1022
- * This fetches dynamic fields from the PvP coinflip registry object, then loads
1023
- * each referenced game object through `resolvePvPConflipGame()`. Registry
1020
+ * This fetches dynamic fields from the PvP coinflip registry object, then bulk
1021
+ * loads the referenced game objects through `client.core.getObjects()`. Registry
1024
1022
  * membership is the unresolved-state signal: when a game is joined and resolved,
1025
1023
  * the Move flow removes it from the registry and deletes the live `Game` object.
1026
1024
  * Use this when a product needs the current set of open PvP coinflip matches for
1027
1025
  * browsing or lobby views.
1028
1026
  *
1029
1027
  * @param options Optional dynamic field pagination forwarded to `listDynamicFields()`, excluding `parentId`.
1030
- * Pass `throwOnError: true` to fail the whole lookup when any referenced game
1031
- * cannot be resolved. By default, failed game resolutions are skipped and only
1032
- * successfully parsed unresolved games are returned.
1028
+ * Supported options such as `limit`, `cursor`, and `signal` are forwarded to the
1029
+ * underlying lookup calls. Pass `throwOnError: true` to fail the whole lookup
1030
+ * when any referenced game object cannot be fetched or parsed. By default,
1031
+ * failed per-object lookups are skipped and only successfully parsed unresolved
1032
+ * games are returned.
1033
1033
  * @returns Parsed unresolved PvP coinflip game objects for the requested
1034
- * registry page. When `throwOnError` is `false`, entries that fail
1035
- * `resolvePvPConflipGame()` are omitted from the returned array.
1034
+ * registry page. When `throwOnError` is `false`, entries that fail object fetch
1035
+ * or parse are omitted from the returned array.
1036
1036
  */
1037
1037
  async getPvPCoinflipGames(options = {
1038
1038
  limit: 50
1039
1039
  }) {
1040
1040
  const { throwOnError = false, ...listOptions } = options;
1041
1041
  const { dynamicFields } = await this.#client.core.listDynamicFields({
1042
- parentId: this.#config.registryIds.pvpCoinflip,
1043
- ...listOptions
1042
+ ...listOptions,
1043
+ parentId: this.#config.registryIds.pvpCoinflip
1044
+ });
1045
+ const { objects } = await this.#client.core.getObjects({
1046
+ objectIds: dynamicFields.map(({ childId }) => childId),
1047
+ signal: listOptions.signal,
1048
+ include: {
1049
+ content: true
1050
+ }
1051
+ });
1052
+ const resolvedGames = objects.map((object) => {
1053
+ try {
1054
+ return this.#resolvePvPCoinflipGameObject(object);
1055
+ } catch (error) {
1056
+ return error instanceof Error ? error : new Error(String(error));
1057
+ }
1044
1058
  });
1045
1059
  if (throwOnError) {
1046
- return Promise.all(
1047
- dynamicFields.map(({ childId }) => this.resolvePvPConflipGame(childId))
1048
- );
1060
+ const firstError = resolvedGames.find((game) => game instanceof Error);
1061
+ if (firstError) {
1062
+ throw firstError;
1063
+ }
1049
1064
  }
1050
- const settledGames = await Promise.allSettled(
1051
- dynamicFields.map(({ childId }) => this.resolvePvPConflipGame(childId))
1052
- );
1053
- return settledGames.flatMap(
1054
- (result) => result.status === "fulfilled" ? [result.value] : []
1065
+ return resolvedGames.flatMap(
1066
+ (game) => game instanceof Error ? [] : [game]
1055
1067
  );
1056
1068
  }
1057
1069
  /**
@@ -1065,21 +1077,19 @@ var SuigarClient = class {
1065
1077
  * of a specific PvP coinflip match before rendering join, cancel, or result UI.
1066
1078
  *
1067
1079
  * @param gameId On-chain object id of the PvP coinflip game.
1080
+ * @param options Optional `getObject()` options forwarded to the underlying
1081
+ * client lookup, excluding `objectId` and `include`. Supported options include
1082
+ * `signal`.
1068
1083
  * @returns Parsed PvP coinflip game state with a normalized `coinType`.
1069
1084
  * @throws Error If the object cannot be decoded because no content was returned.
1070
1085
  */
1071
- async resolvePvPConflipGame(gameId) {
1086
+ async resolvePvPConflipGame(gameId, options = {}) {
1072
1087
  const { object } = await this.#client.core.getObject({
1088
+ ...options,
1073
1089
  objectId: gameId,
1074
1090
  include: { content: true }
1075
1091
  });
1076
- if (!object.content) {
1077
- throw new Error("Unable to resolve PvP coinflip from game object");
1078
- }
1079
- return {
1080
- ...Game.parse(object.content),
1081
- coinType: utils.normalizeStructTag(utils.parseStructTag(object.type).typeParams[0])
1082
- };
1092
+ return this.#resolvePvPCoinflipGameObject(object);
1083
1093
  }
1084
1094
  /**
1085
1095
  * BCS struct constructors for decoding on-chain objects and events related to Suigar games.
@@ -1209,6 +1219,20 @@ var SuigarClient = class {
1209
1219
  });
1210
1220
  };
1211
1221
  }
1222
+ #resolvePvPCoinflipGameObject(object) {
1223
+ if (object instanceof Error) {
1224
+ throw object;
1225
+ }
1226
+ if (!object.content) {
1227
+ throw new Error(
1228
+ "Unable to resolve PvP coinflip game from retrieved object"
1229
+ );
1230
+ }
1231
+ return {
1232
+ ...Game.parse(object.content),
1233
+ coinType: utils.normalizeStructTag(utils.parseStructTag(object.type).typeParams[0])
1234
+ };
1235
+ }
1212
1236
  };
1213
1237
 
1214
1238
  exports.SuigarClient = SuigarClient;
package/dist/index.d.cts CHANGED
@@ -2,7 +2,7 @@ import { M as MoveStruct } from './index-jwSXA8q3.cjs';
2
2
  import * as _mysten_bcs from '@mysten/bcs';
3
3
  import { ClientWithCoreApi, SuiClientTypes } from '@mysten/sui/client';
4
4
  import { Transaction, BuildTransactionOptions } from '@mysten/sui/transactions';
5
- import { S as StandardGame, B as BuildCoinflipTransactionOptions, a as BuildWheelTransactionOptions, b as BuildLimboTransactionOptions, c as BuildPlinkoTransactionOptions, d as BuildRangeTransactionOptions, e as SuigarConfig, W as WithThrowOnError, P as PvPCoinflipAction, f as BuildPvPCoinflipTransactionOptions, g as SuigarExtensionOptions } from './games--Haw_z7M.cjs';
5
+ import { S as StandardGame, B as BuildCoinflipTransactionOptions, a as BuildWheelTransactionOptions, b as BuildLimboTransactionOptions, c as BuildPlinkoTransactionOptions, d as BuildRangeTransactionOptions, e as SuigarConfig, W as WithThrowOnError, P as PvPCoinflipAction, f as BuildPvPCoinflipTransactionOptions, g as SuigarExtensionOptions } from './games-BccpPyWd.cjs';
6
6
  import '@mysten/sui/bcs';
7
7
 
8
8
  type WithoutConfig<T> = Omit<T, 'config'>;
@@ -44,20 +44,22 @@ declare class SuigarClient {
44
44
  * Lists unresolved PvP coinflip games from the configured registry and resolves
45
45
  * each entry into parsed onchain game state.
46
46
  *
47
- * This fetches dynamic fields from the PvP coinflip registry object, then loads
48
- * each referenced game object through `resolvePvPConflipGame()`. Registry
47
+ * This fetches dynamic fields from the PvP coinflip registry object, then bulk
48
+ * loads the referenced game objects through `client.core.getObjects()`. Registry
49
49
  * membership is the unresolved-state signal: when a game is joined and resolved,
50
50
  * the Move flow removes it from the registry and deletes the live `Game` object.
51
51
  * Use this when a product needs the current set of open PvP coinflip matches for
52
52
  * browsing or lobby views.
53
53
  *
54
54
  * @param options Optional dynamic field pagination forwarded to `listDynamicFields()`, excluding `parentId`.
55
- * Pass `throwOnError: true` to fail the whole lookup when any referenced game
56
- * cannot be resolved. By default, failed game resolutions are skipped and only
57
- * successfully parsed unresolved games are returned.
55
+ * Supported options such as `limit`, `cursor`, and `signal` are forwarded to the
56
+ * underlying lookup calls. Pass `throwOnError: true` to fail the whole lookup
57
+ * when any referenced game object cannot be fetched or parsed. By default,
58
+ * failed per-object lookups are skipped and only successfully parsed unresolved
59
+ * games are returned.
58
60
  * @returns Parsed unresolved PvP coinflip game objects for the requested
59
- * registry page. When `throwOnError` is `false`, entries that fail
60
- * `resolvePvPConflipGame()` are omitted from the returned array.
61
+ * registry page. When `throwOnError` is `false`, entries that fail object fetch
62
+ * or parse are omitted from the returned array.
61
63
  */
62
64
  getPvPCoinflipGames(options?: WithThrowOnError<Omit<SuiClientTypes.ListDynamicFieldsOptions, 'parentId'>>): Promise<{
63
65
  coinType: string;
@@ -90,10 +92,13 @@ declare class SuigarClient {
90
92
  * of a specific PvP coinflip match before rendering join, cancel, or result UI.
91
93
  *
92
94
  * @param gameId On-chain object id of the PvP coinflip game.
95
+ * @param options Optional `getObject()` options forwarded to the underlying
96
+ * client lookup, excluding `objectId` and `include`. Supported options include
97
+ * `signal`.
93
98
  * @returns Parsed PvP coinflip game state with a normalized `coinType`.
94
99
  * @throws Error If the object cannot be decoded because no content was returned.
95
100
  */
96
- resolvePvPConflipGame(gameId: string): Promise<{
101
+ resolvePvPConflipGame(gameId: string, options?: Omit<SuiClientTypes.GetObjectOptions, 'objectId' | 'include'>): Promise<{
97
102
  coinType: string;
98
103
  id: string;
99
104
  creator: string;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { M as MoveStruct } from './index-jwSXA8q3.js';
2
2
  import * as _mysten_bcs from '@mysten/bcs';
3
3
  import { ClientWithCoreApi, SuiClientTypes } from '@mysten/sui/client';
4
4
  import { Transaction, BuildTransactionOptions } from '@mysten/sui/transactions';
5
- import { S as StandardGame, B as BuildCoinflipTransactionOptions, a as BuildWheelTransactionOptions, b as BuildLimboTransactionOptions, c as BuildPlinkoTransactionOptions, d as BuildRangeTransactionOptions, e as SuigarConfig, W as WithThrowOnError, P as PvPCoinflipAction, f as BuildPvPCoinflipTransactionOptions, g as SuigarExtensionOptions } from './games--Haw_z7M.js';
5
+ import { S as StandardGame, B as BuildCoinflipTransactionOptions, a as BuildWheelTransactionOptions, b as BuildLimboTransactionOptions, c as BuildPlinkoTransactionOptions, d as BuildRangeTransactionOptions, e as SuigarConfig, W as WithThrowOnError, P as PvPCoinflipAction, f as BuildPvPCoinflipTransactionOptions, g as SuigarExtensionOptions } from './games-BccpPyWd.js';
6
6
  import '@mysten/sui/bcs';
7
7
 
8
8
  type WithoutConfig<T> = Omit<T, 'config'>;
@@ -44,20 +44,22 @@ declare class SuigarClient {
44
44
  * Lists unresolved PvP coinflip games from the configured registry and resolves
45
45
  * each entry into parsed onchain game state.
46
46
  *
47
- * This fetches dynamic fields from the PvP coinflip registry object, then loads
48
- * each referenced game object through `resolvePvPConflipGame()`. Registry
47
+ * This fetches dynamic fields from the PvP coinflip registry object, then bulk
48
+ * loads the referenced game objects through `client.core.getObjects()`. Registry
49
49
  * membership is the unresolved-state signal: when a game is joined and resolved,
50
50
  * the Move flow removes it from the registry and deletes the live `Game` object.
51
51
  * Use this when a product needs the current set of open PvP coinflip matches for
52
52
  * browsing or lobby views.
53
53
  *
54
54
  * @param options Optional dynamic field pagination forwarded to `listDynamicFields()`, excluding `parentId`.
55
- * Pass `throwOnError: true` to fail the whole lookup when any referenced game
56
- * cannot be resolved. By default, failed game resolutions are skipped and only
57
- * successfully parsed unresolved games are returned.
55
+ * Supported options such as `limit`, `cursor`, and `signal` are forwarded to the
56
+ * underlying lookup calls. Pass `throwOnError: true` to fail the whole lookup
57
+ * when any referenced game object cannot be fetched or parsed. By default,
58
+ * failed per-object lookups are skipped and only successfully parsed unresolved
59
+ * games are returned.
58
60
  * @returns Parsed unresolved PvP coinflip game objects for the requested
59
- * registry page. When `throwOnError` is `false`, entries that fail
60
- * `resolvePvPConflipGame()` are omitted from the returned array.
61
+ * registry page. When `throwOnError` is `false`, entries that fail object fetch
62
+ * or parse are omitted from the returned array.
61
63
  */
62
64
  getPvPCoinflipGames(options?: WithThrowOnError<Omit<SuiClientTypes.ListDynamicFieldsOptions, 'parentId'>>): Promise<{
63
65
  coinType: string;
@@ -90,10 +92,13 @@ declare class SuigarClient {
90
92
  * of a specific PvP coinflip match before rendering join, cancel, or result UI.
91
93
  *
92
94
  * @param gameId On-chain object id of the PvP coinflip game.
95
+ * @param options Optional `getObject()` options forwarded to the underlying
96
+ * client lookup, excluding `objectId` and `include`. Supported options include
97
+ * `signal`.
93
98
  * @returns Parsed PvP coinflip game state with a normalized `coinType`.
94
99
  * @throws Error If the object cannot be decoded because no content was returned.
95
100
  */
96
- resolvePvPConflipGame(gameId: string): Promise<{
101
+ resolvePvPConflipGame(gameId: string, options?: Omit<SuiClientTypes.GetObjectOptions, 'objectId' | 'include'>): Promise<{
97
102
  coinType: string;
98
103
  id: string;
99
104
  creator: string;
package/dist/index.js CHANGED
@@ -225,20 +225,18 @@ function play(options) {
225
225
  function createBaseGameTransaction({
226
226
  config,
227
227
  game,
228
- owner,
229
- sender,
228
+ playerAddress,
230
229
  gasBudget
231
230
  }) {
232
231
  assertConfiguredBetGame(config, game);
233
232
  const tx = new Transaction();
234
- tx.setSenderIfNotSet(normalizeSuiAddress(sender ?? owner));
233
+ tx.setSenderIfNotSet(normalizeSuiAddress(playerAddress));
235
234
  tx.setGasBudgetIfNotSet(gasBudget ?? DEFAULT_GAS_BUDGET_MIST);
236
235
  return tx;
237
236
  }
238
237
  function buildSharedStandardGameBetCall({
239
238
  config,
240
- owner,
241
- sender,
239
+ playerAddress,
242
240
  coinType,
243
241
  stake,
244
242
  cashStake,
@@ -249,7 +247,7 @@ function buildSharedStandardGameBetCall({
249
247
  buildRewardCoin
250
248
  }) {
251
249
  return (tx) => {
252
- const normalizedOwner = normalizeSuiAddress(sender ?? owner);
250
+ const normalizedPlayerAddress = normalizeSuiAddress(playerAddress);
253
251
  const normalizedCoinType = normalizeStructTag(coinType);
254
252
  const resolvedStake = toBigInt(stake);
255
253
  const resolvedCashStake = toBigInt(cashStake ?? stake);
@@ -267,7 +265,7 @@ function buildSharedStandardGameBetCall({
267
265
  const rewardCoin = buildRewardCoin({
268
266
  tx,
269
267
  config,
270
- owner: normalizedOwner,
268
+ playerAddress: normalizedPlayerAddress,
271
269
  coinType: normalizedCoinType,
272
270
  stake: resolvedStake,
273
271
  cashStake: resolvedCashStake,
@@ -276,7 +274,7 @@ function buildSharedStandardGameBetCall({
276
274
  priceInfoObjectId,
277
275
  betCoin
278
276
  });
279
- tx.transferObjects([rewardCoin], tx.pure.address(normalizedOwner));
277
+ tx.transferObjects([rewardCoin], tx.pure.address(normalizedPlayerAddress));
280
278
  return rewardCoin;
281
279
  };
282
280
  }
@@ -831,39 +829,53 @@ var SuigarClient = class {
831
829
  * Lists unresolved PvP coinflip games from the configured registry and resolves
832
830
  * each entry into parsed onchain game state.
833
831
  *
834
- * This fetches dynamic fields from the PvP coinflip registry object, then loads
835
- * each referenced game object through `resolvePvPConflipGame()`. Registry
832
+ * This fetches dynamic fields from the PvP coinflip registry object, then bulk
833
+ * loads the referenced game objects through `client.core.getObjects()`. Registry
836
834
  * membership is the unresolved-state signal: when a game is joined and resolved,
837
835
  * the Move flow removes it from the registry and deletes the live `Game` object.
838
836
  * Use this when a product needs the current set of open PvP coinflip matches for
839
837
  * browsing or lobby views.
840
838
  *
841
839
  * @param options Optional dynamic field pagination forwarded to `listDynamicFields()`, excluding `parentId`.
842
- * Pass `throwOnError: true` to fail the whole lookup when any referenced game
843
- * cannot be resolved. By default, failed game resolutions are skipped and only
844
- * successfully parsed unresolved games are returned.
840
+ * Supported options such as `limit`, `cursor`, and `signal` are forwarded to the
841
+ * underlying lookup calls. Pass `throwOnError: true` to fail the whole lookup
842
+ * when any referenced game object cannot be fetched or parsed. By default,
843
+ * failed per-object lookups are skipped and only successfully parsed unresolved
844
+ * games are returned.
845
845
  * @returns Parsed unresolved PvP coinflip game objects for the requested
846
- * registry page. When `throwOnError` is `false`, entries that fail
847
- * `resolvePvPConflipGame()` are omitted from the returned array.
846
+ * registry page. When `throwOnError` is `false`, entries that fail object fetch
847
+ * or parse are omitted from the returned array.
848
848
  */
849
849
  async getPvPCoinflipGames(options = {
850
850
  limit: 50
851
851
  }) {
852
852
  const { throwOnError = false, ...listOptions } = options;
853
853
  const { dynamicFields } = await this.#client.core.listDynamicFields({
854
- parentId: this.#config.registryIds.pvpCoinflip,
855
- ...listOptions
854
+ ...listOptions,
855
+ parentId: this.#config.registryIds.pvpCoinflip
856
+ });
857
+ const { objects } = await this.#client.core.getObjects({
858
+ objectIds: dynamicFields.map(({ childId }) => childId),
859
+ signal: listOptions.signal,
860
+ include: {
861
+ content: true
862
+ }
863
+ });
864
+ const resolvedGames = objects.map((object) => {
865
+ try {
866
+ return this.#resolvePvPCoinflipGameObject(object);
867
+ } catch (error) {
868
+ return error instanceof Error ? error : new Error(String(error));
869
+ }
856
870
  });
857
871
  if (throwOnError) {
858
- return Promise.all(
859
- dynamicFields.map(({ childId }) => this.resolvePvPConflipGame(childId))
860
- );
872
+ const firstError = resolvedGames.find((game) => game instanceof Error);
873
+ if (firstError) {
874
+ throw firstError;
875
+ }
861
876
  }
862
- const settledGames = await Promise.allSettled(
863
- dynamicFields.map(({ childId }) => this.resolvePvPConflipGame(childId))
864
- );
865
- return settledGames.flatMap(
866
- (result) => result.status === "fulfilled" ? [result.value] : []
877
+ return resolvedGames.flatMap(
878
+ (game) => game instanceof Error ? [] : [game]
867
879
  );
868
880
  }
869
881
  /**
@@ -877,21 +889,19 @@ var SuigarClient = class {
877
889
  * of a specific PvP coinflip match before rendering join, cancel, or result UI.
878
890
  *
879
891
  * @param gameId On-chain object id of the PvP coinflip game.
892
+ * @param options Optional `getObject()` options forwarded to the underlying
893
+ * client lookup, excluding `objectId` and `include`. Supported options include
894
+ * `signal`.
880
895
  * @returns Parsed PvP coinflip game state with a normalized `coinType`.
881
896
  * @throws Error If the object cannot be decoded because no content was returned.
882
897
  */
883
- async resolvePvPConflipGame(gameId) {
898
+ async resolvePvPConflipGame(gameId, options = {}) {
884
899
  const { object } = await this.#client.core.getObject({
900
+ ...options,
885
901
  objectId: gameId,
886
902
  include: { content: true }
887
903
  });
888
- if (!object.content) {
889
- throw new Error("Unable to resolve PvP coinflip from game object");
890
- }
891
- return {
892
- ...Game.parse(object.content),
893
- coinType: normalizeStructTag(parseStructTag(object.type).typeParams[0])
894
- };
904
+ return this.#resolvePvPCoinflipGameObject(object);
895
905
  }
896
906
  /**
897
907
  * BCS struct constructors for decoding on-chain objects and events related to Suigar games.
@@ -1021,6 +1031,20 @@ var SuigarClient = class {
1021
1031
  });
1022
1032
  };
1023
1033
  }
1034
+ #resolvePvPCoinflipGameObject(object) {
1035
+ if (object instanceof Error) {
1036
+ throw object;
1037
+ }
1038
+ if (!object.content) {
1039
+ throw new Error(
1040
+ "Unable to resolve PvP coinflip game from retrieved object"
1041
+ );
1042
+ }
1043
+ return {
1044
+ ...Game.parse(object.content),
1045
+ coinType: normalizeStructTag(parseStructTag(object.type).typeParams[0])
1046
+ };
1047
+ }
1024
1048
  };
1025
1049
 
1026
1050
  export { SuigarClient, suigar };
package/dist/utils.d.cts CHANGED
@@ -61,7 +61,30 @@ declare const DEFAULT_RANGE_SCALE = 1000000;
61
61
  declare const RANGE_POINT_LIMIT: number;
62
62
  declare const DEFAULT_LIMBO_MULTIPLIER_SCALE = 100;
63
63
 
64
+ /**
65
+ * Normalizes a numeric input into a non-negative `bigint`.
66
+ *
67
+ * This helper accepts the two number shapes the SDK commonly sees from app
68
+ * code: plain JavaScript numbers and already-normalized `bigint` values.
69
+ * Number inputs are truncated toward zero before conversion, so UI-friendly
70
+ * values like `5.9` become `5n`.
71
+ *
72
+ * @param value Value to coerce into a `bigint`.
73
+ * @returns The normalized non-negative `bigint`.
74
+ * @throws When `value` is not a finite number or bigint, or when it is negative.
75
+ */
64
76
  declare function toBigInt(value: unknown): bigint;
77
+ /**
78
+ * Validates that a value can be safely used as a Move `u8`.
79
+ *
80
+ * Use this for config ids and other small integer fields that must stay inside
81
+ * the `0..255` range. Unlike `toBigInt`, this does not coerce fractional
82
+ * values: the input must already be an integer.
83
+ *
84
+ * @param value Value to validate.
85
+ * @returns The original number once it has been confirmed to be a valid `u8`.
86
+ * @throws When `value` is not a finite integer between `0` and `255`.
87
+ */
65
88
  declare function toU8(value: unknown): number;
66
89
 
67
90
  declare const Float: MoveStruct<{
@@ -75,6 +98,18 @@ declare const Float: MoveStruct<{
75
98
  type MoveFloat = ReturnType<(typeof Float)['parse']>;
76
99
  declare function fromMoveI64(i64: MoveFloat['exp']): number;
77
100
  declare function fromMoveFloat(float: MoveFloat): number;
101
+ /**
102
+ * Decodes `BetResultEvent.game_details` into plain application values.
103
+ *
104
+ * Suigar stores game detail entries as `VecMap<string, vector<u8>>`, so raw BCS
105
+ * decoding leaves each value as bytes. This helper looks up the known schema for
106
+ * each key, parses the bytes into the expected runtime type, and preserves the
107
+ * original onchain keys in the returned object. Unknown keys fall back to
108
+ * string decoding so newer detail fields remain readable by default.
109
+ *
110
+ * @param gameDetails Raw `game_details` map from a decoded bet result event.
111
+ * @returns A plain object with the same keys and decoded string, number, or boolean values.
112
+ */
78
113
  declare function parseGameDetails(gameDetails: BetResultGameDetails): ParsedGameDetails;
79
114
 
80
115
  export { DEFAULT_GAS_BUDGET_MIST, DEFAULT_LIMBO_MULTIPLIER_SCALE, DEFAULT_RANGE_SCALE, RANGE_POINT_LIMIT, fromMoveFloat, fromMoveI64, parseGameDetails, toBigInt, toU8 };
package/dist/utils.d.ts CHANGED
@@ -61,7 +61,30 @@ declare const DEFAULT_RANGE_SCALE = 1000000;
61
61
  declare const RANGE_POINT_LIMIT: number;
62
62
  declare const DEFAULT_LIMBO_MULTIPLIER_SCALE = 100;
63
63
 
64
+ /**
65
+ * Normalizes a numeric input into a non-negative `bigint`.
66
+ *
67
+ * This helper accepts the two number shapes the SDK commonly sees from app
68
+ * code: plain JavaScript numbers and already-normalized `bigint` values.
69
+ * Number inputs are truncated toward zero before conversion, so UI-friendly
70
+ * values like `5.9` become `5n`.
71
+ *
72
+ * @param value Value to coerce into a `bigint`.
73
+ * @returns The normalized non-negative `bigint`.
74
+ * @throws When `value` is not a finite number or bigint, or when it is negative.
75
+ */
64
76
  declare function toBigInt(value: unknown): bigint;
77
+ /**
78
+ * Validates that a value can be safely used as a Move `u8`.
79
+ *
80
+ * Use this for config ids and other small integer fields that must stay inside
81
+ * the `0..255` range. Unlike `toBigInt`, this does not coerce fractional
82
+ * values: the input must already be an integer.
83
+ *
84
+ * @param value Value to validate.
85
+ * @returns The original number once it has been confirmed to be a valid `u8`.
86
+ * @throws When `value` is not a finite integer between `0` and `255`.
87
+ */
65
88
  declare function toU8(value: unknown): number;
66
89
 
67
90
  declare const Float: MoveStruct<{
@@ -75,6 +98,18 @@ declare const Float: MoveStruct<{
75
98
  type MoveFloat = ReturnType<(typeof Float)['parse']>;
76
99
  declare function fromMoveI64(i64: MoveFloat['exp']): number;
77
100
  declare function fromMoveFloat(float: MoveFloat): number;
101
+ /**
102
+ * Decodes `BetResultEvent.game_details` into plain application values.
103
+ *
104
+ * Suigar stores game detail entries as `VecMap<string, vector<u8>>`, so raw BCS
105
+ * decoding leaves each value as bytes. This helper looks up the known schema for
106
+ * each key, parses the bytes into the expected runtime type, and preserves the
107
+ * original onchain keys in the returned object. Unknown keys fall back to
108
+ * string decoding so newer detail fields remain readable by default.
109
+ *
110
+ * @param gameDetails Raw `game_details` map from a decoded bet result event.
111
+ * @returns A plain object with the same keys and decoded string, number, or boolean values.
112
+ */
78
113
  declare function parseGameDetails(gameDetails: BetResultGameDetails): ParsedGameDetails;
79
114
 
80
115
  export { DEFAULT_GAS_BUDGET_MIST, DEFAULT_LIMBO_MULTIPLIER_SCALE, DEFAULT_RANGE_SCALE, RANGE_POINT_LIMIT, fromMoveFloat, fromMoveI64, parseGameDetails, toBigInt, toU8 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suigar/sdk",
3
- "version": "2.0.0-beta.7",
3
+ "version": "2.0.0-beta.8",
4
4
  "description": "TypeScript SDK for Suigar v2 Move contracts on Sui.",
5
5
  "keywords": [
6
6
  "suigar",