@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/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
- import { normalizeSuiAddress, toBase64, normalizeStructTag } from '@mysten/sui/utils';
2
- import { bcs, BcsStruct, TypeTagSerializer } from '@mysten/sui/bcs';
3
- import { Transaction, isArgument } from '@mysten/sui/transactions';
1
+ import { MoveStruct, Float, toBigIntAmount, toU8Number, DEFAULT_GAS_BUDGET_MIST, normalizeMoveArguments, DEFAULT_LIMBO_MULTIPLIER_SCALE, DEFAULT_RANGE_SCALE } from './chunk-W3WZ2BHO.js';
2
+ import { toBase64, normalizeStructTag, parseStructTag, normalizeSuiAddress, isValidSuiAddress } from '@mysten/sui/utils';
3
+ import { Transaction } from '@mysten/sui/transactions';
4
+ import { bcs } from '@mysten/sui/bcs';
4
5
 
5
6
  // src/types/network.type.ts
6
7
  var SUPPORTED_SUI_NETWORKS = [
@@ -62,13 +63,31 @@ var PRICE_INFO_OBJECT_IDS = {
62
63
  testnet: { ...TESTNET_PRICE_INFO_OBJECT_IDS }
63
64
  };
64
65
 
65
- // src/utils/config.ts
66
+ // src/configs/registry.mainnet.ts
67
+ var PVP_COINFLIP_REGISTRY_ID = "0x3d73568546c539c1da3eb2b8fe917faef3c0acdbec78a67fe6d52800a0729349";
68
+
69
+ // src/configs/registry.testnet.ts
70
+ var PVP_COINFLIP_REGISTRY_ID2 = "0x99f20d8e4be012ea14a681144ae72ac349d0a1a1585205880183eb167f075bad";
71
+
72
+ // src/configs/registry.ts
73
+ var REGISTRY_IDS = {
74
+ mainnet: {
75
+ pvpCoinflip: PVP_COINFLIP_REGISTRY_ID
76
+ },
77
+ testnet: {
78
+ pvpCoinflip: PVP_COINFLIP_REGISTRY_ID2
79
+ }
80
+ };
81
+
82
+ // src/helpers/config.ts
66
83
  function resolveSuigarConfig(network) {
67
84
  const packageIds = PACKAGE_IDS[network];
85
+ const registryIds = REGISTRY_IDS[network];
68
86
  const coinTypes = COIN_TYPES[network];
69
87
  const priceInfoObjectIds = PRICE_INFO_OBJECT_IDS[network];
70
88
  return {
71
89
  packageIds: { ...packageIds },
90
+ registryIds: { ...registryIds },
72
91
  coinTypes: {
73
92
  sui: normalizeStructTag(coinTypes.sui),
74
93
  usdc: normalizeStructTag(coinTypes.usdc)
@@ -123,11 +142,12 @@ function resolveSupportedCoin(config, coinType) {
123
142
  `Unsupported coin type ${coinType}. Supported coin types: ${entries.map(([, configuredCoinType]) => configuredCoinType).join(", ")}`
124
143
  );
125
144
  }
126
- var ADDRESS_METADATA_KEYS = /* @__PURE__ */ new Set(["referrer", "partner"]);
145
+ var ADDRESS_METADATA_KEYS = /* @__PURE__ */ new Set(["partner"]);
146
+ var RESERVED_METADATA_KEYS = /* @__PURE__ */ new Set([...ADDRESS_METADATA_KEYS, "referrer"]);
127
147
  var textEncoder = new TextEncoder();
128
- var parseHexAddress = (value) => {
148
+ function parseHexAddress(value) {
129
149
  const trimmed = value.trim();
130
- if (!trimmed) return null;
150
+ if (!trimmed || !isValidSuiAddress(trimmed)) return null;
131
151
  try {
132
152
  const normalized = normalizeSuiAddress(trimmed).slice(2);
133
153
  const bytes = new Uint8Array(normalized.length / 2);
@@ -141,190 +161,42 @@ var parseHexAddress = (value) => {
141
161
  } catch {
142
162
  return null;
143
163
  }
144
- };
145
- function encodeBetMetadata(metadata) {
146
- const keys = [];
147
- const values = [];
148
- for (const [key, value] of Object.entries(metadata ?? {})) {
149
- if (value === void 0 || value === null) {
150
- continue;
151
- }
152
- let encodedValue;
153
- if (value instanceof Uint8Array) {
154
- encodedValue = Array.from(value);
155
- } else if (Array.isArray(value)) {
156
- encodedValue = value;
157
- } else if (typeof value === "string" && ADDRESS_METADATA_KEYS.has(key)) {
158
- encodedValue = Array.from(
159
- parseHexAddress(value) ?? textEncoder.encode(value)
160
- );
161
- } else {
162
- encodedValue = Array.from(textEncoder.encode(String(value)));
163
- }
164
- keys.push(key);
165
- values.push(encodedValue);
166
- }
167
- return { keys, values };
168
164
  }
169
-
170
- // src/utils/shared.ts
171
- var DEFAULT_GAS_BUDGET_MIST = 5e7;
172
- var RANGE_FIXED_POINT_SCALE = 1e6;
173
- var LIMBO_MULTIPLIER_SCALE = 100;
174
- function toBigIntAmount(value, fieldName) {
175
- if (typeof value === "bigint") {
176
- if (value < 0n) {
177
- throw new Error(`${fieldName} must be non-negative`);
178
- }
179
- return value;
165
+ function encodeMetadataValue(key, value) {
166
+ if (value instanceof Uint8Array) {
167
+ return Array.from(value);
180
168
  }
181
- if (!Number.isFinite(value) || value < 0) {
182
- throw new Error(`${fieldName} must be a finite non-negative number`);
183
- }
184
- return BigInt(Math.trunc(value));
185
- }
186
- function toU8Number(value, fieldName) {
187
- if (!Number.isInteger(value) || value < 0 || value > 255) {
188
- throw new Error(`${fieldName} must be an integer between 0 and 255`);
169
+ if (Array.isArray(value)) {
170
+ return value;
189
171
  }
190
- return value;
191
- }
192
- var MOVE_STDLIB_ADDRESS = normalizeSuiAddress("0x1");
193
- var SUI_FRAMEWORK_ADDRESS = normalizeSuiAddress("0x2");
194
- function getPureBcsSchema(typeTag) {
195
- const parsedTag = typeof typeTag === "string" ? TypeTagSerializer.parseFromStr(typeTag) : typeTag;
196
- if ("u8" in parsedTag) {
197
- return bcs.U8;
198
- } else if ("u16" in parsedTag) {
199
- return bcs.U16;
200
- } else if ("u32" in parsedTag) {
201
- return bcs.U32;
202
- } else if ("u64" in parsedTag) {
203
- return bcs.U64;
204
- } else if ("u128" in parsedTag) {
205
- return bcs.U128;
206
- } else if ("u256" in parsedTag) {
207
- return bcs.U256;
208
- } else if ("address" in parsedTag) {
209
- return bcs.Address;
210
- } else if ("bool" in parsedTag) {
211
- return bcs.Bool;
212
- } else if ("vector" in parsedTag) {
213
- const type = getPureBcsSchema(parsedTag.vector);
214
- return type ? bcs.vector(type) : null;
215
- } else if ("struct" in parsedTag) {
216
- const structTag = parsedTag.struct;
217
- const pkg = normalizeSuiAddress(structTag.address);
218
- if (pkg === MOVE_STDLIB_ADDRESS) {
219
- if ((structTag.module === "ascii" || structTag.module === "string") && structTag.name === "String") {
220
- return bcs.String;
221
- }
222
- if (structTag.module === "option" && structTag.name === "Option") {
223
- const type = getPureBcsSchema(structTag.typeParams[0]);
224
- return type ? bcs.option(type) : null;
225
- }
226
- }
227
- if (pkg === SUI_FRAMEWORK_ADDRESS && structTag.module === "object" && (structTag.name === "ID" || structTag.name === "UID")) {
228
- return bcs.Address;
229
- }
172
+ if (typeof value === "string" && ADDRESS_METADATA_KEYS.has(key)) {
173
+ return Array.from(parseHexAddress(value) ?? textEncoder.encode(value));
230
174
  }
231
- return null;
175
+ return Array.from(textEncoder.encode(String(value)));
232
176
  }
233
- function normalizeMoveArguments(args, argTypes, parameterNames) {
234
- Array.isArray(args) ? args.length : Object.keys(args).length;
235
- const normalizedArgs = [];
236
- let index = 0;
237
- for (const [i, argType] of argTypes.entries()) {
238
- if (argType === "0x2::clock::Clock") {
239
- normalizedArgs.push((tx) => tx.object.clock());
240
- continue;
241
- }
242
- if (argType === "0x2::random::Random") {
243
- normalizedArgs.push((tx) => tx.object.random());
244
- continue;
245
- }
246
- if (argType === "0x2::deny_list::DenyList") {
247
- normalizedArgs.push((tx) => tx.object.denyList());
248
- continue;
249
- }
250
- if (argType === "0x3::sui_system::SuiSystemState") {
251
- normalizedArgs.push((tx) => tx.object.system());
252
- continue;
253
- }
254
- let arg;
255
- if (Array.isArray(args)) {
256
- if (index >= args.length) {
257
- throw new Error(
258
- `Invalid number of arguments, expected at least ${index + 1}, got ${args.length}`
259
- );
260
- }
261
- arg = args[index];
262
- } else {
263
- {
264
- throw new Error(`Expected arguments to be passed as an array`);
265
- }
266
- }
267
- index += 1;
268
- if (typeof arg === "function" || isArgument(arg)) {
269
- normalizedArgs.push(arg);
270
- continue;
271
- }
272
- const type = argTypes[i];
273
- const bcsType = type === null ? null : getPureBcsSchema(type);
274
- if (bcsType) {
275
- const bytes = bcsType.serialize(arg);
276
- normalizedArgs.push((tx) => tx.pure(bytes));
177
+ function encodeBetMetadata(metadata, partner) {
178
+ const keys = [];
179
+ const values = [];
180
+ for (const [key, value] of Object.entries(metadata ?? {})) {
181
+ if (RESERVED_METADATA_KEYS.has(key)) {
182
+ console.warn(
183
+ `Metadata key "${key}" is reserved and will be ignored when parsing metadata.`
184
+ );
277
185
  continue;
278
186
  }
279
- if (typeof arg === "string") {
280
- normalizedArgs.push((tx) => tx.object(arg));
187
+ if (value == null) {
281
188
  continue;
282
189
  }
283
- throw new Error(`Invalid argument ${stringify(arg)} for type ${type}`);
284
- }
285
- return normalizedArgs;
286
- }
287
- var MoveStruct = class extends BcsStruct {
288
- async get({
289
- objectId,
290
- ...options
291
- }) {
292
- const [res] = await this.getMany({
293
- ...options,
294
- objectIds: [objectId]
295
- });
296
- return res;
297
- }
298
- async getMany({
299
- client,
300
- ...options
301
- }) {
302
- const response = await client.core.getObjects({
303
- ...options,
304
- include: {
305
- ...options.include,
306
- content: true
307
- }
308
- });
309
- return response.objects.map((obj) => {
310
- if (obj instanceof Error) {
311
- throw obj;
312
- }
313
- return {
314
- ...obj,
315
- json: this.parse(obj.content)
316
- };
317
- });
318
- }
319
- };
320
- function stringify(val) {
321
- if (typeof val === "object") {
322
- return JSON.stringify(val, (val2) => val2);
190
+ keys.push(key);
191
+ values.push(encodeMetadataValue(key, value));
323
192
  }
324
- if (typeof val === "bigint") {
325
- return val.toString();
193
+ if (!partner?.trim()) {
194
+ return { keys, values };
326
195
  }
327
- return val;
196
+ return {
197
+ keys: [...keys, "partner"],
198
+ values: [...values, encodeMetadataValue("partner", partner)]
199
+ };
328
200
  }
329
201
 
330
202
  // src/contracts/coinflip/coinflip.ts
@@ -372,6 +244,7 @@ function buildSharedStandardGameBetCall({
372
244
  cashStake,
373
245
  betCount,
374
246
  metadata,
247
+ partner,
375
248
  allowGasCoinShortcut = true,
376
249
  buildRewardCoin
377
250
  }) {
@@ -381,7 +254,7 @@ function buildSharedStandardGameBetCall({
381
254
  const resolvedStake = toBigIntAmount(stake, "stake");
382
255
  const resolvedCashStake = toBigIntAmount(cashStake ?? stake, "cashStake");
383
256
  const resolvedBetCount = toBigIntAmount(betCount ?? 1, "betCount");
384
- const encodedMetadata = encodeBetMetadata(metadata);
257
+ const encodedMetadata = encodeBetMetadata(metadata, partner);
385
258
  const priceInfoObjectId = resolvePriceInfoObjectId(
386
259
  config,
387
260
  normalizedCoinType
@@ -471,7 +344,7 @@ function play2(options) {
471
344
 
472
345
  // src/transactions/limbo.ts
473
346
  function buildLimboTransaction(options) {
474
- const scale = options.scale ?? LIMBO_MULTIPLIER_SCALE;
347
+ const scale = options.scale ?? DEFAULT_LIMBO_MULTIPLIER_SCALE;
475
348
  const numerator = Math.round(options.targetMultiplier * scale);
476
349
  return buildSharedStandardGameBetTransaction({
477
350
  ...options,
@@ -558,14 +431,42 @@ function buildPlinkoTransaction(options) {
558
431
  })(tx)
559
432
  });
560
433
  }
561
- var $moduleName = "0x0000000000000000000000000000000000000000000000000000000000000001::type_name";
562
- var TypeName = new MoveStruct({ name: `${$moduleName}::TypeName`, fields: {
434
+ var $moduleName = "0x2::vec_map";
435
+ function Entry(...typeParameters) {
436
+ return new MoveStruct({ name: `${$moduleName}::Entry<${typeParameters[0].name}, ${typeParameters[1].name}>`, fields: {
437
+ key: typeParameters[0],
438
+ value: typeParameters[1]
439
+ } });
440
+ }
441
+ function VecMap(...typeParameters) {
442
+ return new MoveStruct({ name: `${$moduleName}::VecMap<${typeParameters[0].name}, ${typeParameters[1].name}>`, fields: {
443
+ contents: bcs.vector(Entry(typeParameters[0], typeParameters[1]))
444
+ } });
445
+ }
446
+ var $moduleName2 = "0x2::balance";
447
+ var Balance = new MoveStruct({ name: `${$moduleName2}::Balance<phantom T0>`, fields: {
448
+ value: bcs.u64()
449
+ } });
450
+ var $moduleName3 = "0x0000000000000000000000000000000000000000000000000000000000000001::type_name";
451
+ var TypeName = new MoveStruct({ name: `${$moduleName3}::TypeName`, fields: {
563
452
  name: bcs.string()
564
453
  } });
565
454
 
566
455
  // src/contracts/pvp-coinflip/pvp_coinflip.ts
567
- var $moduleName2 = "0xb43cf6583c0c15315c7e66f173af4be79ac40c38aad1fd92ec08638ab2026202::pvp_coinflip";
568
- var GameCreatedEvent = new MoveStruct({ name: `${$moduleName2}::GameCreatedEvent<phantom T0>`, fields: {
456
+ var $moduleName4 = "0xb43cf6583c0c15315c7e66f173af4be79ac40c38aad1fd92ec08638ab2026202::pvp_coinflip";
457
+ var Game = new MoveStruct({ name: `${$moduleName4}::Game<phantom T0>`, fields: {
458
+ id: bcs.Address,
459
+ creator: bcs.Address,
460
+ creator_is_tails: bcs.bool(),
461
+ is_private: bcs.bool(),
462
+ creator_metadata: VecMap(bcs.string(), bcs.vector(bcs.u8())),
463
+ joiner: bcs.Address,
464
+ winner: bcs.Address,
465
+ stake_per_player: bcs.u64(),
466
+ house_edge_bps: bcs.u64(),
467
+ stake_pot: Balance
468
+ } });
469
+ var GameCreatedEvent = new MoveStruct({ name: `${$moduleName4}::GameCreatedEvent<phantom T0>`, fields: {
569
470
  game_id: bcs.Address,
570
471
  creator: bcs.Address,
571
472
  creator_is_tails: bcs.bool(),
@@ -575,7 +476,7 @@ var GameCreatedEvent = new MoveStruct({ name: `${$moduleName2}::GameCreatedEvent
575
476
  house_edge_bps: bcs.u64(),
576
477
  coin_type: TypeName
577
478
  } });
578
- var GameResolvedEvent = new MoveStruct({ name: `${$moduleName2}::GameResolvedEvent<phantom T0>`, fields: {
479
+ var GameResolvedEvent = new MoveStruct({ name: `${$moduleName4}::GameResolvedEvent<phantom T0>`, fields: {
579
480
  game_id: bcs.Address,
580
481
  creator: bcs.Address,
581
482
  joiner: bcs.Address,
@@ -589,7 +490,7 @@ var GameResolvedEvent = new MoveStruct({ name: `${$moduleName2}::GameResolvedEve
589
490
  payout_amount: bcs.u64(),
590
491
  coin_type: TypeName
591
492
  } });
592
- var GameCancelledEvent = new MoveStruct({ name: `${$moduleName2}::GameCancelledEvent<phantom T0>`, fields: {
493
+ var GameCancelledEvent = new MoveStruct({ name: `${$moduleName4}::GameCancelledEvent<phantom T0>`, fields: {
593
494
  game_id: bcs.Address,
594
495
  creator: bcs.Address,
595
496
  creator_is_tails: bcs.bool(),
@@ -657,7 +558,7 @@ function buildPvPCoinflipTransaction(action, options) {
657
558
  game: "pvp-coinflip"
658
559
  });
659
560
  const normalizedCoinType = normalizeStructTag(options.coinType);
660
- const encodedMetadata = encodeBetMetadata(options.metadata);
561
+ const encodedMetadata = encodeBetMetadata(options.metadata, options.partner);
661
562
  switch (action) {
662
563
  case "create": {
663
564
  const createOptions = options;
@@ -685,12 +586,10 @@ function buildPvPCoinflipTransaction(action, options) {
685
586
  }
686
587
  case "join": {
687
588
  const joinOptions = options;
688
- const stake = toBigIntAmount(joinOptions.stake, "stake");
689
- const betCoin = tx.coin({
690
- type: normalizedCoinType,
691
- balance: stake,
692
- useGasCoin: joinOptions.allowGasCoinShortcut
693
- });
589
+ const priceInfoObjectId = resolvePriceInfoObjectId(
590
+ joinOptions.config,
591
+ normalizedCoinType
592
+ );
694
593
  tx.add(
695
594
  joinGame({
696
595
  package: joinOptions.config.packageIds.pvpCoinflip,
@@ -698,10 +597,10 @@ function buildPvPCoinflipTransaction(action, options) {
698
597
  arguments: [
699
598
  joinOptions.gameId,
700
599
  joinOptions.config.packageIds.sweetHouse,
701
- betCoin,
600
+ tx.add(joinOptions.betCoin),
702
601
  encodedMetadata.keys,
703
602
  encodedMetadata.values,
704
- joinOptions.extraObjectId
603
+ priceInfoObjectId
705
604
  ]
706
605
  })
707
606
  );
@@ -754,7 +653,7 @@ function play4(options) {
754
653
 
755
654
  // src/transactions/range.ts
756
655
  function buildRangeTransaction(options) {
757
- const scale = options.scale ?? RANGE_FIXED_POINT_SCALE;
656
+ const scale = options.scale ?? DEFAULT_RANGE_SCALE;
758
657
  const leftPoint = Math.round(options.leftPoint * scale);
759
658
  const rightPoint = Math.round(options.rightPoint * scale);
760
659
  return buildSharedStandardGameBetTransaction({
@@ -843,32 +742,20 @@ function buildWheelTransaction(options) {
843
742
  })(tx)
844
743
  });
845
744
  }
846
- var $moduleName3 = "0x0000000000000000000000000000000000000000000000000000000000000001::type_name";
847
- var TypeName2 = new MoveStruct({ name: `${$moduleName3}::TypeName`, fields: {
745
+ var $moduleName5 = "0x0000000000000000000000000000000000000000000000000000000000000001::type_name";
746
+ var TypeName2 = new MoveStruct({ name: `${$moduleName5}::TypeName`, fields: {
848
747
  name: bcs.string()
849
748
  } });
850
- var $moduleName4 = "0xf391858d2a08473e8d4defcc8df89976bd7b123d3865c6b9341b237f7853dbbc::i64";
851
- var I64 = new MoveStruct({ name: `${$moduleName4}::I64`, fields: {
852
- bits: bcs.u64()
853
- } });
854
-
855
- // src/contracts/core/float.ts
856
- var $moduleName5 = "0xf391858d2a08473e8d4defcc8df89976bd7b123d3865c6b9341b237f7853dbbc::float";
857
- var Float = new MoveStruct({ name: `${$moduleName5}::Float`, fields: {
858
- is_negative: bcs.bool(),
859
- exp: I64,
860
- mant: bcs.u64()
861
- } });
862
749
  var $moduleName6 = "0x2::vec_map";
863
- function Entry(...typeParameters) {
750
+ function Entry2(...typeParameters) {
864
751
  return new MoveStruct({ name: `${$moduleName6}::Entry<${typeParameters[0].name}, ${typeParameters[1].name}>`, fields: {
865
752
  key: typeParameters[0],
866
753
  value: typeParameters[1]
867
754
  } });
868
755
  }
869
- function VecMap(...typeParameters) {
756
+ function VecMap2(...typeParameters) {
870
757
  return new MoveStruct({ name: `${$moduleName6}::VecMap<${typeParameters[0].name}, ${typeParameters[1].name}>`, fields: {
871
- contents: bcs.vector(Entry(typeParameters[0], typeParameters[1]))
758
+ contents: bcs.vector(Entry2(typeParameters[0], typeParameters[1]))
872
759
  } });
873
760
  }
874
761
 
@@ -881,24 +768,32 @@ var BetResultEvent = new MoveStruct({ name: `${$moduleName7}::BetResultEvent<pha
881
768
  unsafe_oracle_usd_coin_price: Float,
882
769
  adjusted_oracle_usd_coin_price: Float,
883
770
  outcome_amount: bcs.u64(),
884
- game_details: VecMap(bcs.string(), bcs.vector(bcs.u8())),
885
- metadata: VecMap(bcs.string(), bcs.vector(bcs.u8()))
771
+ game_details: VecMap2(bcs.string(), bcs.vector(bcs.u8())),
772
+ metadata: VecMap2(bcs.string(), bcs.vector(bcs.u8()))
886
773
  } });
774
+
775
+ // src/client.ts
887
776
  function suigar({
888
- name = "suigar"
777
+ name = "suigar",
778
+ partner
889
779
  } = {}) {
890
780
  return {
891
781
  name,
892
782
  register: (client) => {
893
- return new SuigarClient({ client });
783
+ return new SuigarClient({ client, partner });
894
784
  }
895
785
  };
896
786
  }
897
787
  var SuigarClient = class {
898
788
  #client;
899
789
  #config;
900
- constructor({ client }) {
790
+ #partner;
791
+ constructor({
792
+ client,
793
+ partner
794
+ }) {
901
795
  this.#client = client;
796
+ this.#partner = partner;
902
797
  const network = this.#client.network;
903
798
  if (!SUPPORTED_SUI_NETWORKS.includes(network)) {
904
799
  throw new Error(`Unsupported network: ${network}`);
@@ -933,9 +828,88 @@ var SuigarClient = class {
933
828
  return toBase64(bytes);
934
829
  }
935
830
  /**
936
- * BCS struct constructors for decoding Suigar events emitted on-chain.
831
+ * Lists unresolved PvP coinflip games from the configured registry and resolves
832
+ * each entry into parsed onchain game state.
833
+ *
834
+ * This fetches dynamic fields from the PvP coinflip registry object, then loads
835
+ * each referenced game object through `resolvePvPConflipGame()`. Registry
836
+ * membership is the unresolved-state signal: when a game is joined and resolved,
837
+ * the Move flow removes it from the registry and deletes the live `Game` object.
838
+ * Use this when a product needs the current set of open PvP coinflip matches for
839
+ * browsing or lobby views.
840
+ *
841
+ * @param options Optional dynamic field pagination forwarded to `listDynamicFields()`, excluding `parentId`.
842
+ * Pass `rejectOnError: 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.
845
+ * @returns Parsed unresolved PvP coinflip game objects for the requested
846
+ * registry page. When `rejectOnError` is `false`, entries that fail
847
+ * `resolvePvPConflipGame()` are omitted from the returned array.
848
+ */
849
+ async getPvPCoinflipGames(options = {
850
+ limit: 50
851
+ }) {
852
+ const { rejectOnError = false, ...listOptions } = options;
853
+ const { dynamicFields } = await this.#client.core.listDynamicFields({
854
+ parentId: this.#config.registryIds.pvpCoinflip,
855
+ ...listOptions
856
+ });
857
+ if (rejectOnError) {
858
+ return Promise.all(
859
+ dynamicFields.map(({ childId }) => this.resolvePvPConflipGame(childId))
860
+ );
861
+ }
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] : []
867
+ );
868
+ }
869
+ /**
870
+ * Fetches a PvP coinflip game object from chain and parses it into the SDK's
871
+ * normalized runtime shape.
872
+ *
873
+ * This resolves the raw object through the configured client, requires the
874
+ * object's `content` to be present, decodes that content with the generated
875
+ * `PvPCoinflipGame` BCS parser, and normalizes the generic coin type into a
876
+ * standard struct tag string. Use this when a product needs the current state
877
+ * of a specific PvP coinflip match before rendering join, cancel, or result UI.
878
+ *
879
+ * @param gameId On-chain object id of the PvP coinflip game.
880
+ * @returns Parsed PvP coinflip game state with a normalized `coinType`.
881
+ * @throws Error If the object cannot be decoded because no content was returned.
882
+ */
883
+ async resolvePvPConflipGame(gameId) {
884
+ const { object } = await this.#client.core.getObject({
885
+ objectId: gameId,
886
+ include: { content: true }
887
+ });
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
+ };
895
+ }
896
+ /**
897
+ * BCS struct constructors for decoding on-chain objects and events related to Suigar games.
898
+ *
899
+ * These can be used to parse the `content` field of on-chain objects and events into structured data with the
900
+ * expected types. For example, use `client.suigar.bcs.PvPCoinflipGame.parse(object.content)` to decode a PvP
901
+ * coinflip game object.
902
+ *
903
+ * Note that these constructors are not meant for encoding transaction arguments, as the SDK's transaction
904
+ * builders handle argument serialization internally. Use these primarily for decoding and parsing on-chain data.
937
905
  */
938
906
  bcs = {
907
+ // Objects
908
+ /**
909
+ * Object representing the state of a PvP coinflip game, as stored on-chain.
910
+ */
911
+ PvPCoinflipGame: Game,
912
+ // Events
939
913
  /**
940
914
  * Event emitted at the end of a standard game (e.g., Coinflip, Limbo), containing the result and payout information.
941
915
  */
@@ -969,27 +943,32 @@ var SuigarClient = class {
969
943
  case "coinflip":
970
944
  return buildCoinflipTransaction({
971
945
  ...options,
972
- config: this.#config
946
+ config: this.#config,
947
+ partner: this.#partner
973
948
  });
974
949
  case "limbo":
975
950
  return buildLimboTransaction({
976
951
  ...options,
977
- config: this.#config
952
+ config: this.#config,
953
+ partner: this.#partner
978
954
  });
979
955
  case "plinko":
980
956
  return buildPlinkoTransaction({
981
957
  ...options,
982
- config: this.#config
958
+ config: this.#config,
959
+ partner: this.#partner
983
960
  });
984
961
  case "range":
985
962
  return buildRangeTransaction({
986
963
  ...options,
987
- config: this.#config
964
+ config: this.#config,
965
+ partner: this.#partner
988
966
  });
989
967
  case "wheel":
990
968
  return buildWheelTransaction({
991
969
  ...options,
992
- config: this.#config
970
+ config: this.#config,
971
+ partner: this.#partner
993
972
  });
994
973
  default:
995
974
  throw new Error(`Unsupported game: ${gameId}`);
@@ -1003,12 +982,45 @@ var SuigarClient = class {
1003
982
  * @returns Prepared PvP coinflip transaction.
1004
983
  */
1005
984
  createPvPCoinflipTransaction: (action, options) => {
1006
- return buildPvPCoinflipTransaction(action, {
1007
- ...options,
1008
- config: this.#config
1009
- });
985
+ switch (action) {
986
+ case "create":
987
+ return buildPvPCoinflipTransaction("create", {
988
+ ...options,
989
+ config: this.#config,
990
+ partner: this.#partner
991
+ });
992
+ case "join": {
993
+ const joinOptions = options;
994
+ return buildPvPCoinflipTransaction("join", {
995
+ ...joinOptions,
996
+ betCoin: this.#createPvPCoinflipBetCoin(joinOptions),
997
+ config: this.#config,
998
+ partner: this.#partner
999
+ });
1000
+ }
1001
+ case "cancel":
1002
+ return buildPvPCoinflipTransaction("cancel", {
1003
+ ...options,
1004
+ config: this.#config,
1005
+ partner: this.#partner
1006
+ });
1007
+ default:
1008
+ throw new Error(`Unsupported PvP coinflip action: ${action}`);
1009
+ }
1010
1010
  }
1011
1011
  };
1012
+ #createPvPCoinflipBetCoin(options) {
1013
+ return async (tx) => {
1014
+ const { stake_per_player } = await this.resolvePvPConflipGame(
1015
+ options.gameId
1016
+ );
1017
+ return tx.coin({
1018
+ type: options.coinType,
1019
+ balance: BigInt(stake_per_player),
1020
+ useGasCoin: options.allowGasCoinShortcut
1021
+ });
1022
+ };
1023
+ }
1012
1024
  };
1013
1025
 
1014
- export { suigar };
1026
+ export { SuigarClient, suigar };