@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.d.ts CHANGED
@@ -45218,6 +45218,7 @@ declare enum NonPlayerActionType {
45218
45218
  LEAVE = "leave",
45219
45219
  NEW_HAND = "new-hand",
45220
45220
  SIT_IN = "sit-in",
45221
+ SIT_IN_AND_WAIT = "sit-in-and-wait",
45221
45222
  SIT_OUT = "sit-out",
45222
45223
  TOP_UP = "top-up"
45223
45224
  }
@@ -45229,6 +45230,7 @@ declare const AllPlayerActions: {
45229
45230
  LEAVE: NonPlayerActionType.LEAVE;
45230
45231
  NEW_HAND: NonPlayerActionType.NEW_HAND;
45231
45232
  SIT_IN: NonPlayerActionType.SIT_IN;
45233
+ SIT_IN_AND_WAIT: NonPlayerActionType.SIT_IN_AND_WAIT;
45232
45234
  SIT_OUT: NonPlayerActionType.SIT_OUT;
45233
45235
  TOP_UP: NonPlayerActionType.TOP_UP;
45234
45236
  SMALL_BLIND: PlayerActionType.SMALL_BLIND;
@@ -45272,6 +45274,7 @@ declare enum PlayerStatus {
45272
45274
  SEATED = "seated",
45273
45275
  SITTING_OUT = "sitting-out",
45274
45276
  SITTING_IN = "sitting-in",
45277
+ WAITING_FOR_BIG_BLIND = "waiting-for-big-blind",
45275
45278
  SHOWING = "showing"
45276
45279
  }
45277
45280
  type SitInMethod = "next-bb" | "post-now";
@@ -45974,7 +45977,8 @@ declare class PokerSolver {
45974
45977
  static evaluatePartialHand(cards: Card[]): HandEvaluation;
45975
45978
  /**
45976
45979
  * Evaluate preflop hand (2 hole cards only)
45977
- * Returns descriptive hand names like "Pocket Aces", "Suited Connectors"
45980
+ * Returns descriptive hand names like "Pocket Aces" for pairs, or a simple
45981
+ * "X high" description (e.g. "6 high") for everything else
45978
45982
  */
45979
45983
  private static evaluatePreflopHand;
45980
45984
  /**
@@ -46371,7 +46375,7 @@ interface RakeConfig {
46371
46375
  */
46372
46376
  interface SNGConfig {
46373
46377
  startingStack: bigint;
46374
- blindLevelDuration?: number;
46378
+ blindLevelDuration: number;
46375
46379
  }
46376
46380
  /**
46377
46381
  * Signing Cosmos Client that extends the read-only CosmosClient with transaction capabilities
@@ -46483,6 +46487,49 @@ declare class SigningCosmosClient extends CosmosClient {
46483
46487
  sequence: number;
46484
46488
  accountNumber: number;
46485
46489
  }>;
46490
+ /**
46491
+ * Resolves the signer data (account number + sequence + chain id) for a
46492
+ * sign-only message: uses the caller-supplied data when present (the
46493
+ * gateway settlement path tracks sequence locally so optimistic actions
46494
+ * don't query the stale committed value), else queries the account once.
46495
+ */
46496
+ private resolveSignerData;
46497
+ /**
46498
+ * Signs a single cosmos message (no broadcast) and returns the base64 TxRaw
46499
+ * plus the signer data used — the sign-only primitive the money-mover
46500
+ * helpers below share with signPerformAction's gateway-settlement pattern.
46501
+ */
46502
+ private signMsgOnly;
46503
+ /**
46504
+ * Sign-only MsgJoinGame: builds and signs the player's buy-in tx WITHOUT
46505
+ * broadcasting, returning the base64 TxRaw for the gateway to relay
46506
+ * (WS-first money-mover settlement, block52/poker-vm#2325). The player is
46507
+ * the signer — the gateway never moves funds on their behalf. Mirrors
46508
+ * joinGame()'s message shape and signPerformAction()'s sign-only return.
46509
+ */
46510
+ signJoinGame(gameId: string, seat: number, buyInAmount: bigint, signerData?: SignerData): Promise<{
46511
+ base64: string;
46512
+ sequence: number;
46513
+ accountNumber: number;
46514
+ }>;
46515
+ /**
46516
+ * Sign-only MsgLeaveGame (no broadcast) — the chain decides the refund
46517
+ * from its own state; the message carries only {creator, gameId}. (#2325)
46518
+ */
46519
+ signLeaveGame(gameId: string, signerData?: SignerData): Promise<{
46520
+ base64: string;
46521
+ sequence: number;
46522
+ accountNumber: number;
46523
+ }>;
46524
+ /**
46525
+ * Sign-only MsgTopUp (no broadcast) — escrow deposit added to the player's
46526
+ * stack; gateway relays it after PVM-verifying the optimistic apply. (#2325)
46527
+ */
46528
+ signTopUp(gameId: string, amount: bigint, signerData?: SignerData): Promise<{
46529
+ base64: string;
46530
+ sequence: number;
46531
+ accountNumber: number;
46532
+ }>;
46486
46533
  /**
46487
46534
  * Top up a player's stack at a table
46488
46535
  * The player must be seated at the table and have sufficient wallet balance.
package/dist/index.esm.js CHANGED
@@ -55935,6 +55935,9 @@ var NonPlayerActionType;
55935
55935
  NonPlayerActionType["LEAVE"] = "leave";
55936
55936
  NonPlayerActionType["NEW_HAND"] = "new-hand";
55937
55937
  NonPlayerActionType["SIT_IN"] = "sit-in";
55938
+ // Sit in and wait for the big blind — distinct action from SIT_IN (post now)
55939
+ // so each has a single responsibility. Sets WAITING_FOR_BIG_BLIND. (#2139)
55940
+ NonPlayerActionType["SIT_IN_AND_WAIT"] = "sit-in-and-wait";
55938
55941
  NonPlayerActionType["SIT_OUT"] = "sit-out";
55939
55942
  NonPlayerActionType["TOP_UP"] = "top-up";
55940
55943
  })(NonPlayerActionType || (NonPlayerActionType = {}));
@@ -55973,6 +55976,11 @@ var PlayerStatus;
55973
55976
  PlayerStatus["SEATED"] = "seated";
55974
55977
  PlayerStatus["SITTING_OUT"] = "sitting-out";
55975
55978
  PlayerStatus["SITTING_IN"] = "sitting-in";
55979
+ // Joined/returning player who opted to wait for the big blind. Held across
55980
+ // hands as a non-playing status (like SITTING_IN) until the button rotates
55981
+ // the BB onto their seat, at which point reInit() activates them and they
55982
+ // post the big blind via the normal ante flow. (#2139)
55983
+ PlayerStatus["WAITING_FOR_BIG_BLIND"] = "waiting-for-big-blind";
55976
55984
  PlayerStatus["SHOWING"] = "showing";
55977
55985
  })(PlayerStatus || (PlayerStatus = {}));
55978
55986
  const SIT_IN_METHOD_NEXT_BB = "next-bb";
@@ -56428,10 +56436,10 @@ class PokerSolver {
56428
56436
  const isFlush = suitCounts.size === 1;
56429
56437
  const isStraight = this.isStraight(sortedCards);
56430
56438
  const isLowStraight = this.isLowStraight(sortedCards); // A-2-3-4-5
56431
- // Check for straight flush and royal flush
56432
- if (isFlush && isStraight) {
56433
- const highRank = this.getHighRank(sortedCards[0].rank);
56434
- if (highRank === 14 && this.getHighRank(sortedCards[1].rank) === 13) {
56439
+ // Check for straight flush and royal flush (including the wheel A-2-3-4-5)
56440
+ if (isFlush && (isStraight || isLowStraight)) {
56441
+ // Royal flush is the high-ace straight only (A-K-Q-J-T), never the wheel
56442
+ if (isStraight && this.getHighRank(sortedCards[0].rank) === 14 && this.getHighRank(sortedCards[1].rank) === 13) {
56435
56443
  return {
56436
56444
  handType: HandType.ROYAL_FLUSH,
56437
56445
  bestHand: sortedCards,
@@ -56589,7 +56597,8 @@ class PokerSolver {
56589
56597
  }
56590
56598
  /**
56591
56599
  * Evaluate preflop hand (2 hole cards only)
56592
- * Returns descriptive hand names like "Pocket Aces", "Suited Connectors"
56600
+ * Returns descriptive hand names like "Pocket Aces" for pairs, or a simple
56601
+ * "X high" description (e.g. "6 high") for everything else
56593
56602
  */
56594
56603
  static evaluatePreflopHand(cards) {
56595
56604
  if (cards.length !== 2) {
@@ -56601,8 +56610,6 @@ class PokerSolver {
56601
56610
  const highRank = Math.max(rank1, rank2);
56602
56611
  const lowRank = Math.min(rank1, rank2);
56603
56612
  const isPair = rank1 === rank2;
56604
- const isSuited = card1.suit === card2.suit;
56605
- const gap = highRank - lowRank;
56606
56613
  let description;
56607
56614
  let handType;
56608
56615
  if (isPair) {
@@ -56611,25 +56618,8 @@ class PokerSolver {
56611
56618
  description = `Pocket ${rankName}s`;
56612
56619
  handType = HandType.PAIR;
56613
56620
  }
56614
- else if (isSuited) {
56615
- if (gap === 1) {
56616
- description = `${this.formatRank(highRank)} - ${this.formatRank(lowRank)} Suited Connectors`;
56617
- }
56618
- else if (gap === 2) {
56619
- description = `${this.formatRank(highRank)} - ${this.formatRank(lowRank)} Suited One-Gapper`;
56620
- }
56621
- else {
56622
- description = `${this.formatRank(highRank)} - ${this.formatRank(lowRank)} Suited`;
56623
- }
56624
- handType = HandType.HIGH_CARD;
56625
- }
56626
56621
  else {
56627
- if (gap === 1) {
56628
- description = `${this.formatRank(highRank)} - ${this.formatRank(lowRank)} Connectors`;
56629
- }
56630
- else {
56631
- description = `${this.formatRank(highRank)} - ${this.formatRank(lowRank)} Offsuit`;
56632
- }
56622
+ description = `${this.formatRank(highRank)} high`;
56633
56623
  handType = HandType.HIGH_CARD;
56634
56624
  }
56635
56625
  // Sort cards by rank for bestHand
@@ -60823,6 +60813,25 @@ class SigningCosmosClient extends CosmosClient {
60823
60813
  * Create a new poker game
60824
60814
  */
60825
60815
  async createGame(gameFormat, gameVariant, minPlayers, maxPlayers, minBuyInB52USDC, maxBuyInB52USDC, smallBlindB52USDC, bigBlindB52USDC, timeout, rakeConfig, sngConfig) {
60816
+ // Validate SNG/Tournament config BEFORE any network work — fail fast.
60817
+ // SNG/Tournament games are DEFINED by startingStack + blindLevelDuration.
60818
+ // Refuse to create one with missing/zero values rather than silently
60819
+ // defaulting (Long.UZERO / 0) — a zero startingStack makes the prize pool
60820
+ // zero (PayoutManager.totalPrizePool = startingStack * runners) and pays
60821
+ // the winner $0; a zero blindLevelDuration breaks blind escalation.
60822
+ // No defaults — fail loud at creation (Commandment #7). (#2282)
60823
+ const isSng = gameFormat === GameFormat.SIT_AND_GO || gameFormat === GameFormat.TOURNAMENT;
60824
+ if (isSng) {
60825
+ if (!sngConfig) {
60826
+ throw new Error(`${gameFormat} games require an sngConfig (startingStack + blindLevelDuration).`);
60827
+ }
60828
+ if (sngConfig.startingStack <= 0n) {
60829
+ throw new Error(`${gameFormat} games require a positive startingStack; got ${sngConfig.startingStack}.`);
60830
+ }
60831
+ if (!sngConfig.blindLevelDuration || sngConfig.blindLevelDuration <= 0) {
60832
+ throw new Error(`${gameFormat} games require a positive blindLevelDuration; got ${sngConfig.blindLevelDuration}.`);
60833
+ }
60834
+ }
60826
60835
  await this.initializeSigningClient();
60827
60836
  if (!this.signingClient || !this.wallet) {
60828
60837
  throw new Error("Signing client not initialized");
@@ -61186,6 +61195,94 @@ class SigningCosmosClient extends CosmosClient {
61186
61195
  const base64 = toBase64(txExports.TxRaw.encode(txRaw).finish());
61187
61196
  return { base64, sequence: explicit.sequence, accountNumber: explicit.accountNumber };
61188
61197
  }
61198
+ /**
61199
+ * Resolves the signer data (account number + sequence + chain id) for a
61200
+ * sign-only message: uses the caller-supplied data when present (the
61201
+ * gateway settlement path tracks sequence locally so optimistic actions
61202
+ * don't query the stale committed value), else queries the account once.
61203
+ */
61204
+ async resolveSignerData(player, signerData) {
61205
+ if (signerData) {
61206
+ return signerData;
61207
+ }
61208
+ const accountInfo = await this.getAccount(player);
61209
+ return {
61210
+ accountNumber: Number(accountInfo.account.account_number),
61211
+ sequence: Number(accountInfo.account.sequence),
61212
+ chainId: this.config.chainId
61213
+ };
61214
+ }
61215
+ /**
61216
+ * Signs a single cosmos message (no broadcast) and returns the base64 TxRaw
61217
+ * plus the signer data used — the sign-only primitive the money-mover
61218
+ * helpers below share with signPerformAction's gateway-settlement pattern.
61219
+ */
61220
+ async signMsgOnly(msg, memo, signerData) {
61221
+ await this.initializeSigningClient();
61222
+ if (!this.signingClient || !this.wallet) {
61223
+ throw new Error("Signing client not initialized");
61224
+ }
61225
+ const [account] = await this.wallet.getAccounts();
61226
+ const player = account.address;
61227
+ const explicit = await this.resolveSignerData(player, signerData);
61228
+ const txRaw = await this.signingClient.sign(player, [msg], gaslessFee(), memo, explicit);
61229
+ const base64 = toBase64(txExports.TxRaw.encode(txRaw).finish());
61230
+ return { base64, sequence: explicit.sequence, accountNumber: explicit.accountNumber };
61231
+ }
61232
+ /**
61233
+ * Sign-only MsgJoinGame: builds and signs the player's buy-in tx WITHOUT
61234
+ * broadcasting, returning the base64 TxRaw for the gateway to relay
61235
+ * (WS-first money-mover settlement, block52/poker-vm#2325). The player is
61236
+ * the signer — the gateway never moves funds on their behalf. Mirrors
61237
+ * joinGame()'s message shape and signPerformAction()'s sign-only return.
61238
+ */
61239
+ async signJoinGame(gameId, seat, buyInAmount, signerData) {
61240
+ await this.initializeSigningClient();
61241
+ const [account] = await this.wallet.getAccounts();
61242
+ const msg = {
61243
+ typeUrl: "/pokerchain.poker.v1.MsgJoinGame",
61244
+ value: {
61245
+ player: account.address,
61246
+ gameId,
61247
+ seat: Long.fromNumber(seat, true),
61248
+ buyInAmount: Long.fromString(buyInAmount.toString(), true)
61249
+ }
61250
+ };
61251
+ return this.signMsgOnly(msg, "Join poker game (relay)", signerData);
61252
+ }
61253
+ /**
61254
+ * Sign-only MsgLeaveGame (no broadcast) — the chain decides the refund
61255
+ * from its own state; the message carries only {creator, gameId}. (#2325)
61256
+ */
61257
+ async signLeaveGame(gameId, signerData) {
61258
+ await this.initializeSigningClient();
61259
+ const [account] = await this.wallet.getAccounts();
61260
+ const msg = {
61261
+ typeUrl: "/pokerchain.poker.v1.MsgLeaveGame",
61262
+ value: {
61263
+ creator: account.address,
61264
+ gameId
61265
+ }
61266
+ };
61267
+ return this.signMsgOnly(msg, "Leave poker game (relay)", signerData);
61268
+ }
61269
+ /**
61270
+ * Sign-only MsgTopUp (no broadcast) — escrow deposit added to the player's
61271
+ * stack; gateway relays it after PVM-verifying the optimistic apply. (#2325)
61272
+ */
61273
+ async signTopUp(gameId, amount, signerData) {
61274
+ await this.initializeSigningClient();
61275
+ const [account] = await this.wallet.getAccounts();
61276
+ const msg = {
61277
+ typeUrl: "/pokerchain.poker.v1.MsgTopUp",
61278
+ value: {
61279
+ player: account.address,
61280
+ gameId,
61281
+ amount: Long.fromString(amount.toString(), true)
61282
+ }
61283
+ };
61284
+ return this.signMsgOnly(msg, "Top up poker stack (relay)", signerData);
61285
+ }
61189
61286
  /**
61190
61287
  * Top up a player's stack at a table
61191
61288
  * The player must be seated at the table and have sufficient wallet balance.