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

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/dist/index.cjs CHANGED
@@ -126,56 +126,44 @@ function resolvePriceInfoObjectId(config, coinType) {
126
126
  const normalizedCoinType = utils.normalizeStructTag(coinType);
127
127
  const supportedCoin = resolveSupportedCoin(config, normalizedCoinType);
128
128
  const objectId = config.priceInfoObjectIds[supportedCoin];
129
- if (objectId) {
130
- return objectId;
129
+ if (!objectId) {
130
+ throw new Error(
131
+ `Missing price info object configuration for coin type ${coinType}`
132
+ );
131
133
  }
132
- throw new Error(
133
- `Missing price info object configuration for coin type ${coinType}`
134
- );
134
+ return objectId;
135
135
  }
136
136
  function resolveSupportedCoin(config, coinType) {
137
- const entries = Object.entries(config.coinTypes);
138
- const supportedCoin = entries.find(
139
- ([, configuredCoinType]) => configuredCoinType === coinType
140
- )?.[0];
141
- if (supportedCoin) {
142
- return supportedCoin;
137
+ const [supportedCoin] = Object.entries(config.coinTypes).find(([_, value]) => value === coinType) ?? [];
138
+ if (!supportedCoin) {
139
+ throw new Error(
140
+ `Unsupported coin type ${coinType}. Supported coin types: ${Object.values(
141
+ config.coinTypes
142
+ ).join(", ")}`
143
+ );
143
144
  }
144
- throw new Error(
145
- `Unsupported coin type ${coinType}. Supported coin types: ${entries.map(([, configuredCoinType]) => configuredCoinType).join(", ")}`
146
- );
145
+ return supportedCoin;
147
146
  }
148
- var ADDRESS_METADATA_KEYS = /* @__PURE__ */ new Set(["partner"]);
149
- var RESERVED_METADATA_KEYS = /* @__PURE__ */ new Set([...ADDRESS_METADATA_KEYS, "referrer"]);
147
+ var PARTNER_METADATA_KEY = "partner";
148
+ var RESERVED_METADATA_KEYS = /* @__PURE__ */ new Set([PARTNER_METADATA_KEY, "referrer"]);
150
149
  var textEncoder = new TextEncoder();
151
150
  function parseHexAddress(value) {
152
- const trimmed = value.trim();
153
- if (!trimmed || !utils.isValidSuiAddress(trimmed)) return null;
154
151
  try {
155
- const normalized = utils.normalizeSuiAddress(trimmed).slice(2);
156
- const bytes = new Uint8Array(normalized.length / 2);
157
- for (let index = 0; index < normalized.length; index += 2) {
158
- bytes[index / 2] = Number.parseInt(
159
- normalized.slice(index, index + 2),
160
- 16
161
- );
162
- }
163
- return bytes;
152
+ return utils.fromHex(value);
164
153
  } catch {
165
154
  return null;
166
155
  }
167
156
  }
168
- function encodeMetadataValue(key, value) {
157
+ function encodeMetadataValue(value) {
169
158
  if (value instanceof Uint8Array) {
170
159
  return Array.from(value);
171
160
  }
172
161
  if (Array.isArray(value)) {
173
162
  return value;
174
163
  }
175
- if (typeof value === "string" && ADDRESS_METADATA_KEYS.has(key)) {
176
- return Array.from(parseHexAddress(value) ?? textEncoder.encode(value));
177
- }
178
- return Array.from(textEncoder.encode(String(value)));
164
+ return Array.from(
165
+ parseHexAddress(String(value)) ?? textEncoder.encode(String(value))
166
+ );
179
167
  }
180
168
  function encodeBetMetadata(metadata, partner) {
181
169
  const keys = [];
@@ -191,14 +179,15 @@ function encodeBetMetadata(metadata, partner) {
191
179
  continue;
192
180
  }
193
181
  keys.push(key);
194
- values.push(encodeMetadataValue(key, value));
182
+ values.push(encodeMetadataValue(value));
195
183
  }
196
- if (!partner?.trim()) {
197
- return { keys, values };
184
+ if (partner?.trim()) {
185
+ keys.unshift(PARTNER_METADATA_KEY);
186
+ values.unshift(encodeMetadataValue(partner));
198
187
  }
199
188
  return {
200
- keys: [...keys, "partner"],
201
- values: [...values, encodeMetadataValue("partner", partner)]
189
+ keys,
190
+ values
202
191
  };
203
192
  }
204
193
  var MOVE_STDLIB_ADDRESS = utils.normalizeSuiAddress("0x1");
@@ -413,20 +402,18 @@ var Float = new MoveStruct({ name: `${$moduleName2}::Float`, fields: {
413
402
  function createBaseGameTransaction({
414
403
  config,
415
404
  game,
416
- owner,
417
- sender,
405
+ playerAddress,
418
406
  gasBudget
419
407
  }) {
420
408
  assertConfiguredBetGame(config, game);
421
409
  const tx = new transactions.Transaction();
422
- tx.setSenderIfNotSet(utils.normalizeSuiAddress(sender ?? owner));
410
+ tx.setSenderIfNotSet(utils.normalizeSuiAddress(playerAddress));
423
411
  tx.setGasBudgetIfNotSet(gasBudget ?? DEFAULT_GAS_BUDGET_MIST);
424
412
  return tx;
425
413
  }
426
414
  function buildSharedStandardGameBetCall({
427
415
  config,
428
- owner,
429
- sender,
416
+ playerAddress,
430
417
  coinType,
431
418
  stake,
432
419
  cashStake,
@@ -437,7 +424,7 @@ function buildSharedStandardGameBetCall({
437
424
  buildRewardCoin
438
425
  }) {
439
426
  return (tx) => {
440
- const normalizedOwner = utils.normalizeSuiAddress(sender ?? owner);
427
+ const normalizedPlayerAddress = utils.normalizeSuiAddress(playerAddress);
441
428
  const normalizedCoinType = utils.normalizeStructTag(coinType);
442
429
  const resolvedStake = toBigInt(stake);
443
430
  const resolvedCashStake = toBigInt(cashStake ?? stake);
@@ -455,7 +442,7 @@ function buildSharedStandardGameBetCall({
455
442
  const rewardCoin = buildRewardCoin({
456
443
  tx,
457
444
  config,
458
- owner: normalizedOwner,
445
+ playerAddress: normalizedPlayerAddress,
459
446
  coinType: normalizedCoinType,
460
447
  stake: resolvedStake,
461
448
  cashStake: resolvedCashStake,
@@ -464,7 +451,7 @@ function buildSharedStandardGameBetCall({
464
451
  priceInfoObjectId,
465
452
  betCoin
466
453
  });
467
- tx.transferObjects([rewardCoin], tx.pure.address(normalizedOwner));
454
+ tx.transferObjects([rewardCoin], tx.pure.address(normalizedPlayerAddress));
468
455
  return rewardCoin;
469
456
  };
470
457
  }
@@ -1019,39 +1006,53 @@ var SuigarClient = class {
1019
1006
  * Lists unresolved PvP coinflip games from the configured registry and resolves
1020
1007
  * each entry into parsed onchain game state.
1021
1008
  *
1022
- * This fetches dynamic fields from the PvP coinflip registry object, then loads
1023
- * each referenced game object through `resolvePvPConflipGame()`. Registry
1009
+ * This fetches dynamic fields from the PvP coinflip registry object, then bulk
1010
+ * loads the referenced game objects through `client.core.getObjects()`. Registry
1024
1011
  * membership is the unresolved-state signal: when a game is joined and resolved,
1025
1012
  * the Move flow removes it from the registry and deletes the live `Game` object.
1026
1013
  * Use this when a product needs the current set of open PvP coinflip matches for
1027
1014
  * browsing or lobby views.
1028
1015
  *
1029
1016
  * @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.
1017
+ * Supported options such as `limit`, `cursor`, and `signal` are forwarded to the
1018
+ * underlying lookup calls. Pass `throwOnError: true` to fail the whole lookup
1019
+ * when any referenced game object cannot be fetched or parsed. By default,
1020
+ * failed per-object lookups are skipped and only successfully parsed unresolved
1021
+ * games are returned.
1033
1022
  * @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.
1023
+ * registry page. When `throwOnError` is `false`, entries that fail object fetch
1024
+ * or parse are omitted from the returned array.
1036
1025
  */
1037
1026
  async getPvPCoinflipGames(options = {
1038
1027
  limit: 50
1039
1028
  }) {
1040
1029
  const { throwOnError = false, ...listOptions } = options;
1041
1030
  const { dynamicFields } = await this.#client.core.listDynamicFields({
1042
- parentId: this.#config.registryIds.pvpCoinflip,
1043
- ...listOptions
1031
+ ...listOptions,
1032
+ parentId: this.#config.registryIds.pvpCoinflip
1033
+ });
1034
+ const { objects } = await this.#client.core.getObjects({
1035
+ objectIds: dynamicFields.map(({ childId }) => childId),
1036
+ signal: listOptions.signal,
1037
+ include: {
1038
+ content: true
1039
+ }
1040
+ });
1041
+ const resolvedGames = objects.map((object) => {
1042
+ try {
1043
+ return this.#resolvePvPCoinflipGameObject(object);
1044
+ } catch (error) {
1045
+ return error instanceof Error ? error : new Error(String(error));
1046
+ }
1044
1047
  });
1045
1048
  if (throwOnError) {
1046
- return Promise.all(
1047
- dynamicFields.map(({ childId }) => this.resolvePvPConflipGame(childId))
1048
- );
1049
+ const firstError = resolvedGames.find((game) => game instanceof Error);
1050
+ if (firstError) {
1051
+ throw firstError;
1052
+ }
1049
1053
  }
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] : []
1054
+ return resolvedGames.flatMap(
1055
+ (game) => game instanceof Error ? [] : [game]
1055
1056
  );
1056
1057
  }
1057
1058
  /**
@@ -1065,21 +1066,19 @@ var SuigarClient = class {
1065
1066
  * of a specific PvP coinflip match before rendering join, cancel, or result UI.
1066
1067
  *
1067
1068
  * @param gameId On-chain object id of the PvP coinflip game.
1069
+ * @param options Optional `getObject()` options forwarded to the underlying
1070
+ * client lookup, excluding `objectId` and `include`. Supported options include
1071
+ * `signal`.
1068
1072
  * @returns Parsed PvP coinflip game state with a normalized `coinType`.
1069
1073
  * @throws Error If the object cannot be decoded because no content was returned.
1070
1074
  */
1071
- async resolvePvPConflipGame(gameId) {
1075
+ async resolvePvPConflipGame(gameId, options = {}) {
1072
1076
  const { object } = await this.#client.core.getObject({
1077
+ ...options,
1073
1078
  objectId: gameId,
1074
1079
  include: { content: true }
1075
1080
  });
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
- };
1081
+ return this.#resolvePvPCoinflipGameObject(object);
1083
1082
  }
1084
1083
  /**
1085
1084
  * BCS struct constructors for decoding on-chain objects and events related to Suigar games.
@@ -1209,6 +1208,20 @@ var SuigarClient = class {
1209
1208
  });
1210
1209
  };
1211
1210
  }
1211
+ #resolvePvPCoinflipGameObject(object) {
1212
+ if (object instanceof Error) {
1213
+ throw object;
1214
+ }
1215
+ if (!object.content) {
1216
+ throw new Error(
1217
+ "Unable to resolve PvP coinflip game from retrieved object"
1218
+ );
1219
+ }
1220
+ return {
1221
+ ...Game.parse(object.content),
1222
+ coinType: utils.normalizeStructTag(utils.parseStructTag(object.type).typeParams[0])
1223
+ };
1224
+ }
1212
1225
  };
1213
1226
 
1214
1227
  exports.SuigarClient = SuigarClient;
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
- import { M as MoveStruct } from './index-jwSXA8q3.cjs';
1
+ import { M as MoveStruct } from './index-3P_LBbDM.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
@@ -1,8 +1,8 @@
1
- import { M as MoveStruct } from './index-jwSXA8q3.js';
1
+ import { M as MoveStruct } from './index-3P_LBbDM.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
@@ -1,5 +1,5 @@
1
- import { MoveStruct, Float, toBigInt, toU8, DEFAULT_GAS_BUDGET_MIST, normalizeMoveArguments, DEFAULT_LIMBO_MULTIPLIER_SCALE, DEFAULT_RANGE_SCALE } from './chunk-YGYMLRE4.js';
2
- import { toBase64, normalizeStructTag, parseStructTag, normalizeSuiAddress, isValidSuiAddress } from '@mysten/sui/utils';
1
+ import { MoveStruct, Float, toBigInt, toU8, DEFAULT_GAS_BUDGET_MIST, normalizeMoveArguments, DEFAULT_LIMBO_MULTIPLIER_SCALE, DEFAULT_RANGE_SCALE } from './chunk-FEQY5O43.js';
2
+ import { toBase64, normalizeStructTag, parseStructTag, normalizeSuiAddress, fromHex } from '@mysten/sui/utils';
3
3
  import { Transaction } from '@mysten/sui/transactions';
4
4
  import { bcs } from '@mysten/sui/bcs';
5
5
 
@@ -123,56 +123,44 @@ function resolvePriceInfoObjectId(config, coinType) {
123
123
  const normalizedCoinType = normalizeStructTag(coinType);
124
124
  const supportedCoin = resolveSupportedCoin(config, normalizedCoinType);
125
125
  const objectId = config.priceInfoObjectIds[supportedCoin];
126
- if (objectId) {
127
- return objectId;
126
+ if (!objectId) {
127
+ throw new Error(
128
+ `Missing price info object configuration for coin type ${coinType}`
129
+ );
128
130
  }
129
- throw new Error(
130
- `Missing price info object configuration for coin type ${coinType}`
131
- );
131
+ return objectId;
132
132
  }
133
133
  function resolveSupportedCoin(config, coinType) {
134
- const entries = Object.entries(config.coinTypes);
135
- const supportedCoin = entries.find(
136
- ([, configuredCoinType]) => configuredCoinType === coinType
137
- )?.[0];
138
- if (supportedCoin) {
139
- return supportedCoin;
134
+ const [supportedCoin] = Object.entries(config.coinTypes).find(([_, value]) => value === coinType) ?? [];
135
+ if (!supportedCoin) {
136
+ throw new Error(
137
+ `Unsupported coin type ${coinType}. Supported coin types: ${Object.values(
138
+ config.coinTypes
139
+ ).join(", ")}`
140
+ );
140
141
  }
141
- throw new Error(
142
- `Unsupported coin type ${coinType}. Supported coin types: ${entries.map(([, configuredCoinType]) => configuredCoinType).join(", ")}`
143
- );
142
+ return supportedCoin;
144
143
  }
145
- var ADDRESS_METADATA_KEYS = /* @__PURE__ */ new Set(["partner"]);
146
- var RESERVED_METADATA_KEYS = /* @__PURE__ */ new Set([...ADDRESS_METADATA_KEYS, "referrer"]);
144
+ var PARTNER_METADATA_KEY = "partner";
145
+ var RESERVED_METADATA_KEYS = /* @__PURE__ */ new Set([PARTNER_METADATA_KEY, "referrer"]);
147
146
  var textEncoder = new TextEncoder();
148
147
  function parseHexAddress(value) {
149
- const trimmed = value.trim();
150
- if (!trimmed || !isValidSuiAddress(trimmed)) return null;
151
148
  try {
152
- const normalized = normalizeSuiAddress(trimmed).slice(2);
153
- const bytes = new Uint8Array(normalized.length / 2);
154
- for (let index = 0; index < normalized.length; index += 2) {
155
- bytes[index / 2] = Number.parseInt(
156
- normalized.slice(index, index + 2),
157
- 16
158
- );
159
- }
160
- return bytes;
149
+ return fromHex(value);
161
150
  } catch {
162
151
  return null;
163
152
  }
164
153
  }
165
- function encodeMetadataValue(key, value) {
154
+ function encodeMetadataValue(value) {
166
155
  if (value instanceof Uint8Array) {
167
156
  return Array.from(value);
168
157
  }
169
158
  if (Array.isArray(value)) {
170
159
  return value;
171
160
  }
172
- if (typeof value === "string" && ADDRESS_METADATA_KEYS.has(key)) {
173
- return Array.from(parseHexAddress(value) ?? textEncoder.encode(value));
174
- }
175
- return Array.from(textEncoder.encode(String(value)));
161
+ return Array.from(
162
+ parseHexAddress(String(value)) ?? textEncoder.encode(String(value))
163
+ );
176
164
  }
177
165
  function encodeBetMetadata(metadata, partner) {
178
166
  const keys = [];
@@ -188,14 +176,15 @@ function encodeBetMetadata(metadata, partner) {
188
176
  continue;
189
177
  }
190
178
  keys.push(key);
191
- values.push(encodeMetadataValue(key, value));
179
+ values.push(encodeMetadataValue(value));
192
180
  }
193
- if (!partner?.trim()) {
194
- return { keys, values };
181
+ if (partner?.trim()) {
182
+ keys.unshift(PARTNER_METADATA_KEY);
183
+ values.unshift(encodeMetadataValue(partner));
195
184
  }
196
185
  return {
197
- keys: [...keys, "partner"],
198
- values: [...values, encodeMetadataValue("partner", partner)]
186
+ keys,
187
+ values
199
188
  };
200
189
  }
201
190
 
@@ -225,20 +214,18 @@ function play(options) {
225
214
  function createBaseGameTransaction({
226
215
  config,
227
216
  game,
228
- owner,
229
- sender,
217
+ playerAddress,
230
218
  gasBudget
231
219
  }) {
232
220
  assertConfiguredBetGame(config, game);
233
221
  const tx = new Transaction();
234
- tx.setSenderIfNotSet(normalizeSuiAddress(sender ?? owner));
222
+ tx.setSenderIfNotSet(normalizeSuiAddress(playerAddress));
235
223
  tx.setGasBudgetIfNotSet(gasBudget ?? DEFAULT_GAS_BUDGET_MIST);
236
224
  return tx;
237
225
  }
238
226
  function buildSharedStandardGameBetCall({
239
227
  config,
240
- owner,
241
- sender,
228
+ playerAddress,
242
229
  coinType,
243
230
  stake,
244
231
  cashStake,
@@ -249,7 +236,7 @@ function buildSharedStandardGameBetCall({
249
236
  buildRewardCoin
250
237
  }) {
251
238
  return (tx) => {
252
- const normalizedOwner = normalizeSuiAddress(sender ?? owner);
239
+ const normalizedPlayerAddress = normalizeSuiAddress(playerAddress);
253
240
  const normalizedCoinType = normalizeStructTag(coinType);
254
241
  const resolvedStake = toBigInt(stake);
255
242
  const resolvedCashStake = toBigInt(cashStake ?? stake);
@@ -267,7 +254,7 @@ function buildSharedStandardGameBetCall({
267
254
  const rewardCoin = buildRewardCoin({
268
255
  tx,
269
256
  config,
270
- owner: normalizedOwner,
257
+ playerAddress: normalizedPlayerAddress,
271
258
  coinType: normalizedCoinType,
272
259
  stake: resolvedStake,
273
260
  cashStake: resolvedCashStake,
@@ -276,7 +263,7 @@ function buildSharedStandardGameBetCall({
276
263
  priceInfoObjectId,
277
264
  betCoin
278
265
  });
279
- tx.transferObjects([rewardCoin], tx.pure.address(normalizedOwner));
266
+ tx.transferObjects([rewardCoin], tx.pure.address(normalizedPlayerAddress));
280
267
  return rewardCoin;
281
268
  };
282
269
  }
@@ -831,39 +818,53 @@ var SuigarClient = class {
831
818
  * Lists unresolved PvP coinflip games from the configured registry and resolves
832
819
  * each entry into parsed onchain game state.
833
820
  *
834
- * This fetches dynamic fields from the PvP coinflip registry object, then loads
835
- * each referenced game object through `resolvePvPConflipGame()`. Registry
821
+ * This fetches dynamic fields from the PvP coinflip registry object, then bulk
822
+ * loads the referenced game objects through `client.core.getObjects()`. Registry
836
823
  * membership is the unresolved-state signal: when a game is joined and resolved,
837
824
  * the Move flow removes it from the registry and deletes the live `Game` object.
838
825
  * Use this when a product needs the current set of open PvP coinflip matches for
839
826
  * browsing or lobby views.
840
827
  *
841
828
  * @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.
829
+ * Supported options such as `limit`, `cursor`, and `signal` are forwarded to the
830
+ * underlying lookup calls. Pass `throwOnError: true` to fail the whole lookup
831
+ * when any referenced game object cannot be fetched or parsed. By default,
832
+ * failed per-object lookups are skipped and only successfully parsed unresolved
833
+ * games are returned.
845
834
  * @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.
835
+ * registry page. When `throwOnError` is `false`, entries that fail object fetch
836
+ * or parse are omitted from the returned array.
848
837
  */
849
838
  async getPvPCoinflipGames(options = {
850
839
  limit: 50
851
840
  }) {
852
841
  const { throwOnError = false, ...listOptions } = options;
853
842
  const { dynamicFields } = await this.#client.core.listDynamicFields({
854
- parentId: this.#config.registryIds.pvpCoinflip,
855
- ...listOptions
843
+ ...listOptions,
844
+ parentId: this.#config.registryIds.pvpCoinflip
845
+ });
846
+ const { objects } = await this.#client.core.getObjects({
847
+ objectIds: dynamicFields.map(({ childId }) => childId),
848
+ signal: listOptions.signal,
849
+ include: {
850
+ content: true
851
+ }
852
+ });
853
+ const resolvedGames = objects.map((object) => {
854
+ try {
855
+ return this.#resolvePvPCoinflipGameObject(object);
856
+ } catch (error) {
857
+ return error instanceof Error ? error : new Error(String(error));
858
+ }
856
859
  });
857
860
  if (throwOnError) {
858
- return Promise.all(
859
- dynamicFields.map(({ childId }) => this.resolvePvPConflipGame(childId))
860
- );
861
+ const firstError = resolvedGames.find((game) => game instanceof Error);
862
+ if (firstError) {
863
+ throw firstError;
864
+ }
861
865
  }
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] : []
866
+ return resolvedGames.flatMap(
867
+ (game) => game instanceof Error ? [] : [game]
867
868
  );
868
869
  }
869
870
  /**
@@ -877,21 +878,19 @@ var SuigarClient = class {
877
878
  * of a specific PvP coinflip match before rendering join, cancel, or result UI.
878
879
  *
879
880
  * @param gameId On-chain object id of the PvP coinflip game.
881
+ * @param options Optional `getObject()` options forwarded to the underlying
882
+ * client lookup, excluding `objectId` and `include`. Supported options include
883
+ * `signal`.
880
884
  * @returns Parsed PvP coinflip game state with a normalized `coinType`.
881
885
  * @throws Error If the object cannot be decoded because no content was returned.
882
886
  */
883
- async resolvePvPConflipGame(gameId) {
887
+ async resolvePvPConflipGame(gameId, options = {}) {
884
888
  const { object } = await this.#client.core.getObject({
889
+ ...options,
885
890
  objectId: gameId,
886
891
  include: { content: true }
887
892
  });
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
- };
893
+ return this.#resolvePvPCoinflipGameObject(object);
895
894
  }
896
895
  /**
897
896
  * BCS struct constructors for decoding on-chain objects and events related to Suigar games.
@@ -1021,6 +1020,20 @@ var SuigarClient = class {
1021
1020
  });
1022
1021
  };
1023
1022
  }
1023
+ #resolvePvPCoinflipGameObject(object) {
1024
+ if (object instanceof Error) {
1025
+ throw object;
1026
+ }
1027
+ if (!object.content) {
1028
+ throw new Error(
1029
+ "Unable to resolve PvP coinflip game from retrieved object"
1030
+ );
1031
+ }
1032
+ return {
1033
+ ...Game.parse(object.content),
1034
+ coinType: normalizeStructTag(parseStructTag(object.type).typeParams[0])
1035
+ };
1036
+ }
1024
1037
  };
1025
1038
 
1026
1039
  export { SuigarClient, suigar };