@block52/poker-vm-sdk 1.2.6 → 1.2.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/dist/index.js CHANGED
@@ -55937,6 +55937,9 @@ exports.NonPlayerActionType = void 0;
55937
55937
  NonPlayerActionType["LEAVE"] = "leave";
55938
55938
  NonPlayerActionType["NEW_HAND"] = "new-hand";
55939
55939
  NonPlayerActionType["SIT_IN"] = "sit-in";
55940
+ // Sit in and wait for the big blind — distinct action from SIT_IN (post now)
55941
+ // so each has a single responsibility. Sets WAITING_FOR_BIG_BLIND. (#2139)
55942
+ NonPlayerActionType["SIT_IN_AND_WAIT"] = "sit-in-and-wait";
55940
55943
  NonPlayerActionType["SIT_OUT"] = "sit-out";
55941
55944
  NonPlayerActionType["TOP_UP"] = "top-up";
55942
55945
  })(exports.NonPlayerActionType || (exports.NonPlayerActionType = {}));
@@ -55975,6 +55978,11 @@ exports.PlayerStatus = void 0;
55975
55978
  PlayerStatus["SEATED"] = "seated";
55976
55979
  PlayerStatus["SITTING_OUT"] = "sitting-out";
55977
55980
  PlayerStatus["SITTING_IN"] = "sitting-in";
55981
+ // Joined/returning player who opted to wait for the big blind. Held across
55982
+ // hands as a non-playing status (like SITTING_IN) until the button rotates
55983
+ // the BB onto their seat, at which point reInit() activates them and they
55984
+ // post the big blind via the normal ante flow. (#2139)
55985
+ PlayerStatus["WAITING_FOR_BIG_BLIND"] = "waiting-for-big-blind";
55978
55986
  PlayerStatus["SHOWING"] = "showing";
55979
55987
  })(exports.PlayerStatus || (exports.PlayerStatus = {}));
55980
55988
  const SIT_IN_METHOD_NEXT_BB = "next-bb";
