@playmos/sdk 0.3.11 → 0.3.13

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/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@ All notable changes to `@playmos/sdk`. This project adheres to [Semantic Version
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## [0.3.13] — 2026-09-11
8
+
9
+ ### Docs
10
+ - Same-studio key rule (`payment not found`). `payoutAddress` at mint or `POST /v1/studio/payout`. Browser `pay()` + MetaMask catch. Webhook register: `POST /v1/webhook_endpoints` (no signing secret in the response).
11
+ - npm README + package description name the live prepare → sign → register path (**flat 1%**). Types include `bytecode` / `unsignedTx`.
12
+
13
+ ## [0.3.12] — 2026-08-27
14
+
15
+ ### Added
16
+ - **Operator-signed epoch settlement (E1b / sdk#664 / PR #670):** `epochs.getAttestation`, `epochs.executeSettlement`, `epochs.settlementTypedData`. Service `POST`/`GET` `/v1/epochs/:epochId/attestation`. GET is a public board (any authenticated key). POST is `sk_` + studio-gated. Amounts stay micro-USDC strings. Refs #664.
17
+
18
+ ### Notes
19
+ - Hub CI installs from npm, not the monorepo. This tag is what E1c (hub auto-pin before broadcast) consumes.
20
+
7
21
  ## [0.3.11] — 2026-08-09
8
22
 
9
23
  ### Added
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Playmos Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **🧪 Beta — Playmos SDK.** Runs on Base Sepolia **testnet**. The value-movement primitives (escrow / marketplace / transfer) are proven on-chain but **not yet production-hardened**, and nothing is on mainnet. Build and integrate freely against the sandbox; don't route real user funds yet.
4
4
 
5
- Stablecoin payments for games on Base. One SDK for in-app purchases (1%), skill-game prize-pool entries (10%, 60/30/10), and **in-game economies** (player · NPC · agent commerce via `transfer()`). USD in, USDC on-chain — no crypto UX for your players.
5
+ Stablecoin payments for games on Base. **One default path:** `pay()` `verify()` a real `pay_…` id with status `confirmed` (1% Playmos — you keep 99%). No game required. Contests, economies, and timers are **optional**. Skill contests are **flat 1%** on **your** pool. If `rounds.open` is refused, that is expected until you prepare → sign → register your own contest pool. USD in, USDC on-chain — no crypto UX for your players.
6
6
 
7
7
  **Changelog:** see [`CHANGELOG.md`](./CHANGELOG.md) (shipped in the npm tarball from the next publish). **Breaking in 0.3.8:** player-wallet `enterRound` requires `identity` — no silent invent.
8
8
 
@@ -25,9 +25,9 @@ The sandbox API also sends CORS headers so browser `pay()` / `enterRound()` work
25
25
 
26
26
  The public sandbox key `pk_test_playmos_sandbox` runs against a real Playmos test service on Base Sepolia. **You don't need a wallet:** on a `pk_test` key with no `wallet` configured, the SDK routes to a server-settle path where Playmos signs and submits the on-chain transaction for you. You still get a real, confirmed `txHash` — just signed by the service. No wallet, no gas, no crypto.
27
27
 
28
- The key comes wired to two demo games: `game_sandbox_iap` (IAP) and `game_sandbox_skill` (prize pool).
28
+ The public key is wired to `game_sandbox_iap`. Skill entry (`game_sandbox_skill`) is an optional later path — not the first-hour default.
29
29
 
30
- ### In-app purchase — `pay()`
30
+ ### In-app purchase — `pay()` (the front door)
31
31
 
32
32
  <!-- snippet:pay -->
33
33
  ```ts
@@ -38,15 +38,22 @@ import { Playmos } from "@playmos/sdk";
38
38
  const playmos = new Playmos({ apiKey: "pk_test_playmos_sandbox" });
39
39
 
40
40
  const payment = await playmos.pay({
41
- gameId: "game_sandbox_iap", // public sandbox IAP game include it (this key spans IAP + skill)
41
+ gameId: "game_sandbox_iap", // required for the public sandbox key
42
42
  amount: "0.99", // USD string — sandbox server-settle cap $1.00/request
43
43
  sku: "gems_500", // your product id
44
- playerId: "player_abc", // your opaque user id
44
+ playerId: "player_" + Date.now(),
45
45
  });
46
46
 
47
- payment.id; // "pay_…" — real, server-issued (ULID)
48
- payment.status; // "confirmed" — real, on Base Sepolia
49
- payment.txHash; // 0x… — open on sepolia.basescan.org/tx/{txHash}
47
+ let result = await playmos.verify(payment.id);
48
+ let tries = 30;
49
+ while (result.status !== "confirmed" && tries !== 0) {
50
+ await new Promise((r) => setTimeout(r, 500));
51
+ result = await playmos.verify(payment.id);
52
+ tries -= 1;
53
+ }
54
+
55
+ console.log({ id: payment.id, status: result.status, tx: payment.txHash });
56
+ // You won: pay_… + confirmed on Base Sepolia
50
57
  ```
51
58
 
52
59
  ### Verify before you grant
@@ -68,7 +75,7 @@ if (result.status === "confirmed") {
68
75
  }
69
76
  ```
70
77
 
71
- ### Skill-game entry `enterRound()`
78
+ ### Optional later — skill-game entry (`enterRound()`)
72
79
 
73
80
  ```ts
74
81
  const entry = await playmos.enterRound({
@@ -77,9 +84,21 @@ const entry = await playmos.enterRound({
77
84
  amount: "1.00", // grows this round's pool
78
85
  playerId: "player_abc",
79
86
  });
80
- // entry.status === "confirmed"; entry.split is the on-chain 60/30/10 breakdown
87
+ // entry.status === "confirmed". Public sandbox skill is a shared Playmos pool — not your contest.
88
+ // Your 1% contest is live only after you register your own pool (next section).
81
89
  ```
82
90
 
91
+ ### Your own contest pool — `epochs.preparePool` (you sign)
92
+
93
+ `@playmos/sdk` **0.3.13** ships `epochs.preparePool` with `bytecode` / `unsignedTx` on the typed response. It calls the live API. Playmos sets `broadcast: false` and does **not** send the transaction.
94
+
95
+ 1. Fund your studio wallet on Base Sepolia (ETH + test USDC). Playmos has no faucet — use [Coinbase's faucet docs](https://docs.cdp.coinbase.com/faucets/introduction/welcome).
96
+ 2. Call `epochs.preparePool({ studioWallet })` or `POST /v1/epochs/pools/prepare`. Use `feeSink` from that response (`0xD84c190085aa59c48a9B478Ea333D50B8DF4aD42`).
97
+ 3. Sign `unsignedTx` in your wallet and send it.
98
+ 4. `epochs.registerPool` with `walletProof`, then open / enter **your** game — not the shared sandbox game.
99
+
100
+ Full steps: https://playmos-docs-public.vercel.app/docs#studio-pool-prepare
101
+
83
102
  ### Move USDC between wallets — `transfer()`
84
103
 
85
104
  The base value-movement primitive: move USDC from one wallet to another with a configurable per-call fee. The **game logic is the authority** — you already decided the move is valid — so this is a direct, unconditional push (reach for `escrow`/`marketplace` when a trust boundary needs fair exchange). Settled through the on-chain `PlaymosTransfer` contract; the split is verifiable on BaseScan.
@@ -280,8 +299,8 @@ The escrow/marketplace resolve endpoints (release/refund/confirm) return a deter
280
299
 
281
300
  ## Docs
282
301
 
283
- Full developer docs (install, IAP `pay()`, skill `enterRound()`, agents, webhooks, REST) — **public, no login**:
302
+ Full developer docs (install, IAP `pay()`, skill `enterRound()`, your own contest pool, agents, webhooks, REST) — **public, no login**:
284
303
 
285
- **https://playmos-docs-public.vercel.app/docs**
304
+ **https://playmos-docs-public.vercel.app/docs** · contest pool: **https://playmos-docs-public.vercel.app/docs#studio-pool-prepare**
286
305
 
287
306
  That is the third-party / stranger surface while we stress-test. Production **`playmos.io/docs`** comes after Founder promote (gate still holds for production only).
@@ -1,4 +1,4 @@
1
- import { numberToHex, keccak256, toBytes, encodeFunctionData } from 'viem';
1
+ import { keccak256, toHex, numberToHex, encodeFunctionData, toBytes, getAddress } from 'viem';
2
2
 
3
3
  // src/errors.ts
4
4
  var PlaymosError = class extends Error {
@@ -81,6 +81,12 @@ var NothingToWithdrawError = class extends PlaymosError {
81
81
  );
82
82
  }
83
83
  };
84
+ function seriesToBytes32(series) {
85
+ const s = series.trim();
86
+ if (/^0x[0-9a-fA-F]{64}$/.test(s)) return s.toLowerCase();
87
+ return keccak256(toHex(s));
88
+ }
89
+ var identityToBytes32 = seriesToBytes32;
84
90
 
85
91
  // src/chain/abis.ts
86
92
  var erc20Abi = [
@@ -219,6 +225,174 @@ async function assertEnoughGas(provider, from, minWei) {
219
225
  }
220
226
  }
221
227
 
228
+ // src/chain/epochPrizePoolAbi.ts
229
+ var epochPrizePoolViewAbi = [
230
+ {
231
+ type: "function",
232
+ name: "currentEpochId",
233
+ stateMutability: "view",
234
+ inputs: [{ name: "series", type: "bytes32" }],
235
+ outputs: [{ type: "uint256" }]
236
+ },
237
+ {
238
+ type: "function",
239
+ name: "epochIdAt",
240
+ stateMutability: "view",
241
+ inputs: [
242
+ { name: "series", type: "bytes32" },
243
+ { name: "timestamp", type: "uint256" }
244
+ ],
245
+ outputs: [{ type: "uint256" }]
246
+ },
247
+ {
248
+ type: "function",
249
+ name: "epochPool",
250
+ stateMutability: "view",
251
+ inputs: [
252
+ { name: "series", type: "bytes32" },
253
+ { name: "epochId", type: "uint256" }
254
+ ],
255
+ outputs: [{ type: "uint256" }]
256
+ },
257
+ {
258
+ type: "function",
259
+ name: "epochOutgoingSeed",
260
+ stateMutability: "view",
261
+ inputs: [
262
+ { name: "series", type: "bytes32" },
263
+ { name: "epochId", type: "uint256" }
264
+ ],
265
+ outputs: [{ type: "uint256" }]
266
+ },
267
+ {
268
+ type: "function",
269
+ name: "epochIncomingSeed",
270
+ stateMutability: "view",
271
+ inputs: [
272
+ { name: "series", type: "bytes32" },
273
+ { name: "epochId", type: "uint256" }
274
+ ],
275
+ outputs: [{ type: "uint256" }]
276
+ },
277
+ {
278
+ type: "function",
279
+ name: "epochEntryCount",
280
+ stateMutability: "view",
281
+ inputs: [
282
+ { name: "series", type: "bytes32" },
283
+ { name: "epochId", type: "uint256" }
284
+ ],
285
+ outputs: [{ type: "uint256" }]
286
+ },
287
+ {
288
+ type: "function",
289
+ name: "getSeries",
290
+ stateMutability: "view",
291
+ inputs: [{ name: "series", type: "bytes32" }],
292
+ outputs: [
293
+ { name: "created", type: "bool" },
294
+ { name: "genesis", type: "uint256" },
295
+ { name: "epochDuration", type: "uint256" },
296
+ { name: "entry", type: "uint256" },
297
+ { name: "feeBps", type: "uint16" },
298
+ { name: "poolBps", type: "uint16" },
299
+ { name: "seedBps", type: "uint16" }
300
+ ]
301
+ },
302
+ {
303
+ type: "function",
304
+ name: "getEpoch",
305
+ stateMutability: "view",
306
+ inputs: [
307
+ { name: "series", type: "bytes32" },
308
+ { name: "epochId", type: "uint256" }
309
+ ],
310
+ outputs: [
311
+ { name: "pool", type: "uint256" },
312
+ { name: "outgoingSeed", type: "uint256" },
313
+ { name: "incomingSeed", type: "uint256" },
314
+ { name: "entryCount_", type: "uint256" },
315
+ { name: "terminal", type: "uint8" }
316
+ ]
317
+ },
318
+ {
319
+ type: "function",
320
+ name: "entryCount",
321
+ stateMutability: "view",
322
+ inputs: [
323
+ { name: "series", type: "bytes32" },
324
+ { name: "epochId", type: "uint256" },
325
+ { name: "identity", type: "bytes32" }
326
+ ],
327
+ outputs: [{ type: "uint256" }]
328
+ },
329
+ {
330
+ type: "function",
331
+ name: "claimableRefund",
332
+ stateMutability: "view",
333
+ inputs: [
334
+ { name: "series", type: "bytes32" },
335
+ { name: "epochId", type: "uint256" },
336
+ { name: "payer", type: "address" }
337
+ ],
338
+ outputs: [{ type: "uint256" }]
339
+ },
340
+ {
341
+ type: "function",
342
+ name: "withdrawable",
343
+ stateMutability: "view",
344
+ inputs: [{ name: "account", type: "address" }],
345
+ outputs: [{ type: "uint256" }]
346
+ }
347
+ ];
348
+ var epochPrizePoolEnterAbi = [
349
+ {
350
+ type: "function",
351
+ name: "enter",
352
+ stateMutability: "nonpayable",
353
+ inputs: [
354
+ { name: "series", type: "bytes32" },
355
+ { name: "identity", type: "bytes32" }
356
+ ],
357
+ outputs: []
358
+ }
359
+ ];
360
+ var epochPrizePoolRefundAbi = [
361
+ {
362
+ type: "function",
363
+ name: "claimRefund",
364
+ stateMutability: "nonpayable",
365
+ inputs: [
366
+ { name: "series", type: "bytes32" },
367
+ { name: "epochId", type: "uint256" },
368
+ { name: "payer", type: "address" }
369
+ ],
370
+ outputs: [{ name: "amount", type: "uint256" }]
371
+ },
372
+ {
373
+ type: "function",
374
+ name: "withdraw",
375
+ stateMutability: "nonpayable",
376
+ inputs: [],
377
+ outputs: []
378
+ }
379
+ ];
380
+ var epochPrizePoolExecuteSettlementAbi = [
381
+ {
382
+ type: "function",
383
+ name: "executeSignedSettlement",
384
+ stateMutability: "nonpayable",
385
+ inputs: [
386
+ { name: "series", type: "bytes32" },
387
+ { name: "epochId", type: "uint256" },
388
+ { name: "winners", type: "address[]" },
389
+ { name: "amounts", type: "uint256[]" },
390
+ { name: "signature", type: "bytes" }
391
+ ],
392
+ outputs: []
393
+ }
394
+ ];
395
+
222
396
  // src/chain/calls.ts
223
397
  var toBytes32 = (s) => keccak256(toBytes(s));
224
398
  function buildIapCalls(args) {
@@ -251,5 +425,21 @@ function buildWithdrawCall(prizePool) {
251
425
  });
252
426
  return { to: prizePool, data };
253
427
  }
428
+ function buildEpochExecuteSettlementCall(args) {
429
+ return {
430
+ to: args.epochPrizePool,
431
+ data: encodeFunctionData({
432
+ abi: epochPrizePoolExecuteSettlementAbi,
433
+ functionName: "executeSignedSettlement",
434
+ args: [
435
+ seriesToBytes32(args.series),
436
+ args.epochId,
437
+ args.winners.map((w) => getAddress(w.toLowerCase())),
438
+ args.amounts,
439
+ args.signature
440
+ ]
441
+ })
442
+ };
443
+ }
254
444
 
255
- export { AlreadyEnteredError, ApiError, AuthError, ConfigError, InsufficientGasError, InvalidAmountError, MissingFieldError, NothingToWithdrawError, PaymentFailedError, PlaymosError, WalletConnectionError, WalletTimeoutError, assertEnoughGas, buildEntryCalls, buildIapCalls, buildWithdrawCall, prizePoolAbi, sendCalls, toBytes32, waitForCalls };
445
+ export { AlreadyEnteredError, ApiError, AuthError, ConfigError, InsufficientGasError, InvalidAmountError, MissingFieldError, NothingToWithdrawError, PaymentFailedError, PlaymosError, WalletConnectionError, WalletTimeoutError, assertEnoughGas, buildEntryCalls, buildEpochExecuteSettlementCall, buildIapCalls, buildWithdrawCall, encodeApprove, epochPrizePoolEnterAbi, epochPrizePoolRefundAbi, epochPrizePoolViewAbi, identityToBytes32, prizePoolAbi, sendCalls, seriesToBytes32, toBytes32, waitForCalls };
@@ -46,6 +46,8 @@ interface ContractConfig {
46
46
  usdc?: `0x${string}`;
47
47
  playmosPay?: `0x${string}`;
48
48
  prizePool?: `0x${string}`;
49
+ /** EpochPrizePool (rolling-epoch reads — sdk#629). Live PrizePool stays on prizePool. */
50
+ epochPrizePool?: `0x${string}`;
49
51
  }
50
52
  /**
51
53
  * @deprecated Unused — agent routes are enabled server-side (SERVICE_MASTER_SECRET +
@@ -404,7 +406,7 @@ interface Payment {
404
406
  /** `pay_…` (IAP) or `entry_…` (prize-pool) — ULID, server-issued, unique. */
405
407
  id: string;
406
408
  status: PaymentStatus;
407
- /** "iap" (1% external) or "entry" (60/30/10 prize-pool). */
409
+ /** "iap" (1% external) or "entry" (prize-pool; `split` is a first-party 60/30/10 projection). */
408
410
  kind: "iap" | "entry";
409
411
  /**
410
412
  * Requested amount (USD string). For prize-pool **server-settle**, this may
@@ -423,12 +425,13 @@ interface Payment {
423
425
  chainAmountMicro?: string;
424
426
  /**
425
427
  * First-party **60/30/10 projection** (pool/seed/rake USD strings) for prize-pool
426
- * entries — bookkeeping preview, **not** a chain-derived settlement observation
427
- * (sdk#514). Numbers come from SDK constants (`POOL_BPS`/`SEED_BPS`/`RAKE_BPS`),
428
- * not from reading the deployed pool’s constructor bps. On-chain, entry only
429
- * takes the fee off the top; pool/seed split at **lock**; payable pot also
430
- * includes inherited seedBank so `split.pool` is **not** “what this round pays.”
431
- * Reconcile money with {@link Payment.chainAmount} / pool `getRound`.
428
+ * entries — bookkeeping preview, **not** a studio 60/30/9+1% split and **not** a
429
+ * chain-derived settlement observation (sdk#514). Numbers come from SDK constants
430
+ * (`POOL_BPS`/`SEED_BPS`/`RAKE_BPS`), not from reading the deployed pool’s
431
+ * constructor bps. On-chain, entry only takes the fee off the top; pool/seed
432
+ * split at **lock**; payable pot also includes inherited seedBank so
433
+ * `split.pool` is **not** “what this round pays.” Reconcile money with
434
+ * {@link Payment.chainAmount} / pool `getRound`.
432
435
  * Field name kept for compatibility (no rename in V1).
433
436
  */
434
437
  split?: {
@@ -637,6 +640,22 @@ interface CancelRoundResult {
637
640
  status: "cancelling" | "cancelled";
638
641
  round?: RoundState;
639
642
  }
643
+ /** L34 / sdk#610 — a win is funded only after the push tx, else claimable. */
644
+ type PayoutNoticeStatus = "funded" | "claimable";
645
+ interface PayoutNotice {
646
+ roundId: string;
647
+ wallet: `0x${string}`;
648
+ amountMicro: string;
649
+ status: PayoutNoticeStatus;
650
+ /** Present only when status === "funded". */
651
+ txHash?: `0x${string}`;
652
+ reason?: string;
653
+ }
654
+ interface PayoutNoticesResult {
655
+ roundId?: string;
656
+ status?: string;
657
+ notices: PayoutNotice[];
658
+ }
640
659
  /** What `rounds.prize({ … })` returns — claimable pull-payment balance (issue #41). */
641
660
  interface PrizeBalance {
642
661
  roundId: string;
@@ -707,6 +726,43 @@ interface SettleRoundResult {
707
726
  status: "settled" | "settling";
708
727
  }
709
728
 
729
+ /**
730
+ * EIP-5792 batch primitives — ported from the proven game-hub `payEntryOnchain`
731
+ * path (`OnchainEntry.ts`). One `wallet_sendCalls` sends `approve` + the settling
732
+ * call as ONE atomic confirmation; the paymaster sponsors gas when configured.
733
+ * The player sees a single Apple-Pay-style sheet.
734
+ */
735
+
736
+ interface Call {
737
+ to: `0x${string}`;
738
+ data: `0x${string}`;
739
+ }
740
+ type OnchainStatus = "PENDING" | "CONFIRMED" | "FAILED";
741
+
742
+ /**
743
+ * Calldata builders. IAP / PrizePool entry stay on `toBytes32` (keccak of
744
+ * UTF-8 via toBytes) because live paid entries were written with it.
745
+ * Epoch execute uses `seriesToBytes32` — hex-shaped series must not drift.
746
+ */
747
+
748
+ /** The server derives these identically (keccak256 of UTF-8 bytes) so the
749
+ * off-chain record and the on-chain call line up. */
750
+ declare const toBytes32: (s: string) => `0x${string}`;
751
+ interface EpochExecuteSettlementCallArgs {
752
+ epochPrizePool: `0x${string}`;
753
+ series: string;
754
+ epochId: bigint;
755
+ winners: `0x${string}`[];
756
+ amounts: bigint[];
757
+ signature: `0x${string}`;
758
+ }
759
+ /**
760
+ * EpochPrizePool.executeSignedSettlement — permissionless relay of an
761
+ * operator-signed podium (sdk#664 E1b). Series hashed with seriesToBytes32
762
+ * (not this file's toBytes32) so hex-shaped series cannot drift from the chain.
763
+ */
764
+ declare function buildEpochExecuteSettlementCall(args: EpochExecuteSettlementCallArgs): Call;
765
+
710
766
  /**
711
767
  * Typed, actionable errors — the Stripe bar (spec §11).
712
768
  *
@@ -778,4 +834,4 @@ declare class NothingToWithdrawError extends PlaymosError {
778
834
  constructor(detail?: Record<string, unknown>);
779
835
  }
780
836
 
781
- export { type RetryOptions as $, type ActiveSeriesRound as A, type ContractConfig as B, type CancelRoundResult as C, type Eip1193Provider as D, type EscrowHoldInput as E, type GasMode as F, type GasConfig as G, InvalidAmountError as H, InsufficientGasError as I, type ListingStatus as J, type MarketplaceItem as K, type Listing as L, type MarketplaceListInput as M, type Network as N, type MarketplaceSale as O, type PlaymosConfig as P, MissingFieldError as Q, type RoundOpenInput as R, type SettleRoundResult as S, type TransferResult as T, NothingToWithdrawError as U, type VerifyResult as V, type WebhookEvent as W, PaymentFailedError as X, type PaymentStatus as Y, PlaymosError as Z, type PlaymosErrorCode as _, type RoundState as a, type RoundGetVia as a0, type RoundStatus as a1, type WalletConfig as a2, WalletConnectionError as a3, type WalletConnector as a4, WalletTimeoutError as a5, type WebhookEventType as a6, type RoundSettleInput as b, type RoundCancelInput as c, type RoundGetResult as d, type PrizeBalance as e, type WithdrawResult as f, type AgentWallet as g, type AgentFundResult as h, type EscrowHoldResult as i, type EscrowResolveResult as j, type MarketplaceSaleResult as k, type MarketplaceGetResult as l, type PayInput as m, type Payment as n, type EnterRoundInput as o, type TransferReconcile as p, type WaitOptions as q, type TransferInput as r, type TransferConfirmOptions as s, type PayoutRule as t, type ActiveForSeriesResult as u, type AgentEconomyConfig as v, AlreadyEnteredError as w, ApiError as x, AuthError as y, ConfigError as z };
837
+ export { type PaymentStatus as $, type ActiveSeriesRound as A, AuthError as B, type Call as C, ConfigError as D, type EscrowHoldInput as E, type ContractConfig as F, type Eip1193Provider as G, type GasConfig as H, type GasMode as I, InsufficientGasError as J, InvalidAmountError as K, type Listing as L, type MarketplaceListInput as M, type Network as N, type OnchainStatus as O, type PlaymosConfig as P, type ListingStatus as Q, type RoundOpenInput as R, type SettleRoundResult as S, type TransferResult as T, type MarketplaceItem as U, type VerifyResult as V, type WebhookEvent as W, type MarketplaceSale as X, MissingFieldError as Y, NothingToWithdrawError as Z, PaymentFailedError as _, type RoundState as a, type PayoutNotice as a0, type PayoutNoticeStatus as a1, PlaymosError as a2, type PlaymosErrorCode as a3, type RetryOptions as a4, type RoundGetVia as a5, type RoundStatus as a6, type WalletConfig as a7, WalletConnectionError as a8, type WalletConnector as a9, WalletTimeoutError as aa, type WebhookEventType as ab, buildEpochExecuteSettlementCall as ac, toBytes32 as ad, type RoundSettleInput as b, type RoundCancelInput as c, type CancelRoundResult as d, type RoundGetResult as e, type PayoutNoticesResult as f, type PrizeBalance as g, type WithdrawResult as h, type AgentWallet as i, type AgentFundResult as j, type EscrowHoldResult as k, type EscrowResolveResult as l, type MarketplaceSaleResult as m, type MarketplaceGetResult as n, type PayInput as o, type Payment as p, type EnterRoundInput as q, type TransferReconcile as r, type WaitOptions as s, type TransferInput as t, type TransferConfirmOptions as u, type PayoutRule as v, type ActiveForSeriesResult as w, type AgentEconomyConfig as x, AlreadyEnteredError as y, ApiError as z };
@@ -46,6 +46,8 @@ interface ContractConfig {
46
46
  usdc?: `0x${string}`;
47
47
  playmosPay?: `0x${string}`;
48
48
  prizePool?: `0x${string}`;
49
+ /** EpochPrizePool (rolling-epoch reads — sdk#629). Live PrizePool stays on prizePool. */
50
+ epochPrizePool?: `0x${string}`;
49
51
  }
50
52
  /**
51
53
  * @deprecated Unused — agent routes are enabled server-side (SERVICE_MASTER_SECRET +
@@ -404,7 +406,7 @@ interface Payment {
404
406
  /** `pay_…` (IAP) or `entry_…` (prize-pool) — ULID, server-issued, unique. */
405
407
  id: string;
406
408
  status: PaymentStatus;
407
- /** "iap" (1% external) or "entry" (60/30/10 prize-pool). */
409
+ /** "iap" (1% external) or "entry" (prize-pool; `split` is a first-party 60/30/10 projection). */
408
410
  kind: "iap" | "entry";
409
411
  /**
410
412
  * Requested amount (USD string). For prize-pool **server-settle**, this may
@@ -423,12 +425,13 @@ interface Payment {
423
425
  chainAmountMicro?: string;
424
426
  /**
425
427
  * First-party **60/30/10 projection** (pool/seed/rake USD strings) for prize-pool
426
- * entries — bookkeeping preview, **not** a chain-derived settlement observation
427
- * (sdk#514). Numbers come from SDK constants (`POOL_BPS`/`SEED_BPS`/`RAKE_BPS`),
428
- * not from reading the deployed pool’s constructor bps. On-chain, entry only
429
- * takes the fee off the top; pool/seed split at **lock**; payable pot also
430
- * includes inherited seedBank so `split.pool` is **not** “what this round pays.”
431
- * Reconcile money with {@link Payment.chainAmount} / pool `getRound`.
428
+ * entries — bookkeeping preview, **not** a studio 60/30/9+1% split and **not** a
429
+ * chain-derived settlement observation (sdk#514). Numbers come from SDK constants
430
+ * (`POOL_BPS`/`SEED_BPS`/`RAKE_BPS`), not from reading the deployed pool’s
431
+ * constructor bps. On-chain, entry only takes the fee off the top; pool/seed
432
+ * split at **lock**; payable pot also includes inherited seedBank so
433
+ * `split.pool` is **not** “what this round pays.” Reconcile money with
434
+ * {@link Payment.chainAmount} / pool `getRound`.
432
435
  * Field name kept for compatibility (no rename in V1).
433
436
  */
434
437
  split?: {
@@ -637,6 +640,22 @@ interface CancelRoundResult {
637
640
  status: "cancelling" | "cancelled";
638
641
  round?: RoundState;
639
642
  }
643
+ /** L34 / sdk#610 — a win is funded only after the push tx, else claimable. */
644
+ type PayoutNoticeStatus = "funded" | "claimable";
645
+ interface PayoutNotice {
646
+ roundId: string;
647
+ wallet: `0x${string}`;
648
+ amountMicro: string;
649
+ status: PayoutNoticeStatus;
650
+ /** Present only when status === "funded". */
651
+ txHash?: `0x${string}`;
652
+ reason?: string;
653
+ }
654
+ interface PayoutNoticesResult {
655
+ roundId?: string;
656
+ status?: string;
657
+ notices: PayoutNotice[];
658
+ }
640
659
  /** What `rounds.prize({ … })` returns — claimable pull-payment balance (issue #41). */
641
660
  interface PrizeBalance {
642
661
  roundId: string;
@@ -707,6 +726,43 @@ interface SettleRoundResult {
707
726
  status: "settled" | "settling";
708
727
  }
709
728
 
729
+ /**
730
+ * EIP-5792 batch primitives — ported from the proven game-hub `payEntryOnchain`
731
+ * path (`OnchainEntry.ts`). One `wallet_sendCalls` sends `approve` + the settling
732
+ * call as ONE atomic confirmation; the paymaster sponsors gas when configured.
733
+ * The player sees a single Apple-Pay-style sheet.
734
+ */
735
+
736
+ interface Call {
737
+ to: `0x${string}`;
738
+ data: `0x${string}`;
739
+ }
740
+ type OnchainStatus = "PENDING" | "CONFIRMED" | "FAILED";
741
+
742
+ /**
743
+ * Calldata builders. IAP / PrizePool entry stay on `toBytes32` (keccak of
744
+ * UTF-8 via toBytes) because live paid entries were written with it.
745
+ * Epoch execute uses `seriesToBytes32` — hex-shaped series must not drift.
746
+ */
747
+
748
+ /** The server derives these identically (keccak256 of UTF-8 bytes) so the
749
+ * off-chain record and the on-chain call line up. */
750
+ declare const toBytes32: (s: string) => `0x${string}`;
751
+ interface EpochExecuteSettlementCallArgs {
752
+ epochPrizePool: `0x${string}`;
753
+ series: string;
754
+ epochId: bigint;
755
+ winners: `0x${string}`[];
756
+ amounts: bigint[];
757
+ signature: `0x${string}`;
758
+ }
759
+ /**
760
+ * EpochPrizePool.executeSignedSettlement — permissionless relay of an
761
+ * operator-signed podium (sdk#664 E1b). Series hashed with seriesToBytes32
762
+ * (not this file's toBytes32) so hex-shaped series cannot drift from the chain.
763
+ */
764
+ declare function buildEpochExecuteSettlementCall(args: EpochExecuteSettlementCallArgs): Call;
765
+
710
766
  /**
711
767
  * Typed, actionable errors — the Stripe bar (spec §11).
712
768
  *
@@ -778,4 +834,4 @@ declare class NothingToWithdrawError extends PlaymosError {
778
834
  constructor(detail?: Record<string, unknown>);
779
835
  }
780
836
 
781
- export { type RetryOptions as $, type ActiveSeriesRound as A, type ContractConfig as B, type CancelRoundResult as C, type Eip1193Provider as D, type EscrowHoldInput as E, type GasMode as F, type GasConfig as G, InvalidAmountError as H, InsufficientGasError as I, type ListingStatus as J, type MarketplaceItem as K, type Listing as L, type MarketplaceListInput as M, type Network as N, type MarketplaceSale as O, type PlaymosConfig as P, MissingFieldError as Q, type RoundOpenInput as R, type SettleRoundResult as S, type TransferResult as T, NothingToWithdrawError as U, type VerifyResult as V, type WebhookEvent as W, PaymentFailedError as X, type PaymentStatus as Y, PlaymosError as Z, type PlaymosErrorCode as _, type RoundState as a, type RoundGetVia as a0, type RoundStatus as a1, type WalletConfig as a2, WalletConnectionError as a3, type WalletConnector as a4, WalletTimeoutError as a5, type WebhookEventType as a6, type RoundSettleInput as b, type RoundCancelInput as c, type RoundGetResult as d, type PrizeBalance as e, type WithdrawResult as f, type AgentWallet as g, type AgentFundResult as h, type EscrowHoldResult as i, type EscrowResolveResult as j, type MarketplaceSaleResult as k, type MarketplaceGetResult as l, type PayInput as m, type Payment as n, type EnterRoundInput as o, type TransferReconcile as p, type WaitOptions as q, type TransferInput as r, type TransferConfirmOptions as s, type PayoutRule as t, type ActiveForSeriesResult as u, type AgentEconomyConfig as v, AlreadyEnteredError as w, ApiError as x, AuthError as y, ConfigError as z };
837
+ export { type PaymentStatus as $, type ActiveSeriesRound as A, AuthError as B, type Call as C, ConfigError as D, type EscrowHoldInput as E, type ContractConfig as F, type Eip1193Provider as G, type GasConfig as H, type GasMode as I, InsufficientGasError as J, InvalidAmountError as K, type Listing as L, type MarketplaceListInput as M, type Network as N, type OnchainStatus as O, type PlaymosConfig as P, type ListingStatus as Q, type RoundOpenInput as R, type SettleRoundResult as S, type TransferResult as T, type MarketplaceItem as U, type VerifyResult as V, type WebhookEvent as W, type MarketplaceSale as X, MissingFieldError as Y, NothingToWithdrawError as Z, PaymentFailedError as _, type RoundState as a, type PayoutNotice as a0, type PayoutNoticeStatus as a1, PlaymosError as a2, type PlaymosErrorCode as a3, type RetryOptions as a4, type RoundGetVia as a5, type RoundStatus as a6, type WalletConfig as a7, WalletConnectionError as a8, type WalletConnector as a9, WalletTimeoutError as aa, type WebhookEventType as ab, buildEpochExecuteSettlementCall as ac, toBytes32 as ad, type RoundSettleInput as b, type RoundCancelInput as c, type CancelRoundResult as d, type RoundGetResult as e, type PayoutNoticesResult as f, type PrizeBalance as g, type WithdrawResult as h, type AgentWallet as i, type AgentFundResult as j, type EscrowHoldResult as k, type EscrowResolveResult as l, type MarketplaceSaleResult as m, type MarketplaceGetResult as n, type PayInput as o, type Payment as p, type EnterRoundInput as q, type TransferReconcile as r, type WaitOptions as s, type TransferInput as t, type TransferConfirmOptions as u, type PayoutRule as v, type ActiveForSeriesResult as w, type AgentEconomyConfig as x, AlreadyEnteredError as y, ApiError as z };