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

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`);
169
+ if (Array.isArray(value)) {
170
+ return value;
183
171
  }
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`);
172
+ if (typeof value === "string" && ADDRESS_METADATA_KEYS.has(key)) {
173
+ return Array.from(parseHexAddress(value) ?? textEncoder.encode(value));
189
174
  }
190
- return value;
175
+ return Array.from(textEncoder.encode(String(value)));
191
176
  }
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
- }
230
- }
231
- return null;
232
- }
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,74 @@ 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
+ * @returns Parsed unresolved PvP coinflip game objects for the requested registry page.
843
+ */
844
+ async getPvPCoinflipGames(options = {
845
+ limit: 50
846
+ }) {
847
+ const { dynamicFields } = await this.#client.core.listDynamicFields({
848
+ parentId: this.#config.registryIds.pvpCoinflip,
849
+ ...options
850
+ });
851
+ return await Promise.all(
852
+ dynamicFields.map(({ childId }) => this.resolvePvPConflipGame(childId))
853
+ );
854
+ }
855
+ /**
856
+ * Fetches a PvP coinflip game object from chain and parses it into the SDK's
857
+ * normalized runtime shape.
858
+ *
859
+ * This resolves the raw object through the configured client, requires the
860
+ * object's `content` to be present, decodes that content with the generated
861
+ * `PvPCoinflipGame` BCS parser, and normalizes the generic coin type into a
862
+ * standard struct tag string. Use this when a product needs the current state
863
+ * of a specific PvP coinflip match before rendering join, cancel, or result UI.
864
+ *
865
+ * @param gameId On-chain object id of the PvP coinflip game.
866
+ * @returns Parsed PvP coinflip game state with a normalized `coinType`.
867
+ * @throws Error If the object cannot be decoded because no content was returned.
868
+ */
869
+ async resolvePvPConflipGame(gameId) {
870
+ const { object } = await this.#client.core.getObject({
871
+ objectId: gameId,
872
+ include: { content: true }
873
+ });
874
+ if (!object.content) {
875
+ throw new Error("Unable to resolve PvP coinflip from game object");
876
+ }
877
+ return {
878
+ ...Game.parse(object.content),
879
+ coinType: normalizeStructTag(parseStructTag(object.type).typeParams[0])
880
+ };
881
+ }
882
+ /**
883
+ * BCS struct constructors for decoding on-chain objects and events related to Suigar games.
884
+ *
885
+ * These can be used to parse the `content` field of on-chain objects and events into structured data with the
886
+ * expected types. For example, use `client.suigar.bcs.PvPCoinflipGame.parse(object.content)` to decode a PvP
887
+ * coinflip game object.
888
+ *
889
+ * Note that these constructors are not meant for encoding transaction arguments, as the SDK's transaction
890
+ * builders handle argument serialization internally. Use these primarily for decoding and parsing on-chain data.
937
891
  */
938
892
  bcs = {
893
+ // Objects
894
+ /**
895
+ * Object representing the state of a PvP coinflip game, as stored on-chain.
896
+ */
897
+ PvPCoinflipGame: Game,
898
+ // Events
939
899
  /**
940
900
  * Event emitted at the end of a standard game (e.g., Coinflip, Limbo), containing the result and payout information.
941
901
  */
@@ -969,27 +929,32 @@ var SuigarClient = class {
969
929
  case "coinflip":
970
930
  return buildCoinflipTransaction({
971
931
  ...options,
972
- config: this.#config
932
+ config: this.#config,
933
+ partner: this.#partner
973
934
  });
974
935
  case "limbo":
975
936
  return buildLimboTransaction({
976
937
  ...options,
977
- config: this.#config
938
+ config: this.#config,
939
+ partner: this.#partner
978
940
  });
979
941
  case "plinko":
980
942
  return buildPlinkoTransaction({
981
943
  ...options,
982
- config: this.#config
944
+ config: this.#config,
945
+ partner: this.#partner
983
946
  });
984
947
  case "range":
985
948
  return buildRangeTransaction({
986
949
  ...options,
987
- config: this.#config
950
+ config: this.#config,
951
+ partner: this.#partner
988
952
  });
989
953
  case "wheel":
990
954
  return buildWheelTransaction({
991
955
  ...options,
992
- config: this.#config
956
+ config: this.#config,
957
+ partner: this.#partner
993
958
  });
994
959
  default:
995
960
  throw new Error(`Unsupported game: ${gameId}`);
@@ -1003,12 +968,45 @@ var SuigarClient = class {
1003
968
  * @returns Prepared PvP coinflip transaction.
1004
969
  */
1005
970
  createPvPCoinflipTransaction: (action, options) => {
1006
- return buildPvPCoinflipTransaction(action, {
1007
- ...options,
1008
- config: this.#config
1009
- });
971
+ switch (action) {
972
+ case "create":
973
+ return buildPvPCoinflipTransaction("create", {
974
+ ...options,
975
+ config: this.#config,
976
+ partner: this.#partner
977
+ });
978
+ case "join": {
979
+ const joinOptions = options;
980
+ return buildPvPCoinflipTransaction("join", {
981
+ ...joinOptions,
982
+ betCoin: this.#createPvPCoinflipBetCoin(joinOptions),
983
+ config: this.#config,
984
+ partner: this.#partner
985
+ });
986
+ }
987
+ case "cancel":
988
+ return buildPvPCoinflipTransaction("cancel", {
989
+ ...options,
990
+ config: this.#config,
991
+ partner: this.#partner
992
+ });
993
+ default:
994
+ throw new Error(`Unsupported PvP coinflip action: ${action}`);
995
+ }
1010
996
  }
1011
997
  };
998
+ #createPvPCoinflipBetCoin(options) {
999
+ return async (tx) => {
1000
+ const { stake_per_player } = await this.resolvePvPConflipGame(
1001
+ options.gameId
1002
+ );
1003
+ return tx.coin({
1004
+ type: options.coinType,
1005
+ balance: BigInt(stake_per_player),
1006
+ useGasCoin: options.allowGasCoinShortcut
1007
+ });
1008
+ };
1009
+ }
1012
1010
  };
1013
1011
 
1014
- export { suigar };
1012
+ export { SuigarClient, suigar };