@playmos/sdk 0.3.14 → 0.3.16

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,19 @@ All notable changes to `@playmos/sdk`. This project adheres to [Semantic Version
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## [0.3.16] — 2026-09-11
8
+
9
+ ### Added/Fixed
10
+ - EOA / Chrome Coinbase extension: `sendCalls` falls back to sequential `eth_sendTransaction` when `wallet_sendCalls` is missing or fails (not a user cancel). Skip USDC approve when allowance already covers. (#746 / #745)
11
+
12
+ ## [0.3.15] — 2026-09-11
13
+
14
+ ### Added
15
+ - **`epochs.prepareSeries`** / `POST /v1/epochs/series/prepare` — after register, one call returns an unsigned `createSeries` tx (`broadcast: false`, default `feeBps` 100). The studio EOA signs. Playmos never broadcasts. (#742 / #739)
16
+
17
+ ### Fixed (service)
18
+ - Studio-operated pool `POST /v1/epochs/:epochId/settle` returns 4xx naming `settleEpoch` / `executeSignedSettlement`, not a product 502/504. (#741 / #736)
19
+
7
20
  ## [0.3.14] — 2026-09-11
8
21
 
9
22
  ### Added
package/README.md CHANGED
@@ -16,7 +16,7 @@ Requires **Node 18 / 20 / 22 LTS** for local development and CI toolchains. Full
16
16
 
17
17
  ## Browser vs server entry
18
18
 
19
- - **Games (browser / Vite / Phaser):** `import { Playmos } from "@playmos/sdk"` — this entry is browser-safe and does **not** import Node `crypto` (issue #9).
19
+ - **Games (browser / Vite / Phaser):** `import { Playmos } from "@playmos/sdk"` — this entry is browser-safe and does **not** import Node `crypto` (issue #9). The package depends on **viem**; the named import tree-shakes, but a default Vite single chunk can still exceed 500 kB gzip-warn.
20
20
  - **Your backend (webhook receivers):** `import { verifyWebhook } from "@playmos/sdk/server"` — HMAC verification uses Node crypto and must stay off the client bundle.
21
21
 
22
22
  The sandbox API also sends CORS headers so browser `pay()` / `enterRound()` work without a same-origin proxy (issue #10).
@@ -51,6 +51,9 @@ while (result.status !== "confirmed" && tries !== 0) {
51
51
  result = await playmos.verify(payment.id);
52
52
  tries -= 1;
53
53
  }
54
+ if (result.status !== "confirmed") {
55
+ throw new Error(`not confirmed yet: ${result.status}`);
56
+ }
54
57
 
55
58
  console.log({ id: payment.id, status: result.status, tx: payment.txHash });
56
59
  // You won: pay_… + confirmed on Base Sepolia
@@ -78,24 +81,29 @@ if (result.status === "confirmed") {
78
81
  ### Optional later — skill-game entry (`enterRound()`)
79
82
 
80
83
  ```ts
84
+ const idempotencyKey = "entry-player_abc"; // persist BEFORE enterRound
81
85
  const entry = await playmos.enterRound({
82
86
  gameId: "game_sandbox_skill",
83
87
  roundId: "5m-5944009",
84
88
  amount: "1.00", // grows this round's pool
85
89
  playerId: "player_abc",
90
+ idempotencyKey,
86
91
  });
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).
92
+ // entry.status === "confirmed". Public sandbox skill is a shared Playmos pool —
93
+ // not your contest and not your published take. Persist entry.identity
94
+ // (sandbox#entry_…) when there is no wallet. Same $1.00/request cap as pay().
95
+ // Your 1% is IAP pay() and your own registered pool (next section).
89
96
  ```
90
97
 
91
98
  ### Your own contest pool — `epochs.preparePool` (you sign)
92
99
 
93
- `@playmos/sdk` **0.3.14** 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.
100
+ `@playmos/sdk` **0.3.16** ships `epochs.preparePool` and `epochs.prepareSeries` with `unsignedTx` on the typed response. It calls the live API. Playmos sets `broadcast: false` and does **not** send the transaction.
94
101
 
95
102
  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
103
  2. Call `epochs.preparePool({ studioWallet })` or `POST /v1/epochs/pools/prepare`. Use `feeSink` from that response (`0xD84c190085aa59c48a9B478Ea333D50B8DF4aD42`).
97
104
  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.
105
+ 4. `epochs.registerPool` with `walletProof`.
106
+ 5. `epochs.prepareSeries` — one returned `unsignedTx`, you sign in the same EOA. Then `GET /v1/epochs/series` until `created=true`, then enter **your** game — not the shared sandbox game.
99
107
 
100
108
  Full steps: https://playmos-docs-public.vercel.app/docs#studio-pool-prepare
101
109
 
@@ -1,4 +1,4 @@
1
- import { keccak256, toHex, numberToHex, encodeFunctionData, toBytes, getAddress } from 'viem';
1
+ import { keccak256, toHex, numberToHex, encodeFunctionData, toBytes, getAddress, decodeFunctionData } from 'viem';
2
2
 
3
3
  // src/errors.ts
4
4
  var PlaymosError = class extends Error {
@@ -140,6 +140,35 @@ var prizePoolAbi = [
140
140
  outputs: [{ name: "amount", type: "uint256" }]
141
141
  }
142
142
  ];
143
+ var erc20AllowanceAbi = [
144
+ {
145
+ type: "function",
146
+ name: "allowance",
147
+ stateMutability: "view",
148
+ inputs: [
149
+ { name: "owner", type: "address" },
150
+ { name: "spender", type: "address" }
151
+ ],
152
+ outputs: [{ type: "uint256" }]
153
+ }
154
+ ];
155
+ var SEQUENTIAL_TX_ID_PREFIX = "eth:";
156
+ var USER_CANCEL_RE = /reject|denied|cancel|closed/i;
157
+ function sequentialTxId(txHash) {
158
+ return `${SEQUENTIAL_TX_ID_PREFIX}${txHash}`;
159
+ }
160
+ function sequentialTxHashFromId(id) {
161
+ if (!id.startsWith(SEQUENTIAL_TX_ID_PREFIX)) return void 0;
162
+ const hash = id.slice(SEQUENTIAL_TX_ID_PREFIX.length);
163
+ if (/^0x[0-9a-fA-F]{64}$/.test(hash)) return hash;
164
+ return void 0;
165
+ }
166
+ function errorMessage(e) {
167
+ return e?.message ?? String(e);
168
+ }
169
+ function isUserCancel(msg) {
170
+ return USER_CANCEL_RE.test(msg);
171
+ }
143
172
  async function sendCalls(provider, from, chainId, calls, paymasterUrl) {
144
173
  const params = {
145
174
  version: "2.0.0",
@@ -151,23 +180,85 @@ async function sendCalls(provider, from, chainId, calls, paymasterUrl) {
151
180
  if (paymasterUrl) {
152
181
  params.capabilities = { paymasterService: { url: paymasterUrl } };
153
182
  }
154
- let result;
155
183
  try {
156
- result = await provider.request({ method: "wallet_sendCalls", params: [params] });
184
+ const result = await provider.request({ method: "wallet_sendCalls", params: [params] });
185
+ const id = typeof result === "string" ? result : result?.id ?? "";
186
+ if (!id) throw new PaymentFailedError("Wallet returned no calls id.");
187
+ return { id };
157
188
  } catch (e) {
189
+ if (e instanceof PaymentFailedError) throw e;
158
190
  if (e instanceof WalletTimeoutError) throw e;
159
- const msg = e?.message ?? String(e);
160
- if (/reject|denied|cancel|closed/i.test(msg)) {
191
+ const msg = errorMessage(e);
192
+ if (isUserCancel(msg)) {
161
193
  throw new WalletConnectionError("The player cancelled or closed the payment sheet.", { cause: msg });
162
194
  }
163
- throw new PaymentFailedError("wallet_sendCalls failed.", { cause: msg });
195
+ return sendCallsSequentially(provider, from, calls);
164
196
  }
165
- const id = typeof result === "string" ? result : result?.id ?? "";
166
- if (!id) throw new PaymentFailedError("Wallet returned no calls id.");
167
- return { id };
197
+ }
198
+ async function skipCoveredApprove(provider, from, calls) {
199
+ const first = calls[0];
200
+ if (!first) return calls;
201
+ let spender;
202
+ let amount;
203
+ try {
204
+ const decoded = decodeFunctionData({ abi: erc20Abi, data: first.data });
205
+ if (decoded.functionName !== "approve") return calls;
206
+ spender = decoded.args[0];
207
+ amount = decoded.args[1];
208
+ } catch {
209
+ return calls;
210
+ }
211
+ try {
212
+ const data = encodeFunctionData({
213
+ abi: erc20AllowanceAbi,
214
+ functionName: "allowance",
215
+ args: [from, spender]
216
+ });
217
+ const raw = await provider.request({
218
+ method: "eth_call",
219
+ params: [{ to: first.to, data }, "latest"]
220
+ });
221
+ const allowance = BigInt(typeof raw === "string" && raw !== "0x" ? raw : "0");
222
+ if (allowance >= amount) return calls.slice(1);
223
+ } catch {
224
+ }
225
+ return calls;
226
+ }
227
+ async function sendCallsSequentially(provider, from, calls) {
228
+ const toSend = await skipCoveredApprove(provider, from, calls);
229
+ if (toSend.length === 0) {
230
+ throw new PaymentFailedError("No wallet calls to send.");
231
+ }
232
+ let lastHash;
233
+ for (const call of toSend) {
234
+ let hash;
235
+ try {
236
+ hash = await provider.request({
237
+ method: "eth_sendTransaction",
238
+ params: [{ from, to: call.to, data: call.data }]
239
+ });
240
+ } catch (e) {
241
+ if (e instanceof WalletTimeoutError) throw e;
242
+ const msg = errorMessage(e);
243
+ if (isUserCancel(msg)) {
244
+ throw new WalletConnectionError("The player cancelled or closed the payment sheet.", { cause: msg });
245
+ }
246
+ throw new PaymentFailedError("eth_sendTransaction failed.", { cause: msg });
247
+ }
248
+ if (typeof hash !== "string" || !/^0x[0-9a-fA-F]{64}$/.test(hash)) {
249
+ throw new PaymentFailedError("Wallet returned no transaction hash.");
250
+ }
251
+ lastHash = hash;
252
+ }
253
+ if (!lastHash) throw new PaymentFailedError("Wallet returned no transaction hash.");
254
+ return { id: sequentialTxId(lastHash) };
168
255
  }
169
256
  async function waitForCalls(provider, id, timeoutMs = 6e4) {
170
257
  if (!id) return { status: "FAILED" };
258
+ const sequentialHash = sequentialTxHashFromId(id);
259
+ if (sequentialHash) {
260
+ return waitForTransactionReceipt(provider, sequentialHash, timeoutMs);
261
+ }
171
262
  const deadline = Date.now() + timeoutMs;
172
263
  while (Date.now() < deadline) {
173
264
  try {
@@ -190,6 +281,30 @@ async function waitForCalls(provider, id, timeoutMs = 6e4) {
190
281
  }
191
282
  return { status: "PENDING" };
192
283
  }
284
+ async function waitForTransactionReceipt(provider, txHash, timeoutMs) {
285
+ const deadline = Date.now() + timeoutMs;
286
+ while (Date.now() < deadline) {
287
+ try {
288
+ const res = await provider.request({
289
+ method: "eth_getTransactionReceipt",
290
+ params: [txHash]
291
+ });
292
+ if (res && res.status !== void 0 && res.status !== null) {
293
+ const code = typeof res.status === "number" ? res.status : Number(res.status);
294
+ if (code === 1) return { status: "CONFIRMED", txHash };
295
+ if (code === 0) return { status: "FAILED", txHash };
296
+ }
297
+ } catch (e) {
298
+ if (e instanceof WalletTimeoutError) {
299
+ await new Promise((r) => setTimeout(r, 900));
300
+ continue;
301
+ }
302
+ throw e;
303
+ }
304
+ await new Promise((r) => setTimeout(r, 900));
305
+ }
306
+ return { status: "PENDING", txHash };
307
+ }
193
308
  function encodeApprove(spender, amountUnits) {
194
309
  return encodeFunctionData({ abi: erc20Abi, functionName: "approve", args: [spender, amountUnits] });
195
310
  }
@@ -345,6 +460,23 @@ var epochPrizePoolViewAbi = [
345
460
  outputs: [{ type: "uint256" }]
346
461
  }
347
462
  ];
463
+ var epochPrizePoolCreateSeriesAbi = [
464
+ {
465
+ type: "function",
466
+ name: "createSeries",
467
+ stateMutability: "nonpayable",
468
+ inputs: [
469
+ { name: "series", type: "bytes32" },
470
+ { name: "genesis", type: "uint256" },
471
+ { name: "epochDuration", type: "uint256" },
472
+ { name: "entry", type: "uint256" },
473
+ { name: "feeBps", type: "uint16" },
474
+ { name: "poolBps", type: "uint16" },
475
+ { name: "seedBps", type: "uint16" }
476
+ ],
477
+ outputs: []
478
+ }
479
+ ];
348
480
  var epochPrizePoolEnterAbi = [
349
481
  {
350
482
  type: "function",
@@ -442,4 +574,4 @@ function buildEpochExecuteSettlementCall(args) {
442
574
  };
443
575
  }
444
576
 
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 };
577
+ export { AlreadyEnteredError, ApiError, AuthError, ConfigError, InsufficientGasError, InvalidAmountError, MissingFieldError, NothingToWithdrawError, PaymentFailedError, PlaymosError, WalletConnectionError, WalletTimeoutError, assertEnoughGas, buildEntryCalls, buildEpochExecuteSettlementCall, buildIapCalls, buildWithdrawCall, encodeApprove, epochPrizePoolCreateSeriesAbi, epochPrizePoolEnterAbi, epochPrizePoolRefundAbi, epochPrizePoolViewAbi, identityToBytes32, prizePoolAbi, sendCalls, seriesToBytes32, toBytes32, waitForCalls };
@@ -735,9 +735,12 @@ interface SettleRoundResult {
735
735
 
736
736
  /**
737
737
  * EIP-5792 batch primitives — ported from the proven game-hub `payEntryOnchain`
738
- * path (`OnchainEntry.ts`). One `wallet_sendCalls` sends `approve` + the settling
739
- * call as ONE atomic confirmation; the paymaster sponsors gas when configured.
740
- * The player sees a single Apple-Pay-style sheet.
738
+ * path (`OnchainEntry.ts`). `wallet_sendCalls` still sends `approve` + the
739
+ * settling call as one atomic confirmation when the wallet can batch (paymaster
740
+ * sponsors gas when configured). If `wallet_sendCalls` is missing or fails on an
741
+ * EOA — not a user cancel — the same Call[] is sent as sequential
742
+ * `eth_sendTransaction`s. That fallback is not atomic and never attaches a
743
+ * paymaster. Covered USDC allowance skips the approve tx (one confirm).
741
744
  */
742
745
 
743
746
  interface Call {
@@ -735,9 +735,12 @@ interface SettleRoundResult {
735
735
 
736
736
  /**
737
737
  * EIP-5792 batch primitives — ported from the proven game-hub `payEntryOnchain`
738
- * path (`OnchainEntry.ts`). One `wallet_sendCalls` sends `approve` + the settling
739
- * call as ONE atomic confirmation; the paymaster sponsors gas when configured.
740
- * The player sees a single Apple-Pay-style sheet.
738
+ * path (`OnchainEntry.ts`). `wallet_sendCalls` still sends `approve` + the
739
+ * settling call as one atomic confirmation when the wallet can batch (paymaster
740
+ * sponsors gas when configured). If `wallet_sendCalls` is missing or fails on an
741
+ * EOA — not a user cancel — the same Call[] is sent as sequential
742
+ * `eth_sendTransaction`s. That fallback is not atomic and never attaches a
743
+ * paymaster. Covered USDC allowance skips the approve tx (one confirm).
741
744
  */
742
745
 
743
746
  interface Call {
package/dist/index.cjs CHANGED
@@ -718,6 +718,37 @@ var prizePoolAbi = [
718
718
  outputs: [{ name: "amount", type: "uint256" }]
719
719
  }
720
720
  ];
721
+
722
+ // src/chain/batch.ts
723
+ var erc20AllowanceAbi = [
724
+ {
725
+ type: "function",
726
+ name: "allowance",
727
+ stateMutability: "view",
728
+ inputs: [
729
+ { name: "owner", type: "address" },
730
+ { name: "spender", type: "address" }
731
+ ],
732
+ outputs: [{ type: "uint256" }]
733
+ }
734
+ ];
735
+ var SEQUENTIAL_TX_ID_PREFIX = "eth:";
736
+ var USER_CANCEL_RE = /reject|denied|cancel|closed/i;
737
+ function sequentialTxId(txHash) {
738
+ return `${SEQUENTIAL_TX_ID_PREFIX}${txHash}`;
739
+ }
740
+ function sequentialTxHashFromId(id) {
741
+ if (!id.startsWith(SEQUENTIAL_TX_ID_PREFIX)) return void 0;
742
+ const hash = id.slice(SEQUENTIAL_TX_ID_PREFIX.length);
743
+ if (/^0x[0-9a-fA-F]{64}$/.test(hash)) return hash;
744
+ return void 0;
745
+ }
746
+ function errorMessage(e) {
747
+ return e?.message ?? String(e);
748
+ }
749
+ function isUserCancel(msg) {
750
+ return USER_CANCEL_RE.test(msg);
751
+ }
721
752
  async function sendCalls(provider, from, chainId, calls, paymasterUrl) {
722
753
  const params = {
723
754
  version: "2.0.0",
@@ -729,23 +760,85 @@ async function sendCalls(provider, from, chainId, calls, paymasterUrl) {
729
760
  if (paymasterUrl) {
730
761
  params.capabilities = { paymasterService: { url: paymasterUrl } };
731
762
  }
732
- let result;
733
763
  try {
734
- result = await provider.request({ method: "wallet_sendCalls", params: [params] });
764
+ const result = await provider.request({ method: "wallet_sendCalls", params: [params] });
765
+ const id = typeof result === "string" ? result : result?.id ?? "";
766
+ if (!id) throw new PaymentFailedError("Wallet returned no calls id.");
767
+ return { id };
735
768
  } catch (e) {
769
+ if (e instanceof PaymentFailedError) throw e;
736
770
  if (e instanceof WalletTimeoutError) throw e;
737
- const msg = e?.message ?? String(e);
738
- if (/reject|denied|cancel|closed/i.test(msg)) {
771
+ const msg = errorMessage(e);
772
+ if (isUserCancel(msg)) {
739
773
  throw new WalletConnectionError("The player cancelled or closed the payment sheet.", { cause: msg });
740
774
  }
741
- throw new PaymentFailedError("wallet_sendCalls failed.", { cause: msg });
775
+ return sendCallsSequentially(provider, from, calls);
776
+ }
777
+ }
778
+ async function skipCoveredApprove(provider, from, calls) {
779
+ const first = calls[0];
780
+ if (!first) return calls;
781
+ let spender;
782
+ let amount;
783
+ try {
784
+ const decoded = viem.decodeFunctionData({ abi: erc20Abi, data: first.data });
785
+ if (decoded.functionName !== "approve") return calls;
786
+ spender = decoded.args[0];
787
+ amount = decoded.args[1];
788
+ } catch {
789
+ return calls;
790
+ }
791
+ try {
792
+ const data = viem.encodeFunctionData({
793
+ abi: erc20AllowanceAbi,
794
+ functionName: "allowance",
795
+ args: [from, spender]
796
+ });
797
+ const raw = await provider.request({
798
+ method: "eth_call",
799
+ params: [{ to: first.to, data }, "latest"]
800
+ });
801
+ const allowance = BigInt(typeof raw === "string" && raw !== "0x" ? raw : "0");
802
+ if (allowance >= amount) return calls.slice(1);
803
+ } catch {
804
+ }
805
+ return calls;
806
+ }
807
+ async function sendCallsSequentially(provider, from, calls) {
808
+ const toSend = await skipCoveredApprove(provider, from, calls);
809
+ if (toSend.length === 0) {
810
+ throw new PaymentFailedError("No wallet calls to send.");
811
+ }
812
+ let lastHash;
813
+ for (const call of toSend) {
814
+ let hash;
815
+ try {
816
+ hash = await provider.request({
817
+ method: "eth_sendTransaction",
818
+ params: [{ from, to: call.to, data: call.data }]
819
+ });
820
+ } catch (e) {
821
+ if (e instanceof WalletTimeoutError) throw e;
822
+ const msg = errorMessage(e);
823
+ if (isUserCancel(msg)) {
824
+ throw new WalletConnectionError("The player cancelled or closed the payment sheet.", { cause: msg });
825
+ }
826
+ throw new PaymentFailedError("eth_sendTransaction failed.", { cause: msg });
827
+ }
828
+ if (typeof hash !== "string" || !/^0x[0-9a-fA-F]{64}$/.test(hash)) {
829
+ throw new PaymentFailedError("Wallet returned no transaction hash.");
830
+ }
831
+ lastHash = hash;
742
832
  }
743
- const id = typeof result === "string" ? result : result?.id ?? "";
744
- if (!id) throw new PaymentFailedError("Wallet returned no calls id.");
745
- return { id };
833
+ if (!lastHash) throw new PaymentFailedError("Wallet returned no transaction hash.");
834
+ return { id: sequentialTxId(lastHash) };
746
835
  }
747
836
  async function waitForCalls(provider, id, timeoutMs = 6e4) {
748
837
  if (!id) return { status: "FAILED" };
838
+ const sequentialHash = sequentialTxHashFromId(id);
839
+ if (sequentialHash) {
840
+ return waitForTransactionReceipt(provider, sequentialHash, timeoutMs);
841
+ }
749
842
  const deadline = Date.now() + timeoutMs;
750
843
  while (Date.now() < deadline) {
751
844
  try {
@@ -768,6 +861,30 @@ async function waitForCalls(provider, id, timeoutMs = 6e4) {
768
861
  }
769
862
  return { status: "PENDING" };
770
863
  }
864
+ async function waitForTransactionReceipt(provider, txHash, timeoutMs) {
865
+ const deadline = Date.now() + timeoutMs;
866
+ while (Date.now() < deadline) {
867
+ try {
868
+ const res = await provider.request({
869
+ method: "eth_getTransactionReceipt",
870
+ params: [txHash]
871
+ });
872
+ if (res && res.status !== void 0 && res.status !== null) {
873
+ const code = typeof res.status === "number" ? res.status : Number(res.status);
874
+ if (code === 1) return { status: "CONFIRMED", txHash };
875
+ if (code === 0) return { status: "FAILED", txHash };
876
+ }
877
+ } catch (e) {
878
+ if (e instanceof WalletTimeoutError) {
879
+ await new Promise((r) => setTimeout(r, 900));
880
+ continue;
881
+ }
882
+ throw e;
883
+ }
884
+ await new Promise((r) => setTimeout(r, 900));
885
+ }
886
+ return { status: "PENDING", txHash };
887
+ }
771
888
  function encodeApprove(spender, amountUnits) {
772
889
  return viem.encodeFunctionData({ abi: erc20Abi, functionName: "approve", args: [spender, amountUnits] });
773
890
  }
@@ -929,6 +1046,23 @@ var epochPrizePoolViewAbi = [
929
1046
  outputs: [{ type: "uint256" }]
930
1047
  }
931
1048
  ];
1049
+ var epochPrizePoolCreateSeriesAbi = [
1050
+ {
1051
+ type: "function",
1052
+ name: "createSeries",
1053
+ stateMutability: "nonpayable",
1054
+ inputs: [
1055
+ { name: "series", type: "bytes32" },
1056
+ { name: "genesis", type: "uint256" },
1057
+ { name: "epochDuration", type: "uint256" },
1058
+ { name: "entry", type: "uint256" },
1059
+ { name: "feeBps", type: "uint16" },
1060
+ { name: "poolBps", type: "uint16" },
1061
+ { name: "seedBps", type: "uint16" }
1062
+ ],
1063
+ outputs: []
1064
+ }
1065
+ ];
932
1066
  var epochPrizePoolEnterAbi = [
933
1067
  {
934
1068
  type: "function",
@@ -1136,6 +1270,9 @@ function encodeEpochPoolConstructorArgs(args) {
1136
1270
  args.refundTimeout
1137
1271
  ]);
1138
1272
  }
1273
+ var LOCKED_SERIES_FEE_BPS = 100;
1274
+ var DEFAULT_SERIES_POOL_BPS = 7900;
1275
+ var DEFAULT_SERIES_SEED_BPS = 2e3;
1139
1276
  function derivedEpochId(genesis, epochDuration, at) {
1140
1277
  if (epochDuration === 0n) {
1141
1278
  throw new ConfigError("epochDuration must be > 0");
@@ -1304,6 +1441,66 @@ function walletStatus(status) {
1304
1441
  function sameAddr(a, b) {
1305
1442
  return a.toLowerCase() === b.toLowerCase();
1306
1443
  }
1444
+ function parseSeriesBps(raw, field) {
1445
+ if (raw === void 0) return void 0;
1446
+ if (!Number.isInteger(raw) || raw < 0) {
1447
+ throw new ConfigError(`${field} must be a non-negative integer`);
1448
+ }
1449
+ return raw;
1450
+ }
1451
+ function prepareSeriesLocal(input, chainId) {
1452
+ const pool = requireAddr(input.epochPrizePool, "epochPrizePool");
1453
+ const series = requireSeries(input.series);
1454
+ const feeBps = parseSeriesBps(input.feeBps, "feeBps");
1455
+ if (feeBps !== void 0 && feeBps !== LOCKED_SERIES_FEE_BPS) {
1456
+ throw new ConfigError(
1457
+ "feeBps must be 100 (the locked 1% Playmos take); refused before anything signable"
1458
+ );
1459
+ }
1460
+ const poolBps = parseSeriesBps(input.poolBps, "poolBps") ?? DEFAULT_SERIES_POOL_BPS;
1461
+ const seedBps = parseSeriesBps(input.seedBps, "seedBps") ?? DEFAULT_SERIES_SEED_BPS;
1462
+ if (LOCKED_SERIES_FEE_BPS + poolBps + seedBps !== 1e4) {
1463
+ throw new ConfigError("feeBps + poolBps + seedBps must sum to 10000 (fee is 100)");
1464
+ }
1465
+ const epochDuration = toBig(input.epochDuration, 0n);
1466
+ const entry = toBig(input.entry, 0n);
1467
+ if (epochDuration <= 0n) throw new ConfigError("epochDuration must be greater than 0");
1468
+ if (entry <= 0n) throw new ConfigError("entry must be greater than 0");
1469
+ const genesis = toBig(input.genesis, BigInt(Math.floor(Date.now() / 1e3)));
1470
+ if (genesis <= 0n) throw new ConfigError("genesis must be greater than 0");
1471
+ const data = viem.encodeFunctionData({
1472
+ abi: epochPrizePoolCreateSeriesAbi,
1473
+ functionName: "createSeries",
1474
+ args: [
1475
+ seriesToBytes32(series),
1476
+ genesis,
1477
+ epochDuration,
1478
+ entry,
1479
+ LOCKED_SERIES_FEE_BPS,
1480
+ poolBps,
1481
+ seedBps
1482
+ ]
1483
+ });
1484
+ return {
1485
+ series,
1486
+ epochPrizePool: pool,
1487
+ genesis: genesis.toString(),
1488
+ epochDuration: epochDuration.toString(),
1489
+ entry: entry.toString(),
1490
+ feeBps: 100,
1491
+ poolBps,
1492
+ seedBps,
1493
+ unsignedTx: {
1494
+ chainId,
1495
+ to: pool,
1496
+ value: "0",
1497
+ data
1498
+ },
1499
+ broadcast: false,
1500
+ via: "mock",
1501
+ mock: true
1502
+ };
1503
+ }
1307
1504
  function prepareStudioPoolLocal(input, playmosFeeSink, token, playmosAddresses = []) {
1308
1505
  const studio = requireAddr(input.studioWallet, "studioWallet");
1309
1506
  const locked = PLAYMOS_FEE_SINK_DEFAULT;
@@ -1452,6 +1649,7 @@ async function readEpochTerminal(deps, pool, series, epochId) {
1452
1649
  }
1453
1650
  }
1454
1651
  function createEpochsApi(deps) {
1652
+ const mockPreparedSeries = /* @__PURE__ */ new Map();
1455
1653
  return {
1456
1654
  async currentId(input) {
1457
1655
  const series = requireSeries(input?.series);
@@ -1529,6 +1727,9 @@ function createEpochsApi(deps) {
1529
1727
  const series = requireSeries(input?.series);
1530
1728
  const cfg = deps.config();
1531
1729
  if (cfg.mock) {
1730
+ const pool = (input.epochPrizePool ?? cfg.contracts?.epochPrizePool ?? "").toLowerCase();
1731
+ const prepared = mockPreparedSeries.get(`${pool}:${series}`);
1732
+ if (prepared) return prepared;
1532
1733
  return {
1533
1734
  series,
1534
1735
  created: true,
@@ -1549,6 +1750,42 @@ function createEpochsApi(deps) {
1549
1750
  })}`;
1550
1751
  return deps.http().get(path);
1551
1752
  },
1753
+ async prepareSeries(input) {
1754
+ const feeBps = input?.feeBps;
1755
+ if (feeBps !== void 0 && feeBps !== LOCKED_SERIES_FEE_BPS) {
1756
+ throw new ConfigError(
1757
+ "feeBps must be 100 (the locked 1% Playmos take); refused before anything signable"
1758
+ );
1759
+ }
1760
+ const cfg = deps.config();
1761
+ if (cfg.mock) {
1762
+ const prepared = prepareSeriesLocal(input, CHAIN_ID["base-sepolia"]);
1763
+ mockPreparedSeries.set(`${prepared.epochPrizePool}:${prepared.series}`, {
1764
+ series: prepared.series,
1765
+ created: true,
1766
+ genesis: prepared.genesis,
1767
+ epochDuration: prepared.epochDuration,
1768
+ entry: prepared.entry,
1769
+ feeBps: prepared.feeBps,
1770
+ poolBps: prepared.poolBps,
1771
+ seedBps: prepared.seedBps,
1772
+ via: "mock",
1773
+ epochPrizePool: prepared.epochPrizePool,
1774
+ mock: true
1775
+ });
1776
+ return prepared;
1777
+ }
1778
+ return deps.http().post("/epochs/series/prepare", {
1779
+ epochPrizePool: requireAddr(input?.epochPrizePool, "epochPrizePool"),
1780
+ series: requireSeries(input?.series),
1781
+ epochDuration: input.epochDuration,
1782
+ entry: input.entry,
1783
+ genesis: input.genesis,
1784
+ feeBps: input.feeBps,
1785
+ poolBps: input.poolBps,
1786
+ seedBps: input.seedBps
1787
+ });
1788
+ },
1552
1789
  async preparePool(input) {
1553
1790
  const studioWallet = requireAddr(input?.studioWallet, "studioWallet");
1554
1791
  const cfg = deps.config();
@@ -4238,8 +4475,11 @@ exports.C1_ENTER_SPLIT_MICRO = C1_ENTER_SPLIT_MICRO;
4238
4475
  exports.CHAIN_ID = CHAIN_ID;
4239
4476
  exports.ConfigError = ConfigError;
4240
4477
  exports.DEFAULT_API_BASE_URL = DEFAULT_API_BASE_URL;
4478
+ exports.DEFAULT_SERIES_POOL_BPS = DEFAULT_SERIES_POOL_BPS;
4479
+ exports.DEFAULT_SERIES_SEED_BPS = DEFAULT_SERIES_SEED_BPS;
4241
4480
  exports.InsufficientGasError = InsufficientGasError;
4242
4481
  exports.InvalidAmountError = InvalidAmountError;
4482
+ exports.LOCKED_SERIES_FEE_BPS = LOCKED_SERIES_FEE_BPS;
4243
4483
  exports.MICRO_PER_USDC = MICRO_PER_USDC;
4244
4484
  exports.MissingFieldError = MissingFieldError;
4245
4485
  exports.NothingToWithdrawError = NothingToWithdrawError;
@@ -4279,6 +4519,7 @@ exports.networkToCaip2 = networkToCaip2;
4279
4519
  exports.parsePaymentRequirement = parsePaymentRequirement;
4280
4520
  exports.parseUsdToMicro = parseUsdToMicro;
4281
4521
  exports.prefixedId = prefixedId;
4522
+ exports.prepareSeriesLocal = prepareSeriesLocal;
4282
4523
  exports.prepareStudioPoolLocal = prepareStudioPoolLocal;
4283
4524
  exports.previewEscrowFee = previewEscrowFee;
4284
4525
  exports.previewIapSplit = previewIapSplit;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as Call, P as PlaymosConfig, O as OnchainStatus, N as Network, W as WebhookEvent, R as RoundOpenInput, a as RoundState, b as RoundSettleInput, S as SettleRoundResult, c as RoundCancelInput, d as CancelRoundResult, e as RoundGetResult, A as ActiveSeriesRound, f as PayoutNoticesResult, g as PrizeBalance, h as WithdrawResult, i as AgentWallet, j as AgentFundResult, T as TransferResult, E as EscrowHoldInput, k as EscrowHoldResult, l as EscrowResolveResult, M as MarketplaceListInput, L as Listing, m as MarketplaceSaleResult, n as MarketplaceGetResult, o as PayInput, p as Payment, q as EnterRoundInput, r as TransferReconcile, s as WaitOptions, t as TransferInput, u as TransferConfirmOptions, V as VerifyResult, v as PayoutRule } from './errors-WcDNfb4q.cjs';
2
- export { w as ActiveForSeriesResult, x as AgentEconomyConfig, y as AlreadyEnteredError, z as ApiError, B as AuthError, D as ConfigError, F as ContractConfig, G as Eip1193Provider, H as GasConfig, I as GasMode, J as InsufficientGasError, K as InvalidAmountError, Q as ListingStatus, U as MarketplaceItem, X as MarketplaceSale, Y as MissingFieldError, Z as NothingToWithdrawError, _ as PaymentFailedError, $ as PaymentStatus, a0 as PayoutNotice, a1 as PayoutNoticeStatus, a2 as PlaymosError, a3 as PlaymosErrorCode, a4 as RetryOptions, a5 as RoundGetVia, a6 as RoundStatus, a7 as WalletConfig, a8 as WalletConnectionError, a9 as WalletConnector, aa as WalletTimeoutError, ab as WebhookEventType, ac as buildEpochExecuteSettlementCall } from './errors-WcDNfb4q.cjs';
1
+ import { C as Call, P as PlaymosConfig, O as OnchainStatus, N as Network, W as WebhookEvent, R as RoundOpenInput, a as RoundState, b as RoundSettleInput, S as SettleRoundResult, c as RoundCancelInput, d as CancelRoundResult, e as RoundGetResult, A as ActiveSeriesRound, f as PayoutNoticesResult, g as PrizeBalance, h as WithdrawResult, i as AgentWallet, j as AgentFundResult, T as TransferResult, E as EscrowHoldInput, k as EscrowHoldResult, l as EscrowResolveResult, M as MarketplaceListInput, L as Listing, m as MarketplaceSaleResult, n as MarketplaceGetResult, o as PayInput, p as Payment, q as EnterRoundInput, r as TransferReconcile, s as WaitOptions, t as TransferInput, u as TransferConfirmOptions, V as VerifyResult, v as PayoutRule } from './errors-CdzI_iYO.cjs';
2
+ export { w as ActiveForSeriesResult, x as AgentEconomyConfig, y as AlreadyEnteredError, z as ApiError, B as AuthError, D as ConfigError, F as ContractConfig, G as Eip1193Provider, H as GasConfig, I as GasMode, J as InsufficientGasError, K as InvalidAmountError, Q as ListingStatus, U as MarketplaceItem, X as MarketplaceSale, Y as MissingFieldError, Z as NothingToWithdrawError, _ as PaymentFailedError, $ as PaymentStatus, a0 as PayoutNotice, a1 as PayoutNoticeStatus, a2 as PlaymosError, a3 as PlaymosErrorCode, a4 as RetryOptions, a5 as RoundGetVia, a6 as RoundStatus, a7 as WalletConfig, a8 as WalletConnectionError, a9 as WalletConnector, aa as WalletTimeoutError, ab as WebhookEventType, ac as buildEpochExecuteSettlementCall } from './errors-CdzI_iYO.cjs';
3
3
 
4
4
  /**
5
5
  * Thin REST client for the Playmos service. Every SDK method that touches the
@@ -88,6 +88,8 @@ declare function buildEpochWithdrawCall(epochPrizePool: `0x${string}`): Call;
88
88
  * `epochs.enter` — pay into whatever window the clock says is current; no open
89
89
  * gate. `epochs.preparePool` / `registerPool` / `createPool` — studio wallet
90
90
  * deploys the existing EpochPrizePool constructor; Playmos is feeSink only.
91
+ * `epochs.prepareSeries` — unsigned createSeries tx; studio EOA signs; Playmos
92
+ * never broadcasts (sdk#739).
91
93
  * `epochs.settle` — secret key, operator wallet, broadcast + 202. Passes the
92
94
  * roster through; does not build a hub roster (R7b).
93
95
  * `epochs.claimableRefund` / `claimRefund` / `withdraw` — wallet-direct on
@@ -243,6 +245,44 @@ interface EpochEntry {
243
245
  via: EpochReadVia;
244
246
  mock?: true;
245
247
  }
248
+ /** Locked 1% Playmos take on a studio series. Any other fee is refused before signable bytes. */
249
+ declare const LOCKED_SERIES_FEE_BPS = 100;
250
+ /** Default prize-bucket bps when the studio does not type a split (fee 100 + seed 2000 = 10000). */
251
+ declare const DEFAULT_SERIES_POOL_BPS = 7900;
252
+ /** Default next-window seed bps when the studio does not type a split. */
253
+ declare const DEFAULT_SERIES_SEED_BPS = 2000;
254
+ interface EpochPrepareSeriesInput {
255
+ epochPrizePool: `0x${string}`;
256
+ series: string;
257
+ epochDuration: number | string;
258
+ /** Integer micro-USDC. */
259
+ entry: number | string;
260
+ genesis?: number | string;
261
+ /** Must be 100 if set — the locked 1% Playmos take. */
262
+ feeBps?: number;
263
+ poolBps?: number;
264
+ seedBps?: number;
265
+ }
266
+ interface EpochPreparedSeries {
267
+ series: string;
268
+ epochPrizePool: `0x${string}`;
269
+ genesis: string;
270
+ epochDuration: string;
271
+ entry: string;
272
+ feeBps: 100;
273
+ poolBps: number;
274
+ seedBps: number;
275
+ unsignedTx: {
276
+ chainId: number;
277
+ to: `0x${string}`;
278
+ value: "0";
279
+ data: `0x${string}`;
280
+ };
281
+ /** Playmos never broadcasts. Studio EOA sends. */
282
+ broadcast: false;
283
+ via: EpochReadVia;
284
+ mock?: true;
285
+ }
246
286
  interface EpochPreparePoolInput {
247
287
  studioWallet: `0x${string}`;
248
288
  /** Must equal the Playmos sink if set; any other address is refused before broadcast. */
@@ -531,6 +571,7 @@ interface EpochsApi {
531
571
  prize(input: EpochPrizeInput): Promise<EpochPrize>;
532
572
  get(input: EpochGetInput): Promise<EpochView>;
533
573
  getSeries(input: EpochGetSeriesInput): Promise<EpochSeriesView>;
574
+ prepareSeries(input: EpochPrepareSeriesInput): Promise<EpochPreparedSeries>;
534
575
  preparePool(input: EpochPreparePoolInput): Promise<EpochPreparedPool>;
535
576
  registerPool(input: EpochRegisterPoolInput): Promise<EpochStudioPool>;
536
577
  createPool(input: EpochCreatePoolInput): Promise<EpochStudioPool>;
@@ -603,6 +644,8 @@ interface EpochsDeps {
603
644
  declare function derivedEpochId(genesis: bigint, epochDuration: bigint, at: bigint): bigint;
604
645
  /** Settle payable is inherited seed + this epoch's pool (not outgoingSeed). */
605
646
  declare function epochPayableMicro(incomingSeed: bigint, pool: bigint): bigint;
647
+ /** Same refuse-before-signable posture as preparePool's feeSink check. */
648
+ declare function prepareSeriesLocal(input: EpochPrepareSeriesInput, chainId: number): EpochPreparedSeries;
606
649
  /** Client-side pin — same refusals as the service, so a bad sink never reaches broadcast. */
607
650
  declare function prepareStudioPoolLocal(input: EpochPreparePoolInput, playmosFeeSink: `0x${string}`, token: `0x${string}`, playmosAddresses?: `0x${string}`[]): EpochPreparedPool;
608
651
  /**
@@ -1593,4 +1636,4 @@ declare function ulid(seedTime?: number): string;
1593
1636
  /** `${prefix}_${ulid()}` — e.g. `pay_01J…`, `entry_01J…`, `idem_01J…`. */
1594
1637
  declare function prefixedId(prefix: string): string;
1595
1638
 
1596
- export { ActiveSeriesRound, AgentFundResult, AgentWallet, type Authorization, C1_ENTER_SPLIT_MICRO, CHAIN_ID, CancelRoundResult, type CreatePaymentRequirementInput, DEFAULT_API_BASE_URL, EnterRoundInput, type EpochAttestation, type EpochClaimRefundInput, type EpochClaimRefundResult, type EpochClaimableRefund, type EpochClaimableRefundInput, type EpochCreatePoolInput, type EpochCurrentId, type EpochCurrentIdInput, type EpochEnterInput, type EpochEntry, type EpochEntryStatus, type EpochExecuteSettlementInput, type EpochExecuteSettlementResult, type EpochGetAttestationInput, type EpochGetInput, type EpochGetSeriesInput, type EpochPoolOwnership, type EpochPoolWalletProof, type EpochPreparePoolInput, type EpochPreparedPool, type EpochPrize, type EpochPrizeInput, type EpochReadVia, type EpochRegisterPoolInput, type EpochSeriesView, type EpochSettleInput, type EpochSettleResult, type EpochSettleStatus, type EpochSettleWinner, type EpochStudioPool, type EpochTerminal, type EpochView, type EpochWinnerIn, type EpochWithdrawInput, type EpochWithdrawResult, type EpochsApi, EscrowHoldInput, EscrowHoldResult, EscrowResolveResult, Listing, MICRO_PER_USDC, MarketplaceGetResult, MarketplaceListInput, MarketplaceSaleResult, Network, PLAYMOS_FEE_SINK_DEFAULT, PayInput, Payment, type PaymentRequirement, PayoutError, PayoutNoticesResult, PayoutRule, PayoutRule as PayoutRuleCompute, Playmos, PlaymosConfig, PrizeBalance, RETIRED_PLAYMOS_FEE_SINK, RoundCancelInput, RoundGetResult, RoundOpenInput, RoundSettleInput, RoundState, SettleRoundResult, type SettlementAsset, type SettlementTypedData, type SettlementTypedDataInput, TransferConfirmOptions, TransferInput, TransferReconcile, TransferResult, USDC_ADDRESS, USDC_DECIMALS, VerifyResult, WaitOptions, type WalletSignatureAuthorization, WebhookEvent, WithdrawResult, type X402ChallengeInput, type X402ChallengeResult, type X402FulfillAuthorization, type X402PayInput, type X402PayloadAuthorization, type X402PayloadMode, type X402PaymentRequired, type X402SettleResult, buildEpochClaimRefundCall, buildEpochEntryCalls, buildEpochWithdrawCall, clientRuntimeSignals, computeIapSplit, computePayout, computePoolSplit, createEpochsApi, createPaymentRequirement, createX402Challenge, decodePaymentHeader, derivedEpochId, encodeEpochPoolConstructorArgs, encodePaymentHeader, epochPayableMicro, epochPoolProofMessage, formatMicroToUsd, identityToBytes32, isClientRuntime, isWalletSignatureAuthorization, isX402PayloadAuthorization, networkToCaip2, parsePaymentRequirement, parseUsdToMicro, prefixedId, prepareStudioPoolLocal, previewEscrowFee, previewIapSplit, previewMarketplaceSplit, previewPoolSplit, previewTransferSplit, resolveEnv, serializePaymentRequirement, seriesToBytes32, settlementTypedData, toX402PaymentRequired, ulid, validateX402ChallengeInput };
1639
+ export { ActiveSeriesRound, AgentFundResult, AgentWallet, type Authorization, C1_ENTER_SPLIT_MICRO, CHAIN_ID, CancelRoundResult, type CreatePaymentRequirementInput, DEFAULT_API_BASE_URL, DEFAULT_SERIES_POOL_BPS, DEFAULT_SERIES_SEED_BPS, EnterRoundInput, type EpochAttestation, type EpochClaimRefundInput, type EpochClaimRefundResult, type EpochClaimableRefund, type EpochClaimableRefundInput, type EpochCreatePoolInput, type EpochCurrentId, type EpochCurrentIdInput, type EpochEnterInput, type EpochEntry, type EpochEntryStatus, type EpochExecuteSettlementInput, type EpochExecuteSettlementResult, type EpochGetAttestationInput, type EpochGetInput, type EpochGetSeriesInput, type EpochPoolOwnership, type EpochPoolWalletProof, type EpochPreparePoolInput, type EpochPrepareSeriesInput, type EpochPreparedPool, type EpochPreparedSeries, type EpochPrize, type EpochPrizeInput, type EpochReadVia, type EpochRegisterPoolInput, type EpochSeriesView, type EpochSettleInput, type EpochSettleResult, type EpochSettleStatus, type EpochSettleWinner, type EpochStudioPool, type EpochTerminal, type EpochView, type EpochWinnerIn, type EpochWithdrawInput, type EpochWithdrawResult, type EpochsApi, EscrowHoldInput, EscrowHoldResult, EscrowResolveResult, LOCKED_SERIES_FEE_BPS, Listing, MICRO_PER_USDC, MarketplaceGetResult, MarketplaceListInput, MarketplaceSaleResult, Network, PLAYMOS_FEE_SINK_DEFAULT, PayInput, Payment, type PaymentRequirement, PayoutError, PayoutNoticesResult, PayoutRule, PayoutRule as PayoutRuleCompute, Playmos, PlaymosConfig, PrizeBalance, RETIRED_PLAYMOS_FEE_SINK, RoundCancelInput, RoundGetResult, RoundOpenInput, RoundSettleInput, RoundState, SettleRoundResult, type SettlementAsset, type SettlementTypedData, type SettlementTypedDataInput, TransferConfirmOptions, TransferInput, TransferReconcile, TransferResult, USDC_ADDRESS, USDC_DECIMALS, VerifyResult, WaitOptions, type WalletSignatureAuthorization, WebhookEvent, WithdrawResult, type X402ChallengeInput, type X402ChallengeResult, type X402FulfillAuthorization, type X402PayInput, type X402PayloadAuthorization, type X402PayloadMode, type X402PaymentRequired, type X402SettleResult, buildEpochClaimRefundCall, buildEpochEntryCalls, buildEpochWithdrawCall, clientRuntimeSignals, computeIapSplit, computePayout, computePoolSplit, createEpochsApi, createPaymentRequirement, createX402Challenge, decodePaymentHeader, derivedEpochId, encodeEpochPoolConstructorArgs, encodePaymentHeader, epochPayableMicro, epochPoolProofMessage, formatMicroToUsd, identityToBytes32, isClientRuntime, isWalletSignatureAuthorization, isX402PayloadAuthorization, networkToCaip2, parsePaymentRequirement, parseUsdToMicro, prefixedId, prepareSeriesLocal, prepareStudioPoolLocal, previewEscrowFee, previewIapSplit, previewMarketplaceSplit, previewPoolSplit, previewTransferSplit, resolveEnv, serializePaymentRequirement, seriesToBytes32, settlementTypedData, toX402PaymentRequired, ulid, validateX402ChallengeInput };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as Call, P as PlaymosConfig, O as OnchainStatus, N as Network, W as WebhookEvent, R as RoundOpenInput, a as RoundState, b as RoundSettleInput, S as SettleRoundResult, c as RoundCancelInput, d as CancelRoundResult, e as RoundGetResult, A as ActiveSeriesRound, f as PayoutNoticesResult, g as PrizeBalance, h as WithdrawResult, i as AgentWallet, j as AgentFundResult, T as TransferResult, E as EscrowHoldInput, k as EscrowHoldResult, l as EscrowResolveResult, M as MarketplaceListInput, L as Listing, m as MarketplaceSaleResult, n as MarketplaceGetResult, o as PayInput, p as Payment, q as EnterRoundInput, r as TransferReconcile, s as WaitOptions, t as TransferInput, u as TransferConfirmOptions, V as VerifyResult, v as PayoutRule } from './errors-WcDNfb4q.js';
2
- export { w as ActiveForSeriesResult, x as AgentEconomyConfig, y as AlreadyEnteredError, z as ApiError, B as AuthError, D as ConfigError, F as ContractConfig, G as Eip1193Provider, H as GasConfig, I as GasMode, J as InsufficientGasError, K as InvalidAmountError, Q as ListingStatus, U as MarketplaceItem, X as MarketplaceSale, Y as MissingFieldError, Z as NothingToWithdrawError, _ as PaymentFailedError, $ as PaymentStatus, a0 as PayoutNotice, a1 as PayoutNoticeStatus, a2 as PlaymosError, a3 as PlaymosErrorCode, a4 as RetryOptions, a5 as RoundGetVia, a6 as RoundStatus, a7 as WalletConfig, a8 as WalletConnectionError, a9 as WalletConnector, aa as WalletTimeoutError, ab as WebhookEventType, ac as buildEpochExecuteSettlementCall } from './errors-WcDNfb4q.js';
1
+ import { C as Call, P as PlaymosConfig, O as OnchainStatus, N as Network, W as WebhookEvent, R as RoundOpenInput, a as RoundState, b as RoundSettleInput, S as SettleRoundResult, c as RoundCancelInput, d as CancelRoundResult, e as RoundGetResult, A as ActiveSeriesRound, f as PayoutNoticesResult, g as PrizeBalance, h as WithdrawResult, i as AgentWallet, j as AgentFundResult, T as TransferResult, E as EscrowHoldInput, k as EscrowHoldResult, l as EscrowResolveResult, M as MarketplaceListInput, L as Listing, m as MarketplaceSaleResult, n as MarketplaceGetResult, o as PayInput, p as Payment, q as EnterRoundInput, r as TransferReconcile, s as WaitOptions, t as TransferInput, u as TransferConfirmOptions, V as VerifyResult, v as PayoutRule } from './errors-CdzI_iYO.js';
2
+ export { w as ActiveForSeriesResult, x as AgentEconomyConfig, y as AlreadyEnteredError, z as ApiError, B as AuthError, D as ConfigError, F as ContractConfig, G as Eip1193Provider, H as GasConfig, I as GasMode, J as InsufficientGasError, K as InvalidAmountError, Q as ListingStatus, U as MarketplaceItem, X as MarketplaceSale, Y as MissingFieldError, Z as NothingToWithdrawError, _ as PaymentFailedError, $ as PaymentStatus, a0 as PayoutNotice, a1 as PayoutNoticeStatus, a2 as PlaymosError, a3 as PlaymosErrorCode, a4 as RetryOptions, a5 as RoundGetVia, a6 as RoundStatus, a7 as WalletConfig, a8 as WalletConnectionError, a9 as WalletConnector, aa as WalletTimeoutError, ab as WebhookEventType, ac as buildEpochExecuteSettlementCall } from './errors-CdzI_iYO.js';
3
3
 
4
4
  /**
5
5
  * Thin REST client for the Playmos service. Every SDK method that touches the
@@ -88,6 +88,8 @@ declare function buildEpochWithdrawCall(epochPrizePool: `0x${string}`): Call;
88
88
  * `epochs.enter` — pay into whatever window the clock says is current; no open
89
89
  * gate. `epochs.preparePool` / `registerPool` / `createPool` — studio wallet
90
90
  * deploys the existing EpochPrizePool constructor; Playmos is feeSink only.
91
+ * `epochs.prepareSeries` — unsigned createSeries tx; studio EOA signs; Playmos
92
+ * never broadcasts (sdk#739).
91
93
  * `epochs.settle` — secret key, operator wallet, broadcast + 202. Passes the
92
94
  * roster through; does not build a hub roster (R7b).
93
95
  * `epochs.claimableRefund` / `claimRefund` / `withdraw` — wallet-direct on
@@ -243,6 +245,44 @@ interface EpochEntry {
243
245
  via: EpochReadVia;
244
246
  mock?: true;
245
247
  }
248
+ /** Locked 1% Playmos take on a studio series. Any other fee is refused before signable bytes. */
249
+ declare const LOCKED_SERIES_FEE_BPS = 100;
250
+ /** Default prize-bucket bps when the studio does not type a split (fee 100 + seed 2000 = 10000). */
251
+ declare const DEFAULT_SERIES_POOL_BPS = 7900;
252
+ /** Default next-window seed bps when the studio does not type a split. */
253
+ declare const DEFAULT_SERIES_SEED_BPS = 2000;
254
+ interface EpochPrepareSeriesInput {
255
+ epochPrizePool: `0x${string}`;
256
+ series: string;
257
+ epochDuration: number | string;
258
+ /** Integer micro-USDC. */
259
+ entry: number | string;
260
+ genesis?: number | string;
261
+ /** Must be 100 if set — the locked 1% Playmos take. */
262
+ feeBps?: number;
263
+ poolBps?: number;
264
+ seedBps?: number;
265
+ }
266
+ interface EpochPreparedSeries {
267
+ series: string;
268
+ epochPrizePool: `0x${string}`;
269
+ genesis: string;
270
+ epochDuration: string;
271
+ entry: string;
272
+ feeBps: 100;
273
+ poolBps: number;
274
+ seedBps: number;
275
+ unsignedTx: {
276
+ chainId: number;
277
+ to: `0x${string}`;
278
+ value: "0";
279
+ data: `0x${string}`;
280
+ };
281
+ /** Playmos never broadcasts. Studio EOA sends. */
282
+ broadcast: false;
283
+ via: EpochReadVia;
284
+ mock?: true;
285
+ }
246
286
  interface EpochPreparePoolInput {
247
287
  studioWallet: `0x${string}`;
248
288
  /** Must equal the Playmos sink if set; any other address is refused before broadcast. */
@@ -531,6 +571,7 @@ interface EpochsApi {
531
571
  prize(input: EpochPrizeInput): Promise<EpochPrize>;
532
572
  get(input: EpochGetInput): Promise<EpochView>;
533
573
  getSeries(input: EpochGetSeriesInput): Promise<EpochSeriesView>;
574
+ prepareSeries(input: EpochPrepareSeriesInput): Promise<EpochPreparedSeries>;
534
575
  preparePool(input: EpochPreparePoolInput): Promise<EpochPreparedPool>;
535
576
  registerPool(input: EpochRegisterPoolInput): Promise<EpochStudioPool>;
536
577
  createPool(input: EpochCreatePoolInput): Promise<EpochStudioPool>;
@@ -603,6 +644,8 @@ interface EpochsDeps {
603
644
  declare function derivedEpochId(genesis: bigint, epochDuration: bigint, at: bigint): bigint;
604
645
  /** Settle payable is inherited seed + this epoch's pool (not outgoingSeed). */
605
646
  declare function epochPayableMicro(incomingSeed: bigint, pool: bigint): bigint;
647
+ /** Same refuse-before-signable posture as preparePool's feeSink check. */
648
+ declare function prepareSeriesLocal(input: EpochPrepareSeriesInput, chainId: number): EpochPreparedSeries;
606
649
  /** Client-side pin — same refusals as the service, so a bad sink never reaches broadcast. */
607
650
  declare function prepareStudioPoolLocal(input: EpochPreparePoolInput, playmosFeeSink: `0x${string}`, token: `0x${string}`, playmosAddresses?: `0x${string}`[]): EpochPreparedPool;
608
651
  /**
@@ -1593,4 +1636,4 @@ declare function ulid(seedTime?: number): string;
1593
1636
  /** `${prefix}_${ulid()}` — e.g. `pay_01J…`, `entry_01J…`, `idem_01J…`. */
1594
1637
  declare function prefixedId(prefix: string): string;
1595
1638
 
1596
- export { ActiveSeriesRound, AgentFundResult, AgentWallet, type Authorization, C1_ENTER_SPLIT_MICRO, CHAIN_ID, CancelRoundResult, type CreatePaymentRequirementInput, DEFAULT_API_BASE_URL, EnterRoundInput, type EpochAttestation, type EpochClaimRefundInput, type EpochClaimRefundResult, type EpochClaimableRefund, type EpochClaimableRefundInput, type EpochCreatePoolInput, type EpochCurrentId, type EpochCurrentIdInput, type EpochEnterInput, type EpochEntry, type EpochEntryStatus, type EpochExecuteSettlementInput, type EpochExecuteSettlementResult, type EpochGetAttestationInput, type EpochGetInput, type EpochGetSeriesInput, type EpochPoolOwnership, type EpochPoolWalletProof, type EpochPreparePoolInput, type EpochPreparedPool, type EpochPrize, type EpochPrizeInput, type EpochReadVia, type EpochRegisterPoolInput, type EpochSeriesView, type EpochSettleInput, type EpochSettleResult, type EpochSettleStatus, type EpochSettleWinner, type EpochStudioPool, type EpochTerminal, type EpochView, type EpochWinnerIn, type EpochWithdrawInput, type EpochWithdrawResult, type EpochsApi, EscrowHoldInput, EscrowHoldResult, EscrowResolveResult, Listing, MICRO_PER_USDC, MarketplaceGetResult, MarketplaceListInput, MarketplaceSaleResult, Network, PLAYMOS_FEE_SINK_DEFAULT, PayInput, Payment, type PaymentRequirement, PayoutError, PayoutNoticesResult, PayoutRule, PayoutRule as PayoutRuleCompute, Playmos, PlaymosConfig, PrizeBalance, RETIRED_PLAYMOS_FEE_SINK, RoundCancelInput, RoundGetResult, RoundOpenInput, RoundSettleInput, RoundState, SettleRoundResult, type SettlementAsset, type SettlementTypedData, type SettlementTypedDataInput, TransferConfirmOptions, TransferInput, TransferReconcile, TransferResult, USDC_ADDRESS, USDC_DECIMALS, VerifyResult, WaitOptions, type WalletSignatureAuthorization, WebhookEvent, WithdrawResult, type X402ChallengeInput, type X402ChallengeResult, type X402FulfillAuthorization, type X402PayInput, type X402PayloadAuthorization, type X402PayloadMode, type X402PaymentRequired, type X402SettleResult, buildEpochClaimRefundCall, buildEpochEntryCalls, buildEpochWithdrawCall, clientRuntimeSignals, computeIapSplit, computePayout, computePoolSplit, createEpochsApi, createPaymentRequirement, createX402Challenge, decodePaymentHeader, derivedEpochId, encodeEpochPoolConstructorArgs, encodePaymentHeader, epochPayableMicro, epochPoolProofMessage, formatMicroToUsd, identityToBytes32, isClientRuntime, isWalletSignatureAuthorization, isX402PayloadAuthorization, networkToCaip2, parsePaymentRequirement, parseUsdToMicro, prefixedId, prepareStudioPoolLocal, previewEscrowFee, previewIapSplit, previewMarketplaceSplit, previewPoolSplit, previewTransferSplit, resolveEnv, serializePaymentRequirement, seriesToBytes32, settlementTypedData, toX402PaymentRequired, ulid, validateX402ChallengeInput };
1639
+ export { ActiveSeriesRound, AgentFundResult, AgentWallet, type Authorization, C1_ENTER_SPLIT_MICRO, CHAIN_ID, CancelRoundResult, type CreatePaymentRequirementInput, DEFAULT_API_BASE_URL, DEFAULT_SERIES_POOL_BPS, DEFAULT_SERIES_SEED_BPS, EnterRoundInput, type EpochAttestation, type EpochClaimRefundInput, type EpochClaimRefundResult, type EpochClaimableRefund, type EpochClaimableRefundInput, type EpochCreatePoolInput, type EpochCurrentId, type EpochCurrentIdInput, type EpochEnterInput, type EpochEntry, type EpochEntryStatus, type EpochExecuteSettlementInput, type EpochExecuteSettlementResult, type EpochGetAttestationInput, type EpochGetInput, type EpochGetSeriesInput, type EpochPoolOwnership, type EpochPoolWalletProof, type EpochPreparePoolInput, type EpochPrepareSeriesInput, type EpochPreparedPool, type EpochPreparedSeries, type EpochPrize, type EpochPrizeInput, type EpochReadVia, type EpochRegisterPoolInput, type EpochSeriesView, type EpochSettleInput, type EpochSettleResult, type EpochSettleStatus, type EpochSettleWinner, type EpochStudioPool, type EpochTerminal, type EpochView, type EpochWinnerIn, type EpochWithdrawInput, type EpochWithdrawResult, type EpochsApi, EscrowHoldInput, EscrowHoldResult, EscrowResolveResult, LOCKED_SERIES_FEE_BPS, Listing, MICRO_PER_USDC, MarketplaceGetResult, MarketplaceListInput, MarketplaceSaleResult, Network, PLAYMOS_FEE_SINK_DEFAULT, PayInput, Payment, type PaymentRequirement, PayoutError, PayoutNoticesResult, PayoutRule, PayoutRule as PayoutRuleCompute, Playmos, PlaymosConfig, PrizeBalance, RETIRED_PLAYMOS_FEE_SINK, RoundCancelInput, RoundGetResult, RoundOpenInput, RoundSettleInput, RoundState, SettleRoundResult, type SettlementAsset, type SettlementTypedData, type SettlementTypedDataInput, TransferConfirmOptions, TransferInput, TransferReconcile, TransferResult, USDC_ADDRESS, USDC_DECIMALS, VerifyResult, WaitOptions, type WalletSignatureAuthorization, WebhookEvent, WithdrawResult, type X402ChallengeInput, type X402ChallengeResult, type X402FulfillAuthorization, type X402PayInput, type X402PayloadAuthorization, type X402PayloadMode, type X402PaymentRequired, type X402SettleResult, buildEpochClaimRefundCall, buildEpochEntryCalls, buildEpochWithdrawCall, clientRuntimeSignals, computeIapSplit, computePayout, computePoolSplit, createEpochsApi, createPaymentRequirement, createX402Challenge, decodePaymentHeader, derivedEpochId, encodeEpochPoolConstructorArgs, encodePaymentHeader, epochPayableMicro, epochPoolProofMessage, formatMicroToUsd, identityToBytes32, isClientRuntime, isWalletSignatureAuthorization, isX402PayloadAuthorization, networkToCaip2, parsePaymentRequirement, parseUsdToMicro, prefixedId, prepareSeriesLocal, prepareStudioPoolLocal, previewEscrowFee, previewIapSplit, previewMarketplaceSplit, previewPoolSplit, previewTransferSplit, resolveEnv, serializePaymentRequirement, seriesToBytes32, settlementTypedData, toX402PaymentRequired, ulid, validateX402ChallengeInput };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { AuthError, InvalidAmountError, epochPrizePoolEnterAbi, seriesToBytes32, identityToBytes32, encodeApprove, epochPrizePoolRefundAbi, ConfigError, MissingFieldError, buildEpochExecuteSettlementCall, PaymentFailedError, epochPrizePoolViewAbi, ApiError, assertEnoughGas, sendCalls, waitForCalls, NothingToWithdrawError, buildWithdrawCall, WalletTimeoutError, buildIapCalls, buildEntryCalls, prizePoolAbi, WalletConnectionError, AlreadyEnteredError } from './chunk-TZFGZNXV.js';
2
- export { AlreadyEnteredError, ApiError, AuthError, ConfigError, InsufficientGasError, InvalidAmountError, MissingFieldError, NothingToWithdrawError, PaymentFailedError, PlaymosError, WalletConnectionError, WalletTimeoutError, buildEpochExecuteSettlementCall, identityToBytes32, seriesToBytes32 } from './chunk-TZFGZNXV.js';
1
+ import { AuthError, InvalidAmountError, epochPrizePoolEnterAbi, seriesToBytes32, identityToBytes32, encodeApprove, epochPrizePoolRefundAbi, ConfigError, epochPrizePoolCreateSeriesAbi, MissingFieldError, buildEpochExecuteSettlementCall, PaymentFailedError, epochPrizePoolViewAbi, ApiError, assertEnoughGas, sendCalls, waitForCalls, NothingToWithdrawError, buildWithdrawCall, WalletTimeoutError, buildIapCalls, buildEntryCalls, prizePoolAbi, WalletConnectionError, AlreadyEnteredError } from './chunk-U6BPSEKC.js';
2
+ export { AlreadyEnteredError, ApiError, AuthError, ConfigError, InsufficientGasError, InvalidAmountError, MissingFieldError, NothingToWithdrawError, PaymentFailedError, PlaymosError, WalletConnectionError, WalletTimeoutError, buildEpochExecuteSettlementCall, identityToBytes32, seriesToBytes32 } from './chunk-U6BPSEKC.js';
3
3
  import { encodeFunctionData, encodeAbiParameters, decodeFunctionResult } from 'viem';
4
4
 
5
5
  // src/config.ts
@@ -692,6 +692,9 @@ function encodeEpochPoolConstructorArgs(args) {
692
692
  args.refundTimeout
693
693
  ]);
694
694
  }
695
+ var LOCKED_SERIES_FEE_BPS = 100;
696
+ var DEFAULT_SERIES_POOL_BPS = 7900;
697
+ var DEFAULT_SERIES_SEED_BPS = 2e3;
695
698
  function derivedEpochId(genesis, epochDuration, at) {
696
699
  if (epochDuration === 0n) {
697
700
  throw new ConfigError("epochDuration must be > 0");
@@ -860,6 +863,66 @@ function walletStatus(status) {
860
863
  function sameAddr(a, b) {
861
864
  return a.toLowerCase() === b.toLowerCase();
862
865
  }
866
+ function parseSeriesBps(raw, field) {
867
+ if (raw === void 0) return void 0;
868
+ if (!Number.isInteger(raw) || raw < 0) {
869
+ throw new ConfigError(`${field} must be a non-negative integer`);
870
+ }
871
+ return raw;
872
+ }
873
+ function prepareSeriesLocal(input, chainId) {
874
+ const pool = requireAddr(input.epochPrizePool, "epochPrizePool");
875
+ const series = requireSeries(input.series);
876
+ const feeBps = parseSeriesBps(input.feeBps, "feeBps");
877
+ if (feeBps !== void 0 && feeBps !== LOCKED_SERIES_FEE_BPS) {
878
+ throw new ConfigError(
879
+ "feeBps must be 100 (the locked 1% Playmos take); refused before anything signable"
880
+ );
881
+ }
882
+ const poolBps = parseSeriesBps(input.poolBps, "poolBps") ?? DEFAULT_SERIES_POOL_BPS;
883
+ const seedBps = parseSeriesBps(input.seedBps, "seedBps") ?? DEFAULT_SERIES_SEED_BPS;
884
+ if (LOCKED_SERIES_FEE_BPS + poolBps + seedBps !== 1e4) {
885
+ throw new ConfigError("feeBps + poolBps + seedBps must sum to 10000 (fee is 100)");
886
+ }
887
+ const epochDuration = toBig(input.epochDuration, 0n);
888
+ const entry = toBig(input.entry, 0n);
889
+ if (epochDuration <= 0n) throw new ConfigError("epochDuration must be greater than 0");
890
+ if (entry <= 0n) throw new ConfigError("entry must be greater than 0");
891
+ const genesis = toBig(input.genesis, BigInt(Math.floor(Date.now() / 1e3)));
892
+ if (genesis <= 0n) throw new ConfigError("genesis must be greater than 0");
893
+ const data = encodeFunctionData({
894
+ abi: epochPrizePoolCreateSeriesAbi,
895
+ functionName: "createSeries",
896
+ args: [
897
+ seriesToBytes32(series),
898
+ genesis,
899
+ epochDuration,
900
+ entry,
901
+ LOCKED_SERIES_FEE_BPS,
902
+ poolBps,
903
+ seedBps
904
+ ]
905
+ });
906
+ return {
907
+ series,
908
+ epochPrizePool: pool,
909
+ genesis: genesis.toString(),
910
+ epochDuration: epochDuration.toString(),
911
+ entry: entry.toString(),
912
+ feeBps: 100,
913
+ poolBps,
914
+ seedBps,
915
+ unsignedTx: {
916
+ chainId,
917
+ to: pool,
918
+ value: "0",
919
+ data
920
+ },
921
+ broadcast: false,
922
+ via: "mock",
923
+ mock: true
924
+ };
925
+ }
863
926
  function prepareStudioPoolLocal(input, playmosFeeSink, token, playmosAddresses = []) {
864
927
  const studio = requireAddr(input.studioWallet, "studioWallet");
865
928
  const locked = PLAYMOS_FEE_SINK_DEFAULT;
@@ -1008,6 +1071,7 @@ async function readEpochTerminal(deps, pool, series, epochId) {
1008
1071
  }
1009
1072
  }
1010
1073
  function createEpochsApi(deps) {
1074
+ const mockPreparedSeries = /* @__PURE__ */ new Map();
1011
1075
  return {
1012
1076
  async currentId(input) {
1013
1077
  const series = requireSeries(input?.series);
@@ -1085,6 +1149,9 @@ function createEpochsApi(deps) {
1085
1149
  const series = requireSeries(input?.series);
1086
1150
  const cfg = deps.config();
1087
1151
  if (cfg.mock) {
1152
+ const pool = (input.epochPrizePool ?? cfg.contracts?.epochPrizePool ?? "").toLowerCase();
1153
+ const prepared = mockPreparedSeries.get(`${pool}:${series}`);
1154
+ if (prepared) return prepared;
1088
1155
  return {
1089
1156
  series,
1090
1157
  created: true,
@@ -1105,6 +1172,42 @@ function createEpochsApi(deps) {
1105
1172
  })}`;
1106
1173
  return deps.http().get(path);
1107
1174
  },
1175
+ async prepareSeries(input) {
1176
+ const feeBps = input?.feeBps;
1177
+ if (feeBps !== void 0 && feeBps !== LOCKED_SERIES_FEE_BPS) {
1178
+ throw new ConfigError(
1179
+ "feeBps must be 100 (the locked 1% Playmos take); refused before anything signable"
1180
+ );
1181
+ }
1182
+ const cfg = deps.config();
1183
+ if (cfg.mock) {
1184
+ const prepared = prepareSeriesLocal(input, CHAIN_ID["base-sepolia"]);
1185
+ mockPreparedSeries.set(`${prepared.epochPrizePool}:${prepared.series}`, {
1186
+ series: prepared.series,
1187
+ created: true,
1188
+ genesis: prepared.genesis,
1189
+ epochDuration: prepared.epochDuration,
1190
+ entry: prepared.entry,
1191
+ feeBps: prepared.feeBps,
1192
+ poolBps: prepared.poolBps,
1193
+ seedBps: prepared.seedBps,
1194
+ via: "mock",
1195
+ epochPrizePool: prepared.epochPrizePool,
1196
+ mock: true
1197
+ });
1198
+ return prepared;
1199
+ }
1200
+ return deps.http().post("/epochs/series/prepare", {
1201
+ epochPrizePool: requireAddr(input?.epochPrizePool, "epochPrizePool"),
1202
+ series: requireSeries(input?.series),
1203
+ epochDuration: input.epochDuration,
1204
+ entry: input.entry,
1205
+ genesis: input.genesis,
1206
+ feeBps: input.feeBps,
1207
+ poolBps: input.poolBps,
1208
+ seedBps: input.seedBps
1209
+ });
1210
+ },
1108
1211
  async preparePool(input) {
1109
1212
  const studioWallet = requireAddr(input?.studioWallet, "studioWallet");
1110
1213
  const cfg = deps.config();
@@ -3787,4 +3890,4 @@ function isX402PayloadAuthorization(auth) {
3787
3890
  return auth.kind === "x402-payload";
3788
3891
  }
3789
3892
 
3790
- export { C1_ENTER_SPLIT_MICRO, CHAIN_ID, DEFAULT_API_BASE_URL, MICRO_PER_USDC, PLAYMOS_FEE_SINK_DEFAULT, PayoutError, Playmos, RETIRED_PLAYMOS_FEE_SINK, USDC_ADDRESS, USDC_DECIMALS, buildEpochClaimRefundCall, buildEpochEntryCalls, buildEpochWithdrawCall, clientRuntimeSignals, computeIapSplit, computePayout, computePoolSplit, createEpochsApi, createPaymentRequirement, createX402Challenge, decodePaymentHeader, derivedEpochId, encodeEpochPoolConstructorArgs, encodePaymentHeader, epochPayableMicro, epochPoolProofMessage, formatMicroToUsd, isClientRuntime, isWalletSignatureAuthorization, isX402PayloadAuthorization, networkToCaip2, parsePaymentRequirement, parseUsdToMicro, prefixedId, prepareStudioPoolLocal, previewEscrowFee, previewIapSplit, previewMarketplaceSplit, previewPoolSplit, previewTransferSplit, resolveEnv, serializePaymentRequirement, settlementTypedData, toX402PaymentRequired, ulid, validateX402ChallengeInput };
3893
+ export { C1_ENTER_SPLIT_MICRO, CHAIN_ID, DEFAULT_API_BASE_URL, DEFAULT_SERIES_POOL_BPS, DEFAULT_SERIES_SEED_BPS, LOCKED_SERIES_FEE_BPS, MICRO_PER_USDC, PLAYMOS_FEE_SINK_DEFAULT, PayoutError, Playmos, RETIRED_PLAYMOS_FEE_SINK, USDC_ADDRESS, USDC_DECIMALS, buildEpochClaimRefundCall, buildEpochEntryCalls, buildEpochWithdrawCall, clientRuntimeSignals, computeIapSplit, computePayout, computePoolSplit, createEpochsApi, createPaymentRequirement, createX402Challenge, decodePaymentHeader, derivedEpochId, encodeEpochPoolConstructorArgs, encodePaymentHeader, epochPayableMicro, epochPoolProofMessage, formatMicroToUsd, isClientRuntime, isWalletSignatureAuthorization, isX402PayloadAuthorization, networkToCaip2, parsePaymentRequirement, parseUsdToMicro, prefixedId, prepareSeriesLocal, prepareStudioPoolLocal, previewEscrowFee, previewIapSplit, previewMarketplaceSplit, previewPoolSplit, previewTransferSplit, resolveEnv, serializePaymentRequirement, settlementTypedData, toX402PaymentRequired, ulid, validateX402ChallengeInput };
package/dist/server.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { a2 as PlaymosError, W as WebhookEvent } from './errors-WcDNfb4q.cjs';
2
- export { ad as enterPathToBytes32 } from './errors-WcDNfb4q.cjs';
1
+ import { a2 as PlaymosError, W as WebhookEvent } from './errors-CdzI_iYO.cjs';
2
+ export { ad as enterPathToBytes32 } from './errors-CdzI_iYO.cjs';
3
3
 
4
4
  /**
5
5
  * Webhook signature verification (spec §6.2) — server-side only.
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { a2 as PlaymosError, W as WebhookEvent } from './errors-WcDNfb4q.js';
2
- export { ad as enterPathToBytes32 } from './errors-WcDNfb4q.js';
1
+ import { a2 as PlaymosError, W as WebhookEvent } from './errors-CdzI_iYO.js';
2
+ export { ad as enterPathToBytes32 } from './errors-CdzI_iYO.js';
3
3
 
4
4
  /**
5
5
  * Webhook signature verification (spec §6.2) — server-side only.
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { PlaymosError, ApiError, toBytes32 } from './chunk-TZFGZNXV.js';
2
- export { toBytes32 as enterPathToBytes32 } from './chunk-TZFGZNXV.js';
1
+ import { PlaymosError, ApiError, toBytes32 } from './chunk-U6BPSEKC.js';
2
+ export { toBytes32 as enterPathToBytes32 } from './chunk-U6BPSEKC.js';
3
3
  import { timingSafeEqual, createHmac } from 'crypto';
4
4
  import { encodeFunctionData, decodeFunctionResult } from 'viem';
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playmos/sdk",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "description": "Playmos SDK — stablecoin payments for games on Base. IAP and skill contests are flat 1%. USD in, USDC on-chain, no crypto UX for players.",
5
5
  "license": "MIT",
6
6
  "private": false,