@@ -56430,10 +56438,10 @@ class PokerSolver {
56430
56438
  const isFlush = suitCounts.size === 1;
56431
56439
  const isStraight = this.isStraight(sortedCards);
56432
56440
  const isLowStraight = this.isLowStraight(sortedCards); // A-2-3-4-5
56433
- // Check for straight flush and royal flush
56434
- if (isFlush && isStraight) {
56435
- const highRank = this.getHighRank(sortedCards[0].rank);
56436
- if (highRank === 14 && this.getHighRank(sortedCards[1].rank) === 13) {
56441
+ // Check for straight flush and royal flush (including the wheel A-2-3-4-5)
56442
+ if (isFlush && (isStraight || isLowStraight)) {
56443
+ // Royal flush is the high-ace straight only (A-K-Q-J-T), never the wheel
56444
+ if (isStraight && this.getHighRank(sortedCards[0].rank) === 14 && this.getHighRank(sortedCards[1].rank) === 13) {
56437
56445
  return {
56438
56446
  handType: exports.HandType.ROYAL_FLUSH,
56439
56447
  bestHand: sortedCards,
@@ -56591,7 +56599,8 @@ class PokerSolver {
56591
56599
  }
56592
56600
  /**
56593
56601
  * Evaluate preflop hand (2 hole cards only)
56594
- * Returns descriptive hand names like "Pocket Aces", "Suited Connectors"
56602
+ * Returns descriptive hand names like "Pocket Aces" for pairs, or a simple
56603
+ * "X high" description (e.g. "6 high") for everything else
56595
56604
  */
56596
56605
  static evaluatePreflopHand(cards) {
56597
56606
  if (cards.length !== 2) {
@@ -56603,8 +56612,6 @@ class PokerSolver {
56603
56612
  const highRank = Math.max(rank1, rank2);
56604
56613
  const lowRank = Math.min(rank1, rank2);
56605
56614
  const isPair = rank1 === rank2;
56606
- const isSuited = card1.suit === card2.suit;
56607
- const gap = highRank - lowRank;
56608
56615
  let description;
56609
56616
  let handType;
56610
56617
  if (isPair) {
@@ -56613,25 +56620,8 @@ class PokerSolver {
56613
56620
  description = `Pocket ${rankName}s`;
56614
56621
  handType = exports.HandType.PAIR;
56615
56622
  }
56616
- else if (isSuited) {
56617
- if (gap === 1) {
56618
- description = `${this.formatRank(highRank)} - ${this.formatRank(lowRank)} Suited Connectors`;
56619
- }
56620
- else if (gap === 2) {
56621
- description = `${this.formatRank(highRank)} - ${this.formatRank(lowRank)} Suited One-Gapper`;
56622
- }
56623
- else {
56624
- description = `${this.formatRank(highRank)} - ${this.formatRank(lowRank)} Suited`;
56625
- }
56626
- handType = exports.HandType.HIGH_CARD;
56627
- }
56628
56623
  else {
56629
- if (gap === 1) {
56630
- description = `${this.formatRank(highRank)} - ${this.formatRank(lowRank)} Connectors`;
56631
- }
56632
- else {
56633
- description = `${this.formatRank(highRank)} - ${this.formatRank(lowRank)} Offsuit`;
56634
- }
56624
+ description = `${this.formatRank(highRank)} high`;
56635
56625
  handType = exports.HandType.HIGH_CARD;
56636
56626
  }
56637
56627
  // Sort cards by rank for bestHand
@@ -60825,6 +60815,25 @@ class SigningCosmosClient extends CosmosClient {
60825
60815
  * Create a new poker game
60826
60816
  */
60827
60817
  async createGame(gameFormat, gameVariant, minPlayers, maxPlayers, minBuyInB52USDC, maxBuyInB52USDC, smallBlindB52USDC, bigBlindB52USDC, timeout, rakeConfig, sngConfig) {
60818
+ // Validate SNG/Tournament config BEFORE any network work — fail fast.
60819
+ // SNG/Tournament games are DEFINED by startingStack + blindLevelDuration.
60820
+ // Refuse to create one with missing/zero values rather than silently
60821
+ // defaulting (Long.UZERO / 0) — a zero startingStack makes the prize pool
60822
+ // zero (PayoutManager.totalPrizePool = startingStack * runners) and pays
60823
+ // the winner $0; a zero blindLevelDuration breaks blind escalation.
60824
+ // No defaults — fail loud at creation (Commandment #7). (#2282)
60825
+ const isSng = gameFormat === exports.GameFormat.SIT_AND_GO || gameFormat === exports.GameFormat.TOURNAMENT;
60826
+ if (isSng) {
60827
+ if (!sngConfig) {
60828
+ throw new Error(`${gameFormat} games require an sngConfig (startingStack + blindLevelDuration).`);
60829
+ }
60830
+ if (sngConfig.startingStack <= 0n) {
60831
+ throw new Error(`${gameFormat} games require a positive startingStack; got ${sngConfig.startingStack}.`);
60832
+ }
60833
+ if (!sngConfig.blindLevelDuration || sngConfig.blindLevelDuration <= 0) {
60834
+ throw new Error(`${gameFormat} games require a positive blindLevelDuration; got ${sngConfig.blindLevelDuration}.`);
60835
+ }
60836
+ }
60828
60837
  await this.initializeSigningClient();
60829
60838
  if (!this.signingClient || !this.wallet) {
60830
60839
  throw new Error("Signing client not initialized");
@@ -61188,6 +61197,94 @@ class SigningCosmosClient extends CosmosClient {
61188
61197
  const base64 = encoding.toBase64(txExports.TxRaw.encode(txRaw).finish());
61189
61198
  return { base64, sequence: explicit.sequence, accountNumber: explicit.accountNumber };
61190
61199
  }
61200
+ /**
61201
+ * Resolves the signer data (account number + sequence + chain id) for a
61202
+ * sign-only message: uses the caller-supplied data when present (the
61203
+ * gateway settlement path tracks sequence locally so optimistic actions
61204
+ * don't query the stale committed value), else queries the account once.
61205
+ */
61206
+ async resolveSignerData(player, signerData) {
61207
+ if (signerData) {
61208
+ return signerData;
61209
+ }
61210
+ const accountInfo = await this.getAccount(player);
61211
+ return {
61212
+ accountNumber: Number(accountInfo.account.account_number),
61213
+ sequence: Number(accountInfo.account.sequence),
61214
+ chainId: this.config.chainId
61215
+ };
61216
+ }
61217
+ /**
61218
+ * Signs a single cosmos message (no broadcast) and returns the base64 TxRaw
61219
+ * plus the signer data used — the sign-only primitive the money-mover
61220
+ * helpers below share with signPerformAction's gateway-settlement pattern.
61221
+ */
61222
+ async signMsgOnly(msg, memo, signerData) {
61223
+ await this.initializeSigningClient();
61224
+ if (!this.signingClient || !this.wallet) {
61225
+ throw new Error("Signing client not initialized");
61226
+ }
61227
+ const [account] = await this.wallet.getAccounts();
61228
+ const player = account.address;
61229
+ const explicit = await this.resolveSignerData(player, signerData);
61230
+ const txRaw = await this.signingClient.sign(player, [msg], gaslessFee(), memo, explicit);
61231
+ const base64 = encoding.toBase64(txExports.TxRaw.encode(txRaw).finish());
61232
+ return { base64, sequence: explicit.sequence, accountNumber: explicit.accountNumber };
61233
+ }
61234
+ /**
61235
+ * Sign-only MsgJoinGame: builds and signs the player's buy-in tx WITHOUT
61236
+ * broadcasting, returning the base64 TxRaw for the gateway to relay
61237
+ * (WS-first money-mover settlement, block52/poker-vm#2325). The player is
61238
+ * the signer — the gateway never moves funds on their behalf. Mirrors
61239
+ * joinGame()'s message shape and signPerformAction()'s sign-only return.
61240
+ */
61241
+ async signJoinGame(gameId, seat, buyInAmount, signerData) {
61242
+ await this.initializeSigningClient();
61243
+ const [account] = await this.wallet.getAccounts();
61244
+ const msg = {
61245
+ typeUrl: "/pokerchain.poker.v1.MsgJoinGame",
61246
+ value: {
61247
+ player: account.address,
61248
+ gameId,
61249
+ seat: Long.fromNumber(seat, true),
61250
+ buyInAmount: Long.fromString(buyInAmount.toString(), true)
61251
+ }
61252
+ };
61253
+ return this.signMsgOnly(msg, "Join poker game (relay)", signerData);
61254
+ }
61255
+ /**
61256
+ * Sign-only MsgLeaveGame (no broadcast) — the chain decides the refund
61257
+ * from its own state; the message carries only {creator, gameId}. (#2325)
61258
+ */
61259
+ async signLeaveGame(gameId, signerData) {
61260
+ await this.initializeSigningClient();
61261
+ const [account] = await this.wallet.getAccounts();
61262
+ const msg = {
61263
+ typeUrl: "/pokerchain.poker.v1.MsgLeaveGame",
61264
+ value: {
61265
+ creator: account.address,
61266
+ gameId
61267
+ }
61268
+ };
61269
+ return this.signMsgOnly(msg, "Leave poker game (relay)", signerData);
61270
+ }
61271
+ /**
61272
+ * Sign-only MsgTopUp (no broadcast) — escrow deposit added to the player's
61273
+ * stack; gateway relays it after PVM-verifying the optimistic apply. (#2325)
61274
+ */
61275
+ async signTopUp(gameId, amount, signerData) {
61276
+ await this.initializeSigningClient();
61277
+ const [account] = await this.wallet.getAccounts();
61278
+ const msg = {
61279
+ typeUrl: "/pokerchain.poker.v1.MsgTopUp",
61280
+ value: {
61281
+ player: account.address,
61282
+ gameId,
61283
+ amount: Long.fromString(amount.toString(), true)
61284
+ }
61285
+ };
61286
+ return this.signMsgOnly(msg, "Top up poker stack (relay)", signerData);
61287
+ }
61191
61288
  /**
61192
61289
  * Top up a player's stack at a table
61193
61290
  * The player must be seated at the table and have sufficient wallet balance.