@playmos/sdk 0.3.1 → 0.3.2
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/README.md +33 -20
- package/dist/index.cjs +414 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +379 -129
- package/dist/index.d.ts +379 -129
- package/dist/index.js +410 -44
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,333 @@ interface ResolvedEnv {
|
|
|
23
23
|
isTest: boolean;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* settlement.ts — the x402-ready settlement CORE contract (Phase 0).
|
|
28
|
+
*
|
|
29
|
+
* Two shared shapes every value-movement primitive (`transfer`, `escrow`,
|
|
30
|
+
* `marketplace`) AND the future x402 adapter build on. The whole point of
|
|
31
|
+
* naming them now is that x402 later becomes a thin HTTP-402 adapter with zero
|
|
32
|
+
* rework — see `docs/design/transfer-escrow-marketplace-spec.md` §"Architecture:
|
|
33
|
+
* x402-ready by design".
|
|
34
|
+
*
|
|
35
|
+
* PaymentRequirement — WHAT must be paid. A plain, JSON-safe object. A direct
|
|
36
|
+
* SDK call creates one and satisfies it immediately; an x402 "402 Payment
|
|
37
|
+
* Required" challenge is literally this object serialized onto the wire. So
|
|
38
|
+
* it is designed to round-trip to/from an HTTP 402 body with zero loss —
|
|
39
|
+
* `parsePaymentRequirement(serializePaymentRequirement(req))` is `req`.
|
|
40
|
+
*
|
|
41
|
+
* Authorization — HOW a settlement is authorized. A discriminated union so the
|
|
42
|
+
* settlement core never bakes in "direct SDK signature": today a
|
|
43
|
+
* `wallet-signature` (implemented), tomorrow an `x402-payload` (declared,
|
|
44
|
+
* not settled yet). This union is the seam that keeps x402 out of the core.
|
|
45
|
+
*
|
|
46
|
+
* Nothing here touches the network or the chain — these are the shared data
|
|
47
|
+
* shapes the SDK produces and the service's protocol-agnostic settlement core
|
|
48
|
+
* consumes.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/** The only settlement asset in V1. Named so an x402 challenge carries it verbatim. */
|
|
52
|
+
type SettlementAsset = "USDC";
|
|
53
|
+
/**
|
|
54
|
+
* The shared payment contract — WHAT must be paid, independent of HOW it was
|
|
55
|
+
* requested (direct SDK call today, x402 challenge tomorrow).
|
|
56
|
+
*
|
|
57
|
+
* Every field is a JSON primitive so the object is byte-stable across an HTTP
|
|
58
|
+
* 402 body: mint it once, and both the direct path and the x402 path settle the
|
|
59
|
+
* exact same requirement, idempotent on `id`.
|
|
60
|
+
*/
|
|
61
|
+
interface PaymentRequirement {
|
|
62
|
+
/** The anchor id (`preq_<ulid>`). Settlement idempotency key + x402 challenge id. */
|
|
63
|
+
id: string;
|
|
64
|
+
/** The recipient wallet (the payee). Checksummed or lowercase 0x-address. */
|
|
65
|
+
payTo: `0x${string}`;
|
|
66
|
+
/** USD decimal string ("5.00") — same money convention as `pay()`/`enterRound()`. */
|
|
67
|
+
amount: string;
|
|
68
|
+
/** Only USDC in V1. */
|
|
69
|
+
asset: SettlementAsset;
|
|
70
|
+
/** Which chain settles this requirement. */
|
|
71
|
+
network: Network;
|
|
72
|
+
/** Optional free-form terms/memo, echoed on the receipt and in the 402 body. */
|
|
73
|
+
terms?: string;
|
|
74
|
+
/** ISO-8601 expiry. A challenge/authorization presented after this is rejected. */
|
|
75
|
+
expiresAt: string;
|
|
76
|
+
}
|
|
77
|
+
interface CreatePaymentRequirementInput {
|
|
78
|
+
/** Recipient wallet. */
|
|
79
|
+
payTo: `0x${string}`;
|
|
80
|
+
/** USD decimal string ("5.00"). */
|
|
81
|
+
amount: string;
|
|
82
|
+
/** Settlement chain. */
|
|
83
|
+
network: Network;
|
|
84
|
+
/** Defaults to "USDC". */
|
|
85
|
+
asset?: SettlementAsset;
|
|
86
|
+
/** Optional terms/memo. */
|
|
87
|
+
terms?: string;
|
|
88
|
+
/** Absolute ISO expiry. Overrides `expiresInMs`. Defaults to now + 15 min. */
|
|
89
|
+
expiresAt?: string;
|
|
90
|
+
/** Relative TTL from now, in ms. Ignored if `expiresAt` is set. */
|
|
91
|
+
expiresInMs?: number;
|
|
92
|
+
/** Supply for a deterministic id (e.g. to reuse an upstream id); else a `preq_<ulid>` is minted. */
|
|
93
|
+
id?: string;
|
|
94
|
+
/** Injectable clock for deterministic tests. */
|
|
95
|
+
now?: () => Date;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Build a validated {@link PaymentRequirement}. This is the single producer the
|
|
99
|
+
* direct primitives (`transfer`/`escrow`/`marketplace`) and — later — the x402
|
|
100
|
+
* adapter both call, so every requirement on the wire is shaped identically.
|
|
101
|
+
* Pure: no network, no chain, no id collisions (monotonic ULID).
|
|
102
|
+
*/
|
|
103
|
+
declare function createPaymentRequirement(input: CreatePaymentRequirementInput): PaymentRequirement;
|
|
104
|
+
/**
|
|
105
|
+
* Serialize a requirement to a plain, JSON-safe object — the exact body an x402
|
|
106
|
+
* "402 Payment Required" response carries. Undefined optionals are omitted so
|
|
107
|
+
* the shape is stable across `JSON.stringify` → `JSON.parse` → re-parse.
|
|
108
|
+
*/
|
|
109
|
+
declare function serializePaymentRequirement(req: PaymentRequirement): Record<string, unknown>;
|
|
110
|
+
/**
|
|
111
|
+
* Parse + validate an untrusted object (an HTTP 402 body, a queue message, a
|
|
112
|
+
* direct call) back into a {@link PaymentRequirement}. This is the exact decoder
|
|
113
|
+
* the x402 adapter reuses — it must reject anything malformed with a typed error.
|
|
114
|
+
*/
|
|
115
|
+
declare function parsePaymentRequirement(input: unknown): PaymentRequirement;
|
|
116
|
+
/**
|
|
117
|
+
* A settlement authorized by a wallet — the ONLY variant implemented in Phase 0.
|
|
118
|
+
* Covers both signer models the primitives support:
|
|
119
|
+
* - server-held NPC/agent wallets (the service signs) and
|
|
120
|
+
* - player Base Accounts (the client signs) —
|
|
121
|
+
* carrying either the settlement `txHash` the client already broadcast, or a
|
|
122
|
+
* `signature` + `payload` (e.g. EIP-3009 / EIP-5792 batch params) the service
|
|
123
|
+
* submits. Phase 0 only READS `txHash`; the signed-submit path lands in Phase 1.
|
|
124
|
+
*/
|
|
125
|
+
interface WalletSignatureAuthorization {
|
|
126
|
+
kind: "wallet-signature";
|
|
127
|
+
/** The wallet that authorized the move (payer / signer). */
|
|
128
|
+
from: `0x${string}`;
|
|
129
|
+
/** A settlement tx the client already broadcast (client-signed path). */
|
|
130
|
+
txHash?: `0x${string}`;
|
|
131
|
+
/** An off-chain signature the service submits on the payer's behalf. */
|
|
132
|
+
signature?: `0x${string}`;
|
|
133
|
+
/** Opaque protocol-specific authorization data (EIP-5792 calls, EIP-3009, …). */
|
|
134
|
+
payload?: Record<string, unknown>;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* A settlement authorized by an x402 payment payload (the `X-PAYMENT` header).
|
|
138
|
+
* DECLARED for the Phase 4 HTTP-402 adapter so the core's type surface is final
|
|
139
|
+
* now — but NOT settled in Phase 0: `settle()` throws a clear "not implemented
|
|
140
|
+
* yet" for this variant. This is the seam that keeps x402 out of the core.
|
|
141
|
+
*/
|
|
142
|
+
interface X402PayloadAuthorization {
|
|
143
|
+
kind: "x402-payload";
|
|
144
|
+
/** The raw, opaque x402 payment payload decoded from the request. */
|
|
145
|
+
payload: Record<string, unknown>;
|
|
146
|
+
}
|
|
147
|
+
/** How a settlement is authorized — protocol-agnostic by construction. */
|
|
148
|
+
type Authorization = WalletSignatureAuthorization | X402PayloadAuthorization;
|
|
149
|
+
/** Narrow to the implemented wallet-signature variant. */
|
|
150
|
+
declare function isWalletSignatureAuthorization(auth: Authorization): auth is WalletSignatureAuthorization;
|
|
151
|
+
/** Narrow to the declared-but-unimplemented x402 variant. */
|
|
152
|
+
declare function isX402PayloadAuthorization(auth: Authorization): auth is X402PayloadAuthorization;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* x402 helpers — Phase 4 P3 (#153).
|
|
156
|
+
*
|
|
157
|
+
* Pure builders for studios that mint their own HTTP 402 responses on Playmos
|
|
158
|
+
* rails, plus the wire-shape types the SDK client uses for
|
|
159
|
+
* `playmos.x402.challenge` / `fulfill` / `pay`.
|
|
160
|
+
*
|
|
161
|
+
* V1 routes (ADR): `POST /v1/x402/challenges` + `POST /v1/x402/settle` only.
|
|
162
|
+
* Resource-style URLs are **not** in V1 — `pay({ payTo, amount })` wraps those
|
|
163
|
+
* two calls. See `docs/design/PHASE-4-X402-ADR.md`.
|
|
164
|
+
*
|
|
165
|
+
* Honesty: V1 is an **x402-shaped** API (headers + PaymentRequirement +
|
|
166
|
+
* Playmos payload rules). Stock TransferWithAuthorization settle is wired
|
|
167
|
+
* behind #161 Option B (CREATE2 splitter); claim language stays "x402-shaped"
|
|
168
|
+
* until Gate X X3b is green with a BaseScan hash.
|
|
169
|
+
*/
|
|
170
|
+
|
|
171
|
+
/** x402-shaped PAYMENT-REQUIRED object (wire matrix §4) with Playmos extensions. */
|
|
172
|
+
interface X402PaymentRequired {
|
|
173
|
+
scheme: "exact";
|
|
174
|
+
/** CAIP-2 network id (`eip155:84532` for Base Sepolia). */
|
|
175
|
+
network: string;
|
|
176
|
+
/** Atomic USDC (6 dp) as a decimal string. */
|
|
177
|
+
maxAmountRequired: string;
|
|
178
|
+
asset: string;
|
|
179
|
+
payTo: `0x${string}`;
|
|
180
|
+
/**
|
|
181
|
+
* Stock-client EIP-712 domain + Playmos seller hint (#161).
|
|
182
|
+
* `name` / `version` are read from the live USDC token — never hardcoded.
|
|
183
|
+
*/
|
|
184
|
+
extra?: {
|
|
185
|
+
name: string;
|
|
186
|
+
version: string;
|
|
187
|
+
playmosSeller?: string;
|
|
188
|
+
playmosRequirementId?: string;
|
|
189
|
+
};
|
|
190
|
+
/** Required Playmos extension — settlement idempotency anchor. */
|
|
191
|
+
playmosRequirementId: string;
|
|
192
|
+
/** USD decimal string (Playmos money convention). */
|
|
193
|
+
amount: string;
|
|
194
|
+
playmosNetwork: Network;
|
|
195
|
+
expiresAt: string;
|
|
196
|
+
terms?: string | null;
|
|
197
|
+
feeBps?: number | null;
|
|
198
|
+
feeSink?: string | null;
|
|
199
|
+
/** Economic seller when `payTo` is a CREATE2 clone address (#161). */
|
|
200
|
+
playmosSeller?: string;
|
|
201
|
+
}
|
|
202
|
+
/** Input to `playmos.x402.challenge(...)` — mints a server-authoritative requirement. */
|
|
203
|
+
interface X402ChallengeInput {
|
|
204
|
+
/** Recipient wallet. */
|
|
205
|
+
payTo: `0x${string}`;
|
|
206
|
+
/** USD decimal string ("0.50"). */
|
|
207
|
+
amount: string;
|
|
208
|
+
/**
|
|
209
|
+
* Money intent. V1 service supports `"transfer"` only today; `marketplace.buy`
|
|
210
|
+
* is ADR D1 but lands after listing plumbing.
|
|
211
|
+
*/
|
|
212
|
+
intent?: "transfer" | "marketplace.buy";
|
|
213
|
+
/** Per-call fee bps (same model as `transfer()`). Default 0. */
|
|
214
|
+
feeBps?: number;
|
|
215
|
+
/** Fee destination when feeBps > 0. */
|
|
216
|
+
feeSink?: `0x${string}`;
|
|
217
|
+
/** Optional terms/memo. */
|
|
218
|
+
terms?: string;
|
|
219
|
+
/** Relative TTL ms (service default 15 min). */
|
|
220
|
+
expiresInMs?: number;
|
|
221
|
+
/** Supply a deterministic requirement id; else the service mints `preq_…`. */
|
|
222
|
+
id?: string;
|
|
223
|
+
}
|
|
224
|
+
/** What `playmos.x402.challenge` resolves to (402 body, already success). */
|
|
225
|
+
interface X402ChallengeResult {
|
|
226
|
+
requirement: PaymentRequirement;
|
|
227
|
+
paymentRequired: X402PaymentRequired;
|
|
228
|
+
feeBps: number;
|
|
229
|
+
feeSink: string | null;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Payload modes the Playmos settle path accepts.
|
|
233
|
+
* Stock modes require PLAYMOS_X402_SPLITTER_FACTORY_ADDRESS (#161 Option B).
|
|
234
|
+
* Claim "interop" only after Gate X X3b + BaseScan hash.
|
|
235
|
+
*/
|
|
236
|
+
type X402PayloadMode = "server-signer" | "eip3009-auth" | "tx-hash" | "transfer-with-authorization" | "x402-exact-stock";
|
|
237
|
+
/** Authorization body for `playmos.x402.fulfill` / settle. */
|
|
238
|
+
interface X402FulfillAuthorization {
|
|
239
|
+
mode?: X402PayloadMode;
|
|
240
|
+
/** Payer address. Optional for server-signer (service fills sandbox signer). */
|
|
241
|
+
from?: `0x${string}`;
|
|
242
|
+
/** Optional; if set must match the server-minted challenge (fee authority). */
|
|
243
|
+
feeBps?: number;
|
|
244
|
+
feeSink?: `0x${string}`;
|
|
245
|
+
/** EIP-3009 ReceiveWithAuthorization fields (mode eip3009-auth). */
|
|
246
|
+
authorization?: Record<string, unknown>;
|
|
247
|
+
/** Prior broadcast tx (mode tx-hash). */
|
|
248
|
+
txHash?: `0x${string}`;
|
|
249
|
+
/** Extra opaque fields forwarded into the payload. */
|
|
250
|
+
[key: string]: unknown;
|
|
251
|
+
}
|
|
252
|
+
/** Result of `playmos.x402.fulfill` / `pay`. */
|
|
253
|
+
interface X402SettleResult {
|
|
254
|
+
requirementId: string;
|
|
255
|
+
status: "settled" | "pending" | "failed" | string;
|
|
256
|
+
txHash?: `0x${string}` | null;
|
|
257
|
+
idempotentReplay: boolean;
|
|
258
|
+
verifiedVia?: string;
|
|
259
|
+
feeBps: number;
|
|
260
|
+
fee: string;
|
|
261
|
+
net: string;
|
|
262
|
+
requirement: PaymentRequirement;
|
|
263
|
+
success: boolean;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* One-shot helper input — sequences challenge + settle.
|
|
267
|
+
*
|
|
268
|
+
* **Not** a resource URL. ADR locks V1 senior DX as:
|
|
269
|
+
* `playmos.x402.pay({ payTo, amount, … })`
|
|
270
|
+
* wrapping `POST /v1/x402/challenges` then `POST /v1/x402/settle`.
|
|
271
|
+
* Resource-style `pay({ url })` is deferred V1.1+.
|
|
272
|
+
*/
|
|
273
|
+
interface X402PayInput extends X402ChallengeInput {
|
|
274
|
+
/**
|
|
275
|
+
* Settle mode. Defaults to `"server-signer"` (sandbox convenience).
|
|
276
|
+
* Required on the wire; the SDK always sends an explicit mode (fail-closed).
|
|
277
|
+
*/
|
|
278
|
+
mode?: X402PayloadMode;
|
|
279
|
+
/** Payer when not using server-signer default. */
|
|
280
|
+
from?: `0x${string}`;
|
|
281
|
+
/** EIP-3009 auth blob when mode is eip3009-auth. */
|
|
282
|
+
authorization?: Record<string, unknown>;
|
|
283
|
+
/** Prior tx when mode is tx-hash. */
|
|
284
|
+
txHash?: `0x${string}`;
|
|
285
|
+
}
|
|
286
|
+
/** Map Playmos network enum → CAIP-2 (wire matrix). */
|
|
287
|
+
declare function networkToCaip2(network: Network): string;
|
|
288
|
+
/**
|
|
289
|
+
* Playmos {@link PaymentRequirement} → x402-shaped PAYMENT-REQUIRED object.
|
|
290
|
+
* Mirrors `service/src/routes/x402.ts` `toX402PaymentRequired` so studio-minted
|
|
291
|
+
* challenges match the official service shape.
|
|
292
|
+
*/
|
|
293
|
+
declare function toX402PaymentRequired(req: PaymentRequirement, extras?: {
|
|
294
|
+
feeBps?: number;
|
|
295
|
+
feeSink?: string | null;
|
|
296
|
+
}): X402PaymentRequired;
|
|
297
|
+
/** UTF-8 JSON → base64 (browser + Node). */
|
|
298
|
+
declare function encodePaymentHeader(obj: unknown): string;
|
|
299
|
+
/** Base64 JSON header → object. Throws ConfigError on bad input. */
|
|
300
|
+
declare function decodePaymentHeader(header: string): unknown;
|
|
301
|
+
/**
|
|
302
|
+
* Studio server helper: build a 402 Payment Required response for a Playmos
|
|
303
|
+
* {@link PaymentRequirement}. Use this when your API challenges buyers and
|
|
304
|
+
* Playmos settles via `POST /v1/x402/settle` (or `playmos.x402.fulfill`).
|
|
305
|
+
*
|
|
306
|
+
* Does **not** hit the network — pure. For official mint + fee authority, prefer
|
|
307
|
+
* `playmos.x402.challenge` (server-persisted challenge store).
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```ts
|
|
311
|
+
* import { createPaymentRequirement, createX402Challenge } from "@playmos/sdk";
|
|
312
|
+
*
|
|
313
|
+
* const requirement = createPaymentRequirement({
|
|
314
|
+
* payTo: "0x…", amount: "0.50", network: "base-sepolia",
|
|
315
|
+
* });
|
|
316
|
+
* const challenge = createX402Challenge(requirement, { feeBps: 0 });
|
|
317
|
+
* // res.status(402).set(challenge.headers).json(challenge.body)
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
declare function createX402Challenge(requirement: PaymentRequirement, extras?: {
|
|
321
|
+
feeBps?: number;
|
|
322
|
+
feeSink?: string | null;
|
|
323
|
+
}): {
|
|
324
|
+
status: 402;
|
|
325
|
+
headers: {
|
|
326
|
+
"PAYMENT-REQUIRED": string;
|
|
327
|
+
"Content-Type": string;
|
|
328
|
+
};
|
|
329
|
+
body: {
|
|
330
|
+
error: {
|
|
331
|
+
code: "payment_required";
|
|
332
|
+
message: string;
|
|
333
|
+
};
|
|
334
|
+
requirement: PaymentRequirement;
|
|
335
|
+
paymentRequired: X402PaymentRequired;
|
|
336
|
+
feeBps: number;
|
|
337
|
+
feeSink: string | null;
|
|
338
|
+
};
|
|
339
|
+
paymentRequired: X402PaymentRequired;
|
|
340
|
+
};
|
|
341
|
+
/** Client-side validation shared by challenge / pay (throws before network). */
|
|
342
|
+
declare function validateX402ChallengeInput(input: X402ChallengeInput): {
|
|
343
|
+
payTo: `0x${string}`;
|
|
344
|
+
amount: string;
|
|
345
|
+
intent: "transfer" | "marketplace.buy";
|
|
346
|
+
feeBps: number;
|
|
347
|
+
feeSink?: `0x${string}`;
|
|
348
|
+
terms?: string;
|
|
349
|
+
expiresInMs?: number;
|
|
350
|
+
id?: string;
|
|
351
|
+
};
|
|
352
|
+
|
|
26
353
|
/**
|
|
27
354
|
* The Playmos client — `new Playmos({ apiKey })` → `pay()`, `enterRound()`,
|
|
28
355
|
* `verify()`, `webhooks`, `payouts`, `agents`.
|
|
@@ -61,6 +388,46 @@ declare class Playmos {
|
|
|
61
388
|
url: string;
|
|
62
389
|
}>;
|
|
63
390
|
};
|
|
391
|
+
/**
|
|
392
|
+
* `x402` — Phase 4 HTTP 402 / x402-shaped adapter (#153).
|
|
393
|
+
*
|
|
394
|
+
* V1 surface (ADR):
|
|
395
|
+
* - `challenge` → `POST /v1/x402/challenges` (returns 402; treated as success)
|
|
396
|
+
* - `fulfill` → `POST /v1/x402/settle`
|
|
397
|
+
* - `pay` → challenge then fulfill (senior DX ≤15 lines)
|
|
398
|
+
*
|
|
399
|
+
* **Not** resource URLs (`pay({ url })` is V1.1+). **Not** stock third-party
|
|
400
|
+
* x402 client interop (X3b deferred until #161). Requires `sk_test_` +
|
|
401
|
+
* Base Sepolia; flag `PLAYMOS_X402_ENABLED` on the service.
|
|
402
|
+
*
|
|
403
|
+
* ```ts
|
|
404
|
+
* const playmos = new Playmos({ apiKey: process.env.PLAYMOS_SK!, network: "base-sepolia" });
|
|
405
|
+
* const result = await playmos.x402.pay({
|
|
406
|
+
* payTo: "0x…",
|
|
407
|
+
* amount: "0.50",
|
|
408
|
+
* feeBps: 0,
|
|
409
|
+
* });
|
|
410
|
+
* // result.txHash → BaseScan
|
|
411
|
+
* ```
|
|
412
|
+
*/
|
|
413
|
+
readonly x402: {
|
|
414
|
+
/**
|
|
415
|
+
* Mint a server-authoritative PaymentRequirement (HTTP 402).
|
|
416
|
+
* Fee terms are stored server-side — settle rejects payload disagreement.
|
|
417
|
+
*/
|
|
418
|
+
challenge: (input: X402ChallengeInput) => Promise<X402ChallengeResult>;
|
|
419
|
+
/**
|
|
420
|
+
* Settle a previously minted challenge with an `x402-payload` authorization.
|
|
421
|
+
* Defaults mode to `server-signer` when omitted (explicit on the wire — fail-closed
|
|
422
|
+
* materialize still requires mode; the route also defaults for this path).
|
|
423
|
+
*/
|
|
424
|
+
fulfill: (requirement: PaymentRequirement, authorization?: X402FulfillAuthorization | X402PayloadAuthorization) => Promise<X402SettleResult>;
|
|
425
|
+
/**
|
|
426
|
+
* Senior DX: mint challenge + settle in one call.
|
|
427
|
+
* Wraps challenges + settle only — **not** `pay({ url })` (ADR).
|
|
428
|
+
*/
|
|
429
|
+
pay: (input: X402PayInput) => Promise<X402SettleResult>;
|
|
430
|
+
};
|
|
64
431
|
/**
|
|
65
432
|
* Skill/contest **round lifecycle** (issue #13) — closes the enterRound loop.
|
|
66
433
|
*
|
|
@@ -185,6 +552,11 @@ declare class Playmos {
|
|
|
185
552
|
/** Fetch a listing + its on-chain-verified sale status. */
|
|
186
553
|
get: (listingId: string) => Promise<MarketplaceGetResult>;
|
|
187
554
|
};
|
|
555
|
+
/**
|
|
556
|
+
* Offline mock payments for this client instance — so `verify(id)` after
|
|
557
|
+
* `mock: true` pay/enterRound does not hit the live API (#204).
|
|
558
|
+
*/
|
|
559
|
+
private readonly mockPayments;
|
|
188
560
|
constructor(config: PlaymosConfig);
|
|
189
561
|
/** Connect the player's wallet and return their address. */
|
|
190
562
|
connect(): Promise<`0x${string}`>;
|
|
@@ -214,6 +586,7 @@ declare class Playmos {
|
|
|
214
586
|
identity?: string;
|
|
215
587
|
}>;
|
|
216
588
|
};
|
|
589
|
+
private rememberMock;
|
|
217
590
|
/** External-studio IAP (1%). Returns a real confirmed Payment with a txHash. */
|
|
218
591
|
pay(input: PayInput): Promise<Payment>;
|
|
219
592
|
/** Playmos-owned skill-game entry (10%, 60/30/10 prize pool). Closes #343. */
|
|
@@ -258,6 +631,11 @@ declare class Playmos {
|
|
|
258
631
|
transfer(input: TransferInput, opts?: TransferConfirmOptions): Promise<TransferResult>;
|
|
259
632
|
/** Verify a payment by the service's on-chain read (spec §6.1). Idempotent. */
|
|
260
633
|
verify(paymentId: string): Promise<VerifyResult>;
|
|
634
|
+
/**
|
|
635
|
+
* x402 V1 is Base Sepolia + test keys only (ADR D5). Fail closed before any
|
|
636
|
+
* network call so mainnet / live keys never silently hit the adapter.
|
|
637
|
+
*/
|
|
638
|
+
private assertX402Allowed;
|
|
261
639
|
/**
|
|
262
640
|
* Map a server-settled payment (from the `settle: "server"` response) into the
|
|
263
641
|
* SDK's `Payment` shape. The service already signed + confirmed on-chain, so we
|
|
@@ -415,132 +793,4 @@ declare function ulid(seedTime?: number): string;
|
|
|
415
793
|
/** `${prefix}_${ulid()}` — e.g. `pay_01J…`, `entry_01J…`, `idem_01J…`. */
|
|
416
794
|
declare function prefixedId(prefix: string): string;
|
|
417
795
|
|
|
418
|
-
|
|
419
|
-
* settlement.ts — the x402-ready settlement CORE contract (Phase 0).
|
|
420
|
-
*
|
|
421
|
-
* Two shared shapes every value-movement primitive (`transfer`, `escrow`,
|
|
422
|
-
* `marketplace`) AND the future x402 adapter build on. The whole point of
|
|
423
|
-
* naming them now is that x402 later becomes a thin HTTP-402 adapter with zero
|
|
424
|
-
* rework — see `docs/design/transfer-escrow-marketplace-spec.md` §"Architecture:
|
|
425
|
-
* x402-ready by design".
|
|
426
|
-
*
|
|
427
|
-
* PaymentRequirement — WHAT must be paid. A plain, JSON-safe object. A direct
|
|
428
|
-
* SDK call creates one and satisfies it immediately; an x402 "402 Payment
|
|
429
|
-
* Required" challenge is literally this object serialized onto the wire. So
|
|
430
|
-
* it is designed to round-trip to/from an HTTP 402 body with zero loss —
|
|
431
|
-
* `parsePaymentRequirement(serializePaymentRequirement(req))` is `req`.
|
|
432
|
-
*
|
|
433
|
-
* Authorization — HOW a settlement is authorized. A discriminated union so the
|
|
434
|
-
* settlement core never bakes in "direct SDK signature": today a
|
|
435
|
-
* `wallet-signature` (implemented), tomorrow an `x402-payload` (declared,
|
|
436
|
-
* not settled yet). This union is the seam that keeps x402 out of the core.
|
|
437
|
-
*
|
|
438
|
-
* Nothing here touches the network or the chain — these are the shared data
|
|
439
|
-
* shapes the SDK produces and the service's protocol-agnostic settlement core
|
|
440
|
-
* consumes.
|
|
441
|
-
*/
|
|
442
|
-
|
|
443
|
-
/** The only settlement asset in V1. Named so an x402 challenge carries it verbatim. */
|
|
444
|
-
type SettlementAsset = "USDC";
|
|
445
|
-
/**
|
|
446
|
-
* The shared payment contract — WHAT must be paid, independent of HOW it was
|
|
447
|
-
* requested (direct SDK call today, x402 challenge tomorrow).
|
|
448
|
-
*
|
|
449
|
-
* Every field is a JSON primitive so the object is byte-stable across an HTTP
|
|
450
|
-
* 402 body: mint it once, and both the direct path and the x402 path settle the
|
|
451
|
-
* exact same requirement, idempotent on `id`.
|
|
452
|
-
*/
|
|
453
|
-
interface PaymentRequirement {
|
|
454
|
-
/** The anchor id (`preq_<ulid>`). Settlement idempotency key + x402 challenge id. */
|
|
455
|
-
id: string;
|
|
456
|
-
/** The recipient wallet (the payee). Checksummed or lowercase 0x-address. */
|
|
457
|
-
payTo: `0x${string}`;
|
|
458
|
-
/** USD decimal string ("5.00") — same money convention as `pay()`/`enterRound()`. */
|
|
459
|
-
amount: string;
|
|
460
|
-
/** Only USDC in V1. */
|
|
461
|
-
asset: SettlementAsset;
|
|
462
|
-
/** Which chain settles this requirement. */
|
|
463
|
-
network: Network;
|
|
464
|
-
/** Optional free-form terms/memo, echoed on the receipt and in the 402 body. */
|
|
465
|
-
terms?: string;
|
|
466
|
-
/** ISO-8601 expiry. A challenge/authorization presented after this is rejected. */
|
|
467
|
-
expiresAt: string;
|
|
468
|
-
}
|
|
469
|
-
interface CreatePaymentRequirementInput {
|
|
470
|
-
/** Recipient wallet. */
|
|
471
|
-
payTo: `0x${string}`;
|
|
472
|
-
/** USD decimal string ("5.00"). */
|
|
473
|
-
amount: string;
|
|
474
|
-
/** Settlement chain. */
|
|
475
|
-
network: Network;
|
|
476
|
-
/** Defaults to "USDC". */
|
|
477
|
-
asset?: SettlementAsset;
|
|
478
|
-
/** Optional terms/memo. */
|
|
479
|
-
terms?: string;
|
|
480
|
-
/** Absolute ISO expiry. Overrides `expiresInMs`. Defaults to now + 15 min. */
|
|
481
|
-
expiresAt?: string;
|
|
482
|
-
/** Relative TTL from now, in ms. Ignored if `expiresAt` is set. */
|
|
483
|
-
expiresInMs?: number;
|
|
484
|
-
/** Supply for a deterministic id (e.g. to reuse an upstream id); else a `preq_<ulid>` is minted. */
|
|
485
|
-
id?: string;
|
|
486
|
-
/** Injectable clock for deterministic tests. */
|
|
487
|
-
now?: () => Date;
|
|
488
|
-
}
|
|
489
|
-
/**
|
|
490
|
-
* Build a validated {@link PaymentRequirement}. This is the single producer the
|
|
491
|
-
* direct primitives (`transfer`/`escrow`/`marketplace`) and — later — the x402
|
|
492
|
-
* adapter both call, so every requirement on the wire is shaped identically.
|
|
493
|
-
* Pure: no network, no chain, no id collisions (monotonic ULID).
|
|
494
|
-
*/
|
|
495
|
-
declare function createPaymentRequirement(input: CreatePaymentRequirementInput): PaymentRequirement;
|
|
496
|
-
/**
|
|
497
|
-
* Serialize a requirement to a plain, JSON-safe object — the exact body an x402
|
|
498
|
-
* "402 Payment Required" response carries. Undefined optionals are omitted so
|
|
499
|
-
* the shape is stable across `JSON.stringify` → `JSON.parse` → re-parse.
|
|
500
|
-
*/
|
|
501
|
-
declare function serializePaymentRequirement(req: PaymentRequirement): Record<string, unknown>;
|
|
502
|
-
/**
|
|
503
|
-
* Parse + validate an untrusted object (an HTTP 402 body, a queue message, a
|
|
504
|
-
* direct call) back into a {@link PaymentRequirement}. This is the exact decoder
|
|
505
|
-
* the x402 adapter reuses — it must reject anything malformed with a typed error.
|
|
506
|
-
*/
|
|
507
|
-
declare function parsePaymentRequirement(input: unknown): PaymentRequirement;
|
|
508
|
-
/**
|
|
509
|
-
* A settlement authorized by a wallet — the ONLY variant implemented in Phase 0.
|
|
510
|
-
* Covers both signer models the primitives support:
|
|
511
|
-
* - server-held NPC/agent wallets (the service signs) and
|
|
512
|
-
* - player Base Accounts (the client signs) —
|
|
513
|
-
* carrying either the settlement `txHash` the client already broadcast, or a
|
|
514
|
-
* `signature` + `payload` (e.g. EIP-3009 / EIP-5792 batch params) the service
|
|
515
|
-
* submits. Phase 0 only READS `txHash`; the signed-submit path lands in Phase 1.
|
|
516
|
-
*/
|
|
517
|
-
interface WalletSignatureAuthorization {
|
|
518
|
-
kind: "wallet-signature";
|
|
519
|
-
/** The wallet that authorized the move (payer / signer). */
|
|
520
|
-
from: `0x${string}`;
|
|
521
|
-
/** A settlement tx the client already broadcast (client-signed path). */
|
|
522
|
-
txHash?: `0x${string}`;
|
|
523
|
-
/** An off-chain signature the service submits on the payer's behalf. */
|
|
524
|
-
signature?: `0x${string}`;
|
|
525
|
-
/** Opaque protocol-specific authorization data (EIP-5792 calls, EIP-3009, …). */
|
|
526
|
-
payload?: Record<string, unknown>;
|
|
527
|
-
}
|
|
528
|
-
/**
|
|
529
|
-
* A settlement authorized by an x402 payment payload (the `X-PAYMENT` header).
|
|
530
|
-
* DECLARED for the Phase 4 HTTP-402 adapter so the core's type surface is final
|
|
531
|
-
* now — but NOT settled in Phase 0: `settle()` throws a clear "not implemented
|
|
532
|
-
* yet" for this variant. This is the seam that keeps x402 out of the core.
|
|
533
|
-
*/
|
|
534
|
-
interface X402PayloadAuthorization {
|
|
535
|
-
kind: "x402-payload";
|
|
536
|
-
/** The raw, opaque x402 payment payload decoded from the request. */
|
|
537
|
-
payload: Record<string, unknown>;
|
|
538
|
-
}
|
|
539
|
-
/** How a settlement is authorized — protocol-agnostic by construction. */
|
|
540
|
-
type Authorization = WalletSignatureAuthorization | X402PayloadAuthorization;
|
|
541
|
-
/** Narrow to the implemented wallet-signature variant. */
|
|
542
|
-
declare function isWalletSignatureAuthorization(auth: Authorization): auth is WalletSignatureAuthorization;
|
|
543
|
-
/** Narrow to the declared-but-unimplemented x402 variant. */
|
|
544
|
-
declare function isX402PayloadAuthorization(auth: Authorization): auth is X402PayloadAuthorization;
|
|
545
|
-
|
|
546
|
-
export { AgentFundResult, AgentWallet, type Authorization, CHAIN_ID, type CreatePaymentRequirementInput, DEFAULT_API_BASE_URL, EnterRoundInput, EscrowHoldInput, EscrowHoldResult, EscrowResolveResult, Listing, MICRO_PER_USDC, MarketplaceGetResult, MarketplaceListInput, MarketplaceSaleResult, Network, PayInput, Payment, type PaymentRequirement, PayoutError, type PayoutRule as PayoutRuleCompute, Playmos, PlaymosConfig, PrizeBalance, RoundOpenInput, RoundSettleInput, RoundState, SettleRoundResult, type SettlementAsset, TransferConfirmOptions, TransferInput, TransferReconcile, TransferResult, USDC_ADDRESS, USDC_DECIMALS, VerifyResult, WaitOptions, type WalletSignatureAuthorization, WebhookEvent, WithdrawResult, type X402PayloadAuthorization, computeIapSplit, computePayout, computePoolSplit, createPaymentRequirement, formatMicroToUsd, isWalletSignatureAuthorization, isX402PayloadAuthorization, parsePaymentRequirement, parseUsdToMicro, prefixedId, previewEscrowFee, previewIapSplit, previewMarketplaceSplit, previewPoolSplit, previewTransferSplit, serializePaymentRequirement, ulid };
|
|
796
|
+
export { AgentFundResult, AgentWallet, type Authorization, CHAIN_ID, type CreatePaymentRequirementInput, DEFAULT_API_BASE_URL, EnterRoundInput, EscrowHoldInput, EscrowHoldResult, EscrowResolveResult, Listing, MICRO_PER_USDC, MarketplaceGetResult, MarketplaceListInput, MarketplaceSaleResult, Network, PayInput, Payment, type PaymentRequirement, PayoutError, type PayoutRule as PayoutRuleCompute, Playmos, PlaymosConfig, PrizeBalance, RoundOpenInput, RoundSettleInput, RoundState, SettleRoundResult, type SettlementAsset, 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, computeIapSplit, computePayout, computePoolSplit, createPaymentRequirement, createX402Challenge, decodePaymentHeader, encodePaymentHeader, formatMicroToUsd, isWalletSignatureAuthorization, isX402PayloadAuthorization, networkToCaip2, parsePaymentRequirement, parseUsdToMicro, prefixedId, previewEscrowFee, previewIapSplit, previewMarketplaceSplit, previewPoolSplit, previewTransferSplit, serializePaymentRequirement, toX402PaymentRequired, ulid, validateX402ChallengeInput };
|