@opendatalabs/vana-sdk 3.13.4-pr.186.afb5a4f → 3.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/contracts.config.cjs +1 -1
- package/dist/config/contracts.config.cjs.map +1 -1
- package/dist/config/contracts.config.js +1 -1
- package/dist/config/contracts.config.js.map +1 -1
- package/dist/direct/access-request-client.cjs +3 -1
- package/dist/direct/access-request-client.cjs.map +1 -1
- package/dist/direct/access-request-client.js +3 -1
- package/dist/direct/access-request-client.js.map +1 -1
- package/dist/direct/controller.cjs +72 -32
- package/dist/direct/controller.cjs.map +1 -1
- package/dist/direct/controller.d.ts +41 -3
- package/dist/direct/controller.js +77 -33
- package/dist/direct/controller.js.map +1 -1
- package/dist/direct/errors.cjs +11 -2
- package/dist/direct/errors.cjs.map +1 -1
- package/dist/direct/errors.d.ts +13 -0
- package/dist/direct/errors.js +9 -1
- package/dist/direct/errors.js.map +1 -1
- package/dist/direct/escrow-payment.cjs.map +1 -1
- package/dist/direct/escrow-payment.d.ts +2 -2
- package/dist/direct/escrow-payment.js.map +1 -1
- package/dist/direct/types.cjs.map +1 -1
- package/dist/direct/types.d.ts +33 -1
- package/dist/direct/types.js.map +1 -1
- package/dist/generated/addresses.cjs +6 -6
- package/dist/generated/addresses.cjs.map +1 -1
- package/dist/generated/addresses.d.ts +6 -6
- package/dist/generated/addresses.js +6 -6
- package/dist/generated/addresses.js.map +1 -1
- package/dist/index.browser.d.ts +2 -2
- package/dist/index.browser.js +7 -136
- package/dist/index.browser.js.map +2 -2
- package/dist/index.node.cjs +18 -151
- package/dist/index.node.cjs.map +3 -3
- package/dist/index.node.d.ts +2 -2
- package/dist/index.node.js +17 -146
- package/dist/index.node.js.map +3 -3
- package/dist/protocol/eip712.cjs +2 -28
- package/dist/protocol/eip712.cjs.map +1 -1
- package/dist/protocol/eip712.d.ts +0 -70
- package/dist/protocol/eip712.js +1 -24
- package/dist/protocol/eip712.js.map +1 -1
- package/dist/protocol/escrow.cjs +2 -118
- package/dist/protocol/escrow.cjs.map +1 -1
- package/dist/protocol/escrow.d.ts +2 -108
- package/dist/protocol/escrow.js +1 -116
- package/dist/protocol/escrow.js.map +1 -1
- package/dist/protocol/gateway.cjs.map +1 -1
- package/dist/protocol/gateway.d.ts +38 -8
- package/dist/protocol/gateway.js.map +1 -1
- package/dist/server.cjs +2 -0
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -16,7 +16,6 @@
|
|
|
16
16
|
* @category Protocol
|
|
17
17
|
* @module escrow
|
|
18
18
|
*/
|
|
19
|
-
export { buildWithdrawAuthorizationTypedData, withdrawAuthorizationDomain, WITHDRAW_AUTHORIZATION_TYPES, type WithdrawAuthorizationMessage, } from "./eip712.js";
|
|
20
19
|
import type { TypedDataDomain } from "viem";
|
|
21
20
|
/**
|
|
22
21
|
* EIP-712 typed-data types for a generic op payment.
|
|
@@ -125,16 +124,14 @@ export declare const NATIVE_ASSET_ADDRESS: "0x0000000000000000000000000000000000
|
|
|
125
124
|
* - `authorizedAmount` — sum of all in-flight payments authorized by
|
|
126
125
|
* `/v1/escrow/pay` (soft-lock). May include payments not yet settled
|
|
127
126
|
* on-chain.
|
|
128
|
-
* - `
|
|
129
|
-
*
|
|
130
|
-
* This is what the account can still authorize or withdraw.
|
|
127
|
+
* - `availableAmount` — `max(balance − authorizedAmount, 0)`. This is what
|
|
128
|
+
* the payer can authorize before the gateway rejects with 402.
|
|
131
129
|
*/
|
|
132
130
|
export interface EscrowBalanceEntry {
|
|
133
131
|
asset: string;
|
|
134
132
|
balance: string;
|
|
135
133
|
pendingAmount: string;
|
|
136
134
|
authorizedAmount: string;
|
|
137
|
-
withdrawingAmount: string;
|
|
138
135
|
availableAmount: string;
|
|
139
136
|
updatedAt: string | null;
|
|
140
137
|
}
|
|
@@ -214,85 +211,6 @@ export interface EscrowPayResult {
|
|
|
214
211
|
paymentNonce: string;
|
|
215
212
|
paidAt: string;
|
|
216
213
|
}
|
|
217
|
-
interface EscrowWithdrawalResponseBase {
|
|
218
|
-
account: `0x${string}`;
|
|
219
|
-
asset: `0x${string}`;
|
|
220
|
-
amount: string;
|
|
221
|
-
withdrawNonce: string;
|
|
222
|
-
deadline: string;
|
|
223
|
-
}
|
|
224
|
-
/** A persisted authorization whose transaction has not been broadcast yet. */
|
|
225
|
-
export interface EscrowWithdrawalSubmittedWithoutTransaction extends EscrowWithdrawalResponseBase {
|
|
226
|
-
success: true;
|
|
227
|
-
status: "submitted";
|
|
228
|
-
txHash: null;
|
|
229
|
-
message: string;
|
|
230
|
-
}
|
|
231
|
-
/** A withdrawal with a persisted transaction that is awaiting reconciliation. */
|
|
232
|
-
export interface EscrowWithdrawalSubmittedWithTransaction {
|
|
233
|
-
success: true;
|
|
234
|
-
status: "submitted";
|
|
235
|
-
txHash: `0x${string}`;
|
|
236
|
-
message: string;
|
|
237
|
-
account?: `0x${string}`;
|
|
238
|
-
asset?: `0x${string}`;
|
|
239
|
-
amount?: string;
|
|
240
|
-
withdrawNonce?: string;
|
|
241
|
-
deadline?: string;
|
|
242
|
-
blockNumber?: string;
|
|
243
|
-
}
|
|
244
|
-
/** A withdrawal that the gateway has accepted but not yet confirmed. */
|
|
245
|
-
export type EscrowWithdrawalSubmittedResult = EscrowWithdrawalSubmittedWithoutTransaction | EscrowWithdrawalSubmittedWithTransaction;
|
|
246
|
-
/** A withdrawal whose on-chain debit has reached the named lifecycle state. */
|
|
247
|
-
export interface EscrowWithdrawalSettledResult extends EscrowWithdrawalResponseBase {
|
|
248
|
-
success: true;
|
|
249
|
-
status: "confirmed" | "finalized";
|
|
250
|
-
txHash: `0x${string}`;
|
|
251
|
-
blockNumber: string | null;
|
|
252
|
-
}
|
|
253
|
-
/** Successful lifecycle responses from `POST /v1/escrow/withdraw`. */
|
|
254
|
-
export type EscrowWithdrawalResult = EscrowWithdrawalSubmittedResult | EscrowWithdrawalSettledResult;
|
|
255
|
-
/** Terminal or retryable withdrawal lifecycle state returned with a non-2xx status. */
|
|
256
|
-
export interface EscrowWithdrawalFailureResult extends EscrowWithdrawalResponseBase {
|
|
257
|
-
success: false;
|
|
258
|
-
status: "retryable" | "reorged" | "failed";
|
|
259
|
-
error: string;
|
|
260
|
-
txHash: `0x${string}` | null;
|
|
261
|
-
blockNumber?: string | null;
|
|
262
|
-
}
|
|
263
|
-
export type EscrowWithdrawalRejectionCode = "below_minimum" | "deadline_too_far" | "expired" | "insufficient_available" | "stale_nonce";
|
|
264
|
-
/** Definite pre-acceptance rejection. No durable withdrawal intent was created. */
|
|
265
|
-
export interface EscrowWithdrawalRejectedResult extends EscrowWithdrawalResponseBase {
|
|
266
|
-
success: false;
|
|
267
|
-
status: "rejected";
|
|
268
|
-
code: EscrowWithdrawalRejectionCode;
|
|
269
|
-
error: string;
|
|
270
|
-
balance?: string;
|
|
271
|
-
authorizedAmount?: string;
|
|
272
|
-
withdrawingAmount?: string;
|
|
273
|
-
availableAmount?: string;
|
|
274
|
-
requestedAmount?: string;
|
|
275
|
-
minimumAmount?: string;
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* A typed non-2xx gateway lifecycle response.
|
|
279
|
-
*
|
|
280
|
-
* `retryable` means resend the exact signed intent. `reorged` and `failed`
|
|
281
|
-
* require a newly signed authorization with a new nonce.
|
|
282
|
-
*/
|
|
283
|
-
export declare class EscrowWithdrawalLifecycleError extends Error {
|
|
284
|
-
readonly httpStatus: number;
|
|
285
|
-
readonly result: EscrowWithdrawalFailureResult;
|
|
286
|
-
readonly name = "EscrowWithdrawalLifecycleError";
|
|
287
|
-
constructor(httpStatus: number, result: EscrowWithdrawalFailureResult);
|
|
288
|
-
}
|
|
289
|
-
/** A typed non-2xx gateway rejection before a withdrawal intent is accepted. */
|
|
290
|
-
export declare class EscrowWithdrawalRejectionError extends Error {
|
|
291
|
-
readonly httpStatus: number;
|
|
292
|
-
readonly result: EscrowWithdrawalRejectedResult;
|
|
293
|
-
readonly name = "EscrowWithdrawalRejectionError";
|
|
294
|
-
constructor(httpStatus: number, result: EscrowWithdrawalRejectedResult);
|
|
295
|
-
}
|
|
296
214
|
/**
|
|
297
215
|
* Parameters for submitting a deposit tx hash to the gateway.
|
|
298
216
|
*
|
|
@@ -331,21 +249,6 @@ export interface PayForOpParams {
|
|
|
331
249
|
*/
|
|
332
250
|
accessRecord?: EscrowAccessRecord;
|
|
333
251
|
}
|
|
334
|
-
/**
|
|
335
|
-
* Parameters for `POST /v1/escrow/withdraw`.
|
|
336
|
-
*
|
|
337
|
-
* `withdrawNonce` and `deadline` are caller-supplied decimal uint256 strings.
|
|
338
|
-
* The SDK intentionally does not generate a nonce: retrying safely requires a
|
|
339
|
-
* durable caller-owned nonce source and the exact same signed payload.
|
|
340
|
-
*/
|
|
341
|
-
export interface WithdrawFromEscrowParams {
|
|
342
|
-
account: `0x${string}`;
|
|
343
|
-
asset: `0x${string}`;
|
|
344
|
-
amount: string;
|
|
345
|
-
withdrawNonce: string;
|
|
346
|
-
deadline: string;
|
|
347
|
-
signature: `0x${string}`;
|
|
348
|
-
}
|
|
349
252
|
/** Wire shape of a receipt whose server signature the gateway verifies. */
|
|
350
253
|
export interface EscrowAccessRecord {
|
|
351
254
|
dataPointId: `0x${string}`;
|
|
@@ -398,16 +301,7 @@ export interface EscrowGatewayClient {
|
|
|
398
301
|
* records the payment. Returns 402 if the payer has insufficient balance.
|
|
399
302
|
*/
|
|
400
303
|
payForOp(params: PayForOpParams): Promise<EscrowPayResult>;
|
|
401
|
-
/**
|
|
402
|
-
* Submit or reconcile a signed withdrawal authorization.
|
|
403
|
-
*
|
|
404
|
-
* Retry a `submitted` result with the exact same parameters. Do not replace
|
|
405
|
-
* `withdrawNonce`, `deadline`, or signature unless starting a new intent.
|
|
406
|
-
*/
|
|
407
|
-
withdraw(params: WithdrawFromEscrowParams): Promise<EscrowWithdrawalResult>;
|
|
408
304
|
}
|
|
409
|
-
/** The only gateway capability required by direct data-access payment flows. */
|
|
410
|
-
export type EscrowPaymentClient = Pick<EscrowGatewayClient, "payForOp">;
|
|
411
305
|
/**
|
|
412
306
|
* Creates a client for the gateway escrow endpoints.
|
|
413
307
|
*
|
package/dist/protocol/escrow.js
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
buildWithdrawAuthorizationTypedData,
|
|
3
|
-
withdrawAuthorizationDomain,
|
|
4
|
-
WITHDRAW_AUTHORIZATION_TYPES
|
|
5
|
-
} from "./eip712.js";
|
|
6
|
-
import { isHex } from "viem";
|
|
7
1
|
const GENERIC_PAYMENT_TYPES = {
|
|
8
2
|
GenericPayment: [
|
|
9
3
|
{ name: "payerAddress", type: "address" },
|
|
@@ -43,26 +37,6 @@ const ESCROW_DEPOSIT_ABI = [
|
|
|
43
37
|
}
|
|
44
38
|
];
|
|
45
39
|
const NATIVE_ASSET_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
46
|
-
class EscrowWithdrawalLifecycleError extends Error {
|
|
47
|
-
constructor(httpStatus, result) {
|
|
48
|
-
super(result.error);
|
|
49
|
-
this.httpStatus = httpStatus;
|
|
50
|
-
this.result = result;
|
|
51
|
-
}
|
|
52
|
-
httpStatus;
|
|
53
|
-
result;
|
|
54
|
-
name = "EscrowWithdrawalLifecycleError";
|
|
55
|
-
}
|
|
56
|
-
class EscrowWithdrawalRejectionError extends Error {
|
|
57
|
-
constructor(httpStatus, result) {
|
|
58
|
-
super(result.error);
|
|
59
|
-
this.httpStatus = httpStatus;
|
|
60
|
-
this.result = result;
|
|
61
|
-
}
|
|
62
|
-
httpStatus;
|
|
63
|
-
result;
|
|
64
|
-
name = "EscrowWithdrawalRejectionError";
|
|
65
|
-
}
|
|
66
40
|
function createEscrowGatewayClient(baseUrl) {
|
|
67
41
|
const base = baseUrl.replace(/\/+$/, "");
|
|
68
42
|
async function throwOnError(res, context) {
|
|
@@ -78,27 +52,6 @@ function createEscrowGatewayClient(baseUrl) {
|
|
|
78
52
|
);
|
|
79
53
|
}
|
|
80
54
|
}
|
|
81
|
-
async function throwOnWithdrawError(res) {
|
|
82
|
-
if (res.ok) return;
|
|
83
|
-
let body;
|
|
84
|
-
try {
|
|
85
|
-
body = await res.json();
|
|
86
|
-
} catch {
|
|
87
|
-
throw new Error(
|
|
88
|
-
`Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}`
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
if (isEscrowWithdrawalFailureResult(body)) {
|
|
92
|
-
throw new EscrowWithdrawalLifecycleError(res.status, body);
|
|
93
|
-
}
|
|
94
|
-
if (isEscrowWithdrawalRejectedResult(body)) {
|
|
95
|
-
throw new EscrowWithdrawalRejectionError(res.status, body);
|
|
96
|
-
}
|
|
97
|
-
const error = getGatewayErrorMessage(body);
|
|
98
|
-
throw new Error(
|
|
99
|
-
`Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}${error ? `: ${error}` : ""}`
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
55
|
return {
|
|
103
56
|
async submitDeposit({ txHash }) {
|
|
104
57
|
const res = await fetch(`${base}/v1/escrow/deposit`, {
|
|
@@ -154,82 +107,14 @@ function createEscrowGatewayClient(baseUrl) {
|
|
|
154
107
|
});
|
|
155
108
|
await throwOnError(res, "POST /v1/escrow/pay");
|
|
156
109
|
return res.json();
|
|
157
|
-
},
|
|
158
|
-
async withdraw({
|
|
159
|
-
account,
|
|
160
|
-
asset,
|
|
161
|
-
amount,
|
|
162
|
-
withdrawNonce,
|
|
163
|
-
deadline,
|
|
164
|
-
signature
|
|
165
|
-
}) {
|
|
166
|
-
const res = await fetch(`${base}/v1/escrow/withdraw`, {
|
|
167
|
-
method: "POST",
|
|
168
|
-
headers: {
|
|
169
|
-
"Content-Type": "application/json",
|
|
170
|
-
Authorization: `Web3Signed ${signature}`
|
|
171
|
-
},
|
|
172
|
-
body: JSON.stringify({
|
|
173
|
-
account,
|
|
174
|
-
asset,
|
|
175
|
-
amount,
|
|
176
|
-
withdrawNonce,
|
|
177
|
-
deadline
|
|
178
|
-
})
|
|
179
|
-
});
|
|
180
|
-
await throwOnWithdrawError(res);
|
|
181
|
-
return res.json();
|
|
182
110
|
}
|
|
183
111
|
};
|
|
184
112
|
}
|
|
185
|
-
function getGatewayErrorMessage(body) {
|
|
186
|
-
if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
|
|
187
|
-
return body.error;
|
|
188
|
-
}
|
|
189
|
-
return void 0;
|
|
190
|
-
}
|
|
191
|
-
function isEscrowWithdrawalFailureResult(body) {
|
|
192
|
-
if (typeof body !== "object" || body === null) return false;
|
|
193
|
-
const value = body;
|
|
194
|
-
return value.success === false && (value.status === "retryable" || value.status === "reorged" || value.status === "failed") && typeof value.error === "string" && isAddressHex(value.account) && isAddressHex(value.asset) && isUint256Decimal(value.amount) && isUint256Decimal(value.withdrawNonce) && isUint256Decimal(value.deadline) && (isHash(value.txHash) || value.txHash === null) && (!("blockNumber" in value) || isBlockNumber(value.blockNumber));
|
|
195
|
-
}
|
|
196
|
-
function isEscrowWithdrawalRejectedResult(body) {
|
|
197
|
-
if (typeof body !== "object" || body === null) return false;
|
|
198
|
-
const value = body;
|
|
199
|
-
return value.success === false && value.status === "rejected" && isWithdrawalRejectionCode(value.code) && typeof value.error === "string" && isAddressHex(value.account) && isAddressHex(value.asset) && isUint256Decimal(value.amount) && isUint256Decimal(value.withdrawNonce) && isUint256Decimal(value.deadline) && optionalUint256Decimal(value.balance) && optionalUint256Decimal(value.authorizedAmount) && optionalUint256Decimal(value.withdrawingAmount) && optionalUint256Decimal(value.availableAmount) && optionalUint256Decimal(value.requestedAmount) && optionalUint256Decimal(value.minimumAmount);
|
|
200
|
-
}
|
|
201
|
-
function isWithdrawalRejectionCode(value) {
|
|
202
|
-
return value === "below_minimum" || value === "deadline_too_far" || value === "expired" || value === "insufficient_available" || value === "stale_nonce";
|
|
203
|
-
}
|
|
204
|
-
function optionalUint256Decimal(value) {
|
|
205
|
-
return value === void 0 || isUint256Decimal(value);
|
|
206
|
-
}
|
|
207
|
-
function isAddressHex(value) {
|
|
208
|
-
return typeof value === "string" && isHex(value, { strict: true }) && value.length === 42;
|
|
209
|
-
}
|
|
210
|
-
function isHash(value) {
|
|
211
|
-
return typeof value === "string" && isHex(value, { strict: true }) && value.length === 66;
|
|
212
|
-
}
|
|
213
|
-
function isUint256Decimal(value) {
|
|
214
|
-
if (typeof value !== "string" || value.length === 0 || value.length > 78) {
|
|
215
|
-
return false;
|
|
216
|
-
}
|
|
217
|
-
if (!/^(0|[1-9]\d*)$/.test(value)) return false;
|
|
218
|
-
return BigInt(value) <= 2n ** 256n - 1n;
|
|
219
|
-
}
|
|
220
|
-
function isBlockNumber(value) {
|
|
221
|
-
return value === null || isUint256Decimal(value);
|
|
222
|
-
}
|
|
223
113
|
export {
|
|
224
114
|
ESCROW_DEPOSIT_ABI,
|
|
225
|
-
EscrowWithdrawalLifecycleError,
|
|
226
|
-
EscrowWithdrawalRejectionError,
|
|
227
115
|
GENERIC_PAYMENT_TYPES,
|
|
228
116
|
NATIVE_ASSET_ADDRESS,
|
|
229
|
-
WITHDRAW_AUTHORIZATION_TYPES,
|
|
230
|
-
buildWithdrawAuthorizationTypedData,
|
|
231
117
|
createEscrowGatewayClient,
|
|
232
|
-
genericPaymentDomain
|
|
233
|
-
withdrawAuthorizationDomain
|
|
118
|
+
genericPaymentDomain
|
|
234
119
|
};
|
|
235
120
|
//# sourceMappingURL=escrow.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/protocol/escrow.ts"],"sourcesContent":["/**\n * DPv2 escrow payment helpers.\n *\n * Covers the three-phase flow used by builders to pay for data access:\n *\n * 1. **Deposit** — call `depositNative` or `depositToken` on the\n * DataPortabilityEscrow contract, then notify the gateway.\n * 2. **Balance** — read or force-sync the gateway's off-chain credit view.\n * 3. **Pay** — sign a `GenericPayment` EIP-712 message and POST it to the\n * gateway's `/v1/escrow/pay` endpoint.\n *\n * The gateway is the authority on balances; the on-chain contract is the\n * authority on what has been settled. Nothing in this module touches the\n * chain directly — signing is done by the caller's wallet.\n *\n * @category Protocol\n * @module escrow\n */\n\nexport {\n buildWithdrawAuthorizationTypedData,\n withdrawAuthorizationDomain,\n WITHDRAW_AUTHORIZATION_TYPES,\n type WithdrawAuthorizationMessage,\n} from \"./eip712\";\nimport type { TypedDataDomain } from \"viem\";\nimport { isHex } from \"viem\";\n\n// ---------------------------------------------------------------------------\n// EIP-712 — GenericPayment\n// ---------------------------------------------------------------------------\n\n/**\n * EIP-712 typed-data types for a generic op payment.\n *\n * The gateway verifies that the recovered signer == `payerAddress` and that\n * the (payer, paymentNonce) pair has not been seen before. Use a\n * monotonically-increasing nonce; the first payment for any payer should\n * start at 1.\n */\nexport const GENERIC_PAYMENT_TYPES = {\n GenericPayment: [\n { name: \"payerAddress\", type: \"address\" },\n { name: \"opType\", type: \"string\" },\n { name: \"opId\", type: \"bytes32\" },\n { name: \"asset\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n { name: \"paymentNonce\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * EIP-712 message payload for a generic op payment.\n *\n * - `opType` is `\"grant\"` for legacy grant lifecycle payments or\n * `\"data_access\"` for a standalone receipt-bound read.\n * - `opId` is the bytes32 id of the operation being paid for: the grant id for\n * `\"grant\"`, or `accessRecord.recordId` for `\"data_access\"`.\n * - `asset` is the ERC-20 token address, or the zero address for native VANA.\n * - `amount` is the total amount in base units (wei for VANA). Must match the\n * sum the gateway expects for the current lifecycle of the op.\n * - `paymentNonce` must be a positive integer unique per `payerAddress`. Use 1\n * for the first payment; increment by at least 1 for each subsequent call.\n */\nexport interface GenericPaymentMessage {\n payerAddress: `0x${string}`;\n opType: string;\n opId: `0x${string}`;\n asset: `0x${string}`;\n amount: bigint;\n paymentNonce: bigint;\n}\n\n/**\n * Returns the EIP-712 domain for signing a `GenericPayment` message.\n *\n * The verifying contract is the `DataPortabilityEscrow` contract; all gateway\n * deployments share the same domain name and version.\n *\n * @param chainId - Chain ID of the Vana network (e.g. 1480 mainnet, 14800 testnet).\n * @param escrowContract - Deployed address of DataPortabilityEscrow.\n */\nexport function genericPaymentDomain(\n chainId: number,\n escrowContract: `0x${string}`,\n): TypedDataDomain {\n return {\n name: \"Vana Data Portability\",\n version: \"1\",\n chainId,\n verifyingContract: escrowContract,\n };\n}\n\n// ---------------------------------------------------------------------------\n// On-chain deposit ABI fragments\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal ABI for the two deposit entry points on `DataPortabilityEscrow`.\n *\n * - `depositNative(address account)` payable — credits native VANA.\n * - `depositToken(address account, address token, uint256 amount)` — credits\n * an ERC-20 token (caller must have pre-approved the escrow contract).\n *\n * Pass this to viem's `writeContract` or encode it manually.\n */\nexport const ESCROW_DEPOSIT_ABI = [\n {\n type: \"function\",\n name: \"depositNative\",\n stateMutability: \"payable\",\n inputs: [{ name: \"account\", type: \"address\" }],\n outputs: [],\n },\n {\n type: \"function\",\n name: \"depositToken\",\n stateMutability: \"nonpayable\",\n inputs: [\n { name: \"account\", type: \"address\" },\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n outputs: [],\n },\n] as const;\n\n/**\n * The zero address used by the DataPortabilityEscrow contract to represent\n * native VANA in `asset` fields of events and balance responses.\n */\nexport const NATIVE_ASSET_ADDRESS =\n \"0x0000000000000000000000000000000000000000\" as const;\n\n// ---------------------------------------------------------------------------\n// Gateway API client\n// ---------------------------------------------------------------------------\n\n/**\n * Per-asset balance entry returned by the gateway's escrow balance endpoints.\n *\n * - `balance` — gross finalized credit (deposits credited so far).\n * - `pendingAmount` — sum of submitted deposits not yet confirmed.\n * - `authorizedAmount` — sum of all in-flight payments authorized by\n * `/v1/escrow/pay` (soft-lock). May include payments not yet settled\n * on-chain.\n * - `withdrawingAmount` — sum of in-flight withdrawal reservations.\n * - `availableAmount` — `max(balance − authorizedAmount − withdrawingAmount, 0)`.\n * This is what the account can still authorize or withdraw.\n */\nexport interface EscrowBalanceEntry {\n asset: string;\n balance: string;\n pendingAmount: string;\n authorizedAmount: string;\n withdrawingAmount: string;\n availableAmount: string;\n updatedAt: string | null;\n}\n\nexport interface SubmittedDepositEntry {\n txHash: string;\n submittedAt: string;\n claimedAsset: string;\n claimedAmount: string;\n}\n\nexport interface FinalizedDepositEntry {\n txHash: string;\n finalizedAt: string | null;\n blockNumber: string | null;\n claimedAsset: string;\n claimedAmount: string;\n}\n\nexport interface FailedDepositEntry {\n txHash: string;\n submittedAt: string;\n claimedAsset: string;\n claimedAmount: string;\n lastError: string | null;\n}\n\n/** Full balance read response from `GET /v1/escrow/balance`. */\nexport interface EscrowBalanceResult {\n account: string;\n balances: EscrowBalanceEntry[];\n deposits: {\n submitted: SubmittedDepositEntry[];\n finalized: FinalizedDepositEntry[];\n failed: FailedDepositEntry[];\n };\n}\n\n/**\n * Response from `POST /v1/escrow/balance/sync`.\n *\n * Extends {@link EscrowBalanceResult} with a `sync` summary of what the\n * lazy-confirmation pass did.\n */\nexport interface EscrowBalanceSyncResult extends EscrowBalanceResult {\n sync:\n | {\n scanned: number;\n finalized: number;\n stillPending: number;\n failed: number;\n }\n | { skipped: true };\n}\n\n/** Response from `POST /v1/escrow/deposit`. */\nexport interface DepositSubmissionResult {\n success: true;\n txHash: string;\n account: string;\n status: \"submitted\" | \"finalized\" | \"failed\";\n blockNumber?: string | null;\n submittedAt: string;\n finalizedAt?: string | null;\n lastError?: string | null;\n}\n\n/** Breakdown returned by a successful `POST /v1/escrow/pay`. */\nexport interface PaymentBreakdown {\n registrationFee: string;\n dataAccessFee: string;\n /** True when this call settled the registration fee for the op. */\n registrationPaid: boolean;\n}\n\n/** Response from `POST /v1/escrow/pay`. */\nexport interface EscrowPayResult {\n success: true;\n opType: string;\n opId: string;\n payerAddress: string;\n asset: string;\n amount: string;\n breakdown: PaymentBreakdown;\n paymentNonce: string;\n paidAt: string;\n}\n\ninterface EscrowWithdrawalResponseBase {\n account: `0x${string}`;\n asset: `0x${string}`;\n amount: string;\n withdrawNonce: string;\n deadline: string;\n}\n\n/** A persisted authorization whose transaction has not been broadcast yet. */\nexport interface EscrowWithdrawalSubmittedWithoutTransaction extends EscrowWithdrawalResponseBase {\n success: true;\n status: \"submitted\";\n txHash: null;\n message: string;\n}\n\n/** A withdrawal with a persisted transaction that is awaiting reconciliation. */\nexport interface EscrowWithdrawalSubmittedWithTransaction {\n success: true;\n status: \"submitted\";\n txHash: `0x${string}`;\n message: string;\n // A provisional-revert response contains only txHash, blockNumber, and\n // message. Ordinary submissions include the signed-intent fields.\n account?: `0x${string}`;\n asset?: `0x${string}`;\n amount?: string;\n withdrawNonce?: string;\n deadline?: string;\n blockNumber?: string;\n}\n\n/** A withdrawal that the gateway has accepted but not yet confirmed. */\nexport type EscrowWithdrawalSubmittedResult =\n | EscrowWithdrawalSubmittedWithoutTransaction\n | EscrowWithdrawalSubmittedWithTransaction;\n\n/** A withdrawal whose on-chain debit has reached the named lifecycle state. */\nexport interface EscrowWithdrawalSettledResult extends EscrowWithdrawalResponseBase {\n success: true;\n status: \"confirmed\" | \"finalized\";\n txHash: `0x${string}`;\n blockNumber: string | null;\n}\n\n/** Successful lifecycle responses from `POST /v1/escrow/withdraw`. */\nexport type EscrowWithdrawalResult =\n | EscrowWithdrawalSubmittedResult\n | EscrowWithdrawalSettledResult;\n\n/** Terminal or retryable withdrawal lifecycle state returned with a non-2xx status. */\nexport interface EscrowWithdrawalFailureResult extends EscrowWithdrawalResponseBase {\n success: false;\n status: \"retryable\" | \"reorged\" | \"failed\";\n error: string;\n txHash: `0x${string}` | null;\n blockNumber?: string | null;\n}\n\nexport type EscrowWithdrawalRejectionCode =\n | \"below_minimum\"\n | \"deadline_too_far\"\n | \"expired\"\n | \"insufficient_available\"\n | \"stale_nonce\";\n\n/** Definite pre-acceptance rejection. No durable withdrawal intent was created. */\nexport interface EscrowWithdrawalRejectedResult extends EscrowWithdrawalResponseBase {\n success: false;\n status: \"rejected\";\n code: EscrowWithdrawalRejectionCode;\n error: string;\n balance?: string;\n authorizedAmount?: string;\n withdrawingAmount?: string;\n availableAmount?: string;\n requestedAmount?: string;\n minimumAmount?: string;\n}\n\n/**\n * A typed non-2xx gateway lifecycle response.\n *\n * `retryable` means resend the exact signed intent. `reorged` and `failed`\n * require a newly signed authorization with a new nonce.\n */\nexport class EscrowWithdrawalLifecycleError extends Error {\n override readonly name = \"EscrowWithdrawalLifecycleError\";\n\n constructor(\n readonly httpStatus: number,\n readonly result: EscrowWithdrawalFailureResult,\n ) {\n super(result.error);\n }\n}\n\n/** A typed non-2xx gateway rejection before a withdrawal intent is accepted. */\nexport class EscrowWithdrawalRejectionError extends Error {\n override readonly name = \"EscrowWithdrawalRejectionError\";\n\n constructor(\n readonly httpStatus: number,\n readonly result: EscrowWithdrawalRejectedResult,\n ) {\n super(result.error);\n }\n}\n\n/**\n * Parameters for submitting a deposit tx hash to the gateway.\n *\n * The gateway will decode the `account` from the tx's calldata and\n * credit the identified account once the tx reaches the configured\n * confirmation depth.\n */\nexport interface SubmitDepositParams {\n /** 0x-prefixed 32-byte transaction hash. */\n txHash: `0x${string}`;\n}\n\n/**\n * Parameters for the generic op payment endpoint (`POST /v1/escrow/pay`).\n *\n * The `signature` is an EIP-712 signature over a `GenericPayment` message\n * (see {@link GENERIC_PAYMENT_TYPES} and {@link genericPaymentDomain}).\n * Build and sign the typed data with your wallet before calling\n * {@link EscrowGatewayClient.payForOp}.\n */\nexport interface PayForOpParams {\n payerAddress: `0x${string}`;\n opType: string;\n opId: `0x${string}`;\n asset: `0x${string}`;\n /** Decimal string representation of the uint256 amount. */\n amount: string;\n /** Decimal string representation of the uint256 nonce. */\n paymentNonce: string;\n /** 0x-prefixed 65-byte EIP-712 signature hex string. */\n signature: `0x${string}`;\n /**\n * Optional data-access receipt carried by x402 challenges.\n *\n * The gateway verifies its server signature; this type only describes the\n * wire shape.\n */\n accessRecord?: EscrowAccessRecord;\n}\n\n/**\n * Parameters for `POST /v1/escrow/withdraw`.\n *\n * `withdrawNonce` and `deadline` are caller-supplied decimal uint256 strings.\n * The SDK intentionally does not generate a nonce: retrying safely requires a\n * durable caller-owned nonce source and the exact same signed payload.\n */\nexport interface WithdrawFromEscrowParams {\n account: `0x${string}`;\n asset: `0x${string}`;\n amount: string;\n withdrawNonce: string;\n deadline: string;\n signature: `0x${string}`;\n}\n\n/** Wire shape of a receipt whose server signature the gateway verifies. */\nexport interface EscrowAccessRecord {\n dataPointId: `0x${string}`;\n version: string;\n accessor: `0x${string}`;\n recordId: `0x${string}`;\n signature: `0x${string}`;\n}\n\n/**\n * Minimal client for the gateway's escrow endpoints.\n *\n * Construct with {@link createEscrowGatewayClient}.\n */\nexport interface EscrowGatewayClient {\n /**\n * Notify the gateway of a submitted deposit transaction.\n *\n * The gateway decodes the credited account from the on-chain tx calldata\n * and starts tracking the deposit. Call this immediately after your\n * `depositNative` or `depositToken` tx is broadcast (it accepts pending\n * mempool txs). Returns `202` while the tx awaits confirmation.\n */\n submitDeposit(params: SubmitDepositParams): Promise<DepositSubmissionResult>;\n\n /**\n * Read the current escrow balance for an account.\n *\n * Pure read — no chain calls. To force a reconciliation pass first,\n * use {@link syncEscrowBalance}.\n */\n getEscrowBalance(account: `0x${string}`): Promise<EscrowBalanceResult>;\n\n /**\n * Force a reconciliation pass then return the updated balance.\n *\n * Triggers the gateway's lazy-confirmation worker for the account — any\n * submitted deposits that have reached the configured confirmation level\n * are credited before the balance is returned. Prefer this over\n * {@link getEscrowBalance} when you need a fresh view after a deposit.\n */\n syncEscrowBalance(account: `0x${string}`): Promise<EscrowBalanceSyncResult>;\n\n /**\n * Authorize a payment against the payer's escrow balance.\n *\n * The caller must:\n * 1. Assemble a {@link GenericPaymentMessage}.\n * 2. Sign it with `signTypedData` using {@link GENERIC_PAYMENT_TYPES} and\n * the domain from {@link genericPaymentDomain}.\n * 3. Pass the message fields + signature here.\n *\n * The gateway verifies the signature, checks the soft-lock balance, and\n * records the payment. Returns 402 if the payer has insufficient balance.\n */\n payForOp(params: PayForOpParams): Promise<EscrowPayResult>;\n\n /**\n * Submit or reconcile a signed withdrawal authorization.\n *\n * Retry a `submitted` result with the exact same parameters. Do not replace\n * `withdrawNonce`, `deadline`, or signature unless starting a new intent.\n */\n withdraw(params: WithdrawFromEscrowParams): Promise<EscrowWithdrawalResult>;\n}\n\n/** The only gateway capability required by direct data-access payment flows. */\nexport type EscrowPaymentClient = Pick<EscrowGatewayClient, \"payForOp\">;\n\n/**\n * Creates a client for the gateway escrow endpoints.\n *\n * @param baseUrl - Base URL of the DP RPC gateway\n * (e.g. `\"https://dp.vana.org\"`). Trailing slashes are trimmed.\n *\n * @example\n * ```typescript\n * import {\n * createEscrowGatewayClient,\n * genericPaymentDomain,\n * GENERIC_PAYMENT_TYPES,\n * } from \"@opendatalabs/vana-sdk/node\";\n *\n * const escrow = createEscrowGatewayClient(\"https://dp.vana.org\");\n *\n * // 1. Submit your deposit tx hash after broadcasting depositNative on-chain\n * const deposit = await escrow.submitDeposit({ txHash: \"0xabc…\" });\n *\n * // 2. Force-sync and read the updated balance\n * const { balances } = await escrow.syncEscrowBalance(\"0xpayerAddress\");\n *\n * // 3. Sign and authorize a grant payment\n * const sig = await walletClient.signTypedData({\n * domain: genericPaymentDomain(1480, \"0xEscrowContract\"),\n * types: GENERIC_PAYMENT_TYPES,\n * primaryType: \"GenericPayment\",\n * message: {\n * payerAddress: \"0xpayerAddress\",\n * opType: \"grant\",\n * opId: \"0xgrantId\",\n * asset: \"0x0000000000000000000000000000000000000000\",\n * amount: 1000000000000000000n,\n * paymentNonce: 1n,\n * },\n * });\n * const result = await escrow.payForOp({\n * payerAddress: \"0xpayerAddress\",\n * opType: \"grant\",\n * opId: \"0xgrantId\",\n * asset: \"0x0000000000000000000000000000000000000000\",\n * amount: \"1000000000000000000\",\n * paymentNonce: \"1\",\n * signature: sig,\n * });\n * ```\n */\nexport function createEscrowGatewayClient(\n baseUrl: string,\n): EscrowGatewayClient {\n const base = baseUrl.replace(/\\/+$/, \"\");\n\n async function throwOnError(res: Response, context: string): Promise<void> {\n if (!res.ok) {\n let detail = \"\";\n try {\n const body = (await res.json()) as { error?: string };\n if (body.error) detail = `: ${body.error}`;\n } catch {\n // Ignore JSON parse errors; use status text only.\n }\n throw new Error(\n `Escrow gateway error (${context}): ${res.status} ${res.statusText}${detail}`,\n );\n }\n }\n\n async function throwOnWithdrawError(res: Response): Promise<void> {\n if (res.ok) return;\n\n let body: unknown;\n try {\n body = await res.json();\n } catch {\n throw new Error(\n `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}`,\n );\n }\n\n if (isEscrowWithdrawalFailureResult(body)) {\n throw new EscrowWithdrawalLifecycleError(res.status, body);\n }\n if (isEscrowWithdrawalRejectedResult(body)) {\n throw new EscrowWithdrawalRejectionError(res.status, body);\n }\n\n const error = getGatewayErrorMessage(body);\n throw new Error(\n `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}${error ? `: ${error}` : \"\"}`,\n );\n }\n\n return {\n async submitDeposit({ txHash }) {\n const res = await fetch(`${base}/v1/escrow/deposit`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ txHash }),\n });\n // 202 Accepted and 200 OK are both success states for deposit submission.\n if (res.status !== 200 && res.status !== 202) {\n await throwOnError(res, \"POST /v1/escrow/deposit\");\n }\n return res.json() as Promise<DepositSubmissionResult>;\n },\n\n async getEscrowBalance(account) {\n const res = await fetch(\n `${base}/v1/escrow/balance?account=${encodeURIComponent(account)}`,\n );\n await throwOnError(res, \"GET /v1/escrow/balance\");\n return res.json() as Promise<EscrowBalanceResult>;\n },\n\n async syncEscrowBalance(account) {\n const res = await fetch(\n `${base}/v1/escrow/balance/sync?account=${encodeURIComponent(account)}`,\n { method: \"POST\" },\n );\n await throwOnError(res, \"POST /v1/escrow/balance/sync\");\n return res.json() as Promise<EscrowBalanceSyncResult>;\n },\n\n async payForOp({\n payerAddress,\n opType,\n opId,\n asset,\n amount,\n paymentNonce,\n signature,\n accessRecord,\n }) {\n const res = await fetch(`${base}/v1/escrow/pay`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${signature}`,\n },\n body: JSON.stringify({\n payerAddress,\n opType,\n opId,\n asset,\n amount,\n paymentNonce,\n ...(accessRecord ? { accessRecord } : {}),\n }),\n });\n await throwOnError(res, \"POST /v1/escrow/pay\");\n return res.json() as Promise<EscrowPayResult>;\n },\n\n async withdraw({\n account,\n asset,\n amount,\n withdrawNonce,\n deadline,\n signature,\n }) {\n const res = await fetch(`${base}/v1/escrow/withdraw`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${signature}`,\n },\n body: JSON.stringify({\n account,\n asset,\n amount,\n withdrawNonce,\n deadline,\n }),\n });\n await throwOnWithdrawError(res);\n return res.json() as Promise<EscrowWithdrawalResult>;\n },\n };\n}\n\nfunction getGatewayErrorMessage(body: unknown): string | undefined {\n if (\n typeof body === \"object\" &&\n body !== null &&\n \"error\" in body &&\n typeof body.error === \"string\"\n ) {\n return body.error;\n }\n return undefined;\n}\n\nfunction isEscrowWithdrawalFailureResult(\n body: unknown,\n): body is EscrowWithdrawalFailureResult {\n if (typeof body !== \"object\" || body === null) return false;\n const value = body as Record<string, unknown>;\n return (\n value.success === false &&\n (value.status === \"retryable\" ||\n value.status === \"reorged\" ||\n value.status === \"failed\") &&\n typeof value.error === \"string\" &&\n isAddressHex(value.account) &&\n isAddressHex(value.asset) &&\n isUint256Decimal(value.amount) &&\n isUint256Decimal(value.withdrawNonce) &&\n isUint256Decimal(value.deadline) &&\n (isHash(value.txHash) || value.txHash === null) &&\n (!(\"blockNumber\" in value) || isBlockNumber(value.blockNumber))\n );\n}\n\nfunction isEscrowWithdrawalRejectedResult(\n body: unknown,\n): body is EscrowWithdrawalRejectedResult {\n if (typeof body !== \"object\" || body === null) return false;\n const value = body as Record<string, unknown>;\n return (\n value.success === false &&\n value.status === \"rejected\" &&\n isWithdrawalRejectionCode(value.code) &&\n typeof value.error === \"string\" &&\n isAddressHex(value.account) &&\n isAddressHex(value.asset) &&\n isUint256Decimal(value.amount) &&\n isUint256Decimal(value.withdrawNonce) &&\n isUint256Decimal(value.deadline) &&\n optionalUint256Decimal(value.balance) &&\n optionalUint256Decimal(value.authorizedAmount) &&\n optionalUint256Decimal(value.withdrawingAmount) &&\n optionalUint256Decimal(value.availableAmount) &&\n optionalUint256Decimal(value.requestedAmount) &&\n optionalUint256Decimal(value.minimumAmount)\n );\n}\n\nfunction isWithdrawalRejectionCode(\n value: unknown,\n): value is EscrowWithdrawalRejectionCode {\n return (\n value === \"below_minimum\" ||\n value === \"deadline_too_far\" ||\n value === \"expired\" ||\n value === \"insufficient_available\" ||\n value === \"stale_nonce\"\n );\n}\n\nfunction optionalUint256Decimal(value: unknown): boolean {\n return value === undefined || isUint256Decimal(value);\n}\n\nfunction isAddressHex(value: unknown): value is `0x${string}` {\n return (\n typeof value === \"string\" &&\n isHex(value, { strict: true }) &&\n value.length === 42\n );\n}\n\nfunction isHash(value: unknown): value is `0x${string}` {\n return (\n typeof value === \"string\" &&\n isHex(value, { strict: true }) &&\n value.length === 66\n );\n}\n\nfunction isUint256Decimal(value: unknown): value is string {\n if (typeof value !== \"string\" || value.length === 0 || value.length > 78) {\n return false;\n }\n if (!/^(0|[1-9]\\d*)$/.test(value)) return false;\n return BigInt(value) <= 2n ** 256n - 1n;\n}\n\nfunction isBlockNumber(value: unknown): value is string | null {\n return value === null || isUint256Decimal(value);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/protocol/escrow.ts"],"sourcesContent":["/**\n * DPv2 escrow payment helpers.\n *\n * Covers the three-phase flow used by builders to pay for data access:\n *\n * 1. **Deposit** — call `depositNative` or `depositToken` on the\n * DataPortabilityEscrow contract, then notify the gateway.\n * 2. **Balance** — read or force-sync the gateway's off-chain credit view.\n * 3. **Pay** — sign a `GenericPayment` EIP-712 message and POST it to the\n * gateway's `/v1/escrow/pay` endpoint.\n *\n * The gateway is the authority on balances; the on-chain contract is the\n * authority on what has been settled. Nothing in this module touches the\n * chain directly — signing is done by the caller's wallet.\n *\n * @category Protocol\n * @module escrow\n */\n\nimport type { TypedDataDomain } from \"viem\";\n\n// ---------------------------------------------------------------------------\n// EIP-712 — GenericPayment\n// ---------------------------------------------------------------------------\n\n/**\n * EIP-712 typed-data types for a generic op payment.\n *\n * The gateway verifies that the recovered signer == `payerAddress` and that\n * the (payer, paymentNonce) pair has not been seen before. Use a\n * monotonically-increasing nonce; the first payment for any payer should\n * start at 1.\n */\nexport const GENERIC_PAYMENT_TYPES = {\n GenericPayment: [\n { name: \"payerAddress\", type: \"address\" },\n { name: \"opType\", type: \"string\" },\n { name: \"opId\", type: \"bytes32\" },\n { name: \"asset\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n { name: \"paymentNonce\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * EIP-712 message payload for a generic op payment.\n *\n * - `opType` is `\"grant\"` for legacy grant lifecycle payments or\n * `\"data_access\"` for a standalone receipt-bound read.\n * - `opId` is the bytes32 id of the operation being paid for: the grant id for\n * `\"grant\"`, or `accessRecord.recordId` for `\"data_access\"`.\n * - `asset` is the ERC-20 token address, or the zero address for native VANA.\n * - `amount` is the total amount in base units (wei for VANA). Must match the\n * sum the gateway expects for the current lifecycle of the op.\n * - `paymentNonce` must be a positive integer unique per `payerAddress`. Use 1\n * for the first payment; increment by at least 1 for each subsequent call.\n */\nexport interface GenericPaymentMessage {\n payerAddress: `0x${string}`;\n opType: string;\n opId: `0x${string}`;\n asset: `0x${string}`;\n amount: bigint;\n paymentNonce: bigint;\n}\n\n/**\n * Returns the EIP-712 domain for signing a `GenericPayment` message.\n *\n * The verifying contract is the `DataPortabilityEscrow` contract; all gateway\n * deployments share the same domain name and version.\n *\n * @param chainId - Chain ID of the Vana network (e.g. 1480 mainnet, 14800 testnet).\n * @param escrowContract - Deployed address of DataPortabilityEscrow.\n */\nexport function genericPaymentDomain(\n chainId: number,\n escrowContract: `0x${string}`,\n): TypedDataDomain {\n return {\n name: \"Vana Data Portability\",\n version: \"1\",\n chainId,\n verifyingContract: escrowContract,\n };\n}\n\n// ---------------------------------------------------------------------------\n// On-chain deposit ABI fragments\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal ABI for the two deposit entry points on `DataPortabilityEscrow`.\n *\n * - `depositNative(address account)` payable — credits native VANA.\n * - `depositToken(address account, address token, uint256 amount)` — credits\n * an ERC-20 token (caller must have pre-approved the escrow contract).\n *\n * Pass this to viem's `writeContract` or encode it manually.\n */\nexport const ESCROW_DEPOSIT_ABI = [\n {\n type: \"function\",\n name: \"depositNative\",\n stateMutability: \"payable\",\n inputs: [{ name: \"account\", type: \"address\" }],\n outputs: [],\n },\n {\n type: \"function\",\n name: \"depositToken\",\n stateMutability: \"nonpayable\",\n inputs: [\n { name: \"account\", type: \"address\" },\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n outputs: [],\n },\n] as const;\n\n/**\n * The zero address used by the DataPortabilityEscrow contract to represent\n * native VANA in `asset` fields of events and balance responses.\n */\nexport const NATIVE_ASSET_ADDRESS =\n \"0x0000000000000000000000000000000000000000\" as const;\n\n// ---------------------------------------------------------------------------\n// Gateway API client\n// ---------------------------------------------------------------------------\n\n/**\n * Per-asset balance entry returned by the gateway's escrow balance endpoints.\n *\n * - `balance` — gross finalized credit (deposits credited so far).\n * - `pendingAmount` — sum of submitted deposits not yet confirmed.\n * - `authorizedAmount` — sum of all in-flight payments authorized by\n * `/v1/escrow/pay` (soft-lock). May include payments not yet settled\n * on-chain.\n * - `availableAmount` — `max(balance − authorizedAmount, 0)`. This is what\n * the payer can authorize before the gateway rejects with 402.\n */\nexport interface EscrowBalanceEntry {\n asset: string;\n balance: string;\n pendingAmount: string;\n authorizedAmount: string;\n availableAmount: string;\n updatedAt: string | null;\n}\n\nexport interface SubmittedDepositEntry {\n txHash: string;\n submittedAt: string;\n claimedAsset: string;\n claimedAmount: string;\n}\n\nexport interface FinalizedDepositEntry {\n txHash: string;\n finalizedAt: string | null;\n blockNumber: string | null;\n claimedAsset: string;\n claimedAmount: string;\n}\n\nexport interface FailedDepositEntry {\n txHash: string;\n submittedAt: string;\n claimedAsset: string;\n claimedAmount: string;\n lastError: string | null;\n}\n\n/** Full balance read response from `GET /v1/escrow/balance`. */\nexport interface EscrowBalanceResult {\n account: string;\n balances: EscrowBalanceEntry[];\n deposits: {\n submitted: SubmittedDepositEntry[];\n finalized: FinalizedDepositEntry[];\n failed: FailedDepositEntry[];\n };\n}\n\n/**\n * Response from `POST /v1/escrow/balance/sync`.\n *\n * Extends {@link EscrowBalanceResult} with a `sync` summary of what the\n * lazy-confirmation pass did.\n */\nexport interface EscrowBalanceSyncResult extends EscrowBalanceResult {\n sync:\n | {\n scanned: number;\n finalized: number;\n stillPending: number;\n failed: number;\n }\n | { skipped: true };\n}\n\n/** Response from `POST /v1/escrow/deposit`. */\nexport interface DepositSubmissionResult {\n success: true;\n txHash: string;\n account: string;\n status: \"submitted\" | \"finalized\" | \"failed\";\n blockNumber?: string | null;\n submittedAt: string;\n finalizedAt?: string | null;\n lastError?: string | null;\n}\n\n/** Breakdown returned by a successful `POST /v1/escrow/pay`. */\nexport interface PaymentBreakdown {\n registrationFee: string;\n dataAccessFee: string;\n /** True when this call settled the registration fee for the op. */\n registrationPaid: boolean;\n}\n\n/** Response from `POST /v1/escrow/pay`. */\nexport interface EscrowPayResult {\n success: true;\n opType: string;\n opId: string;\n payerAddress: string;\n asset: string;\n amount: string;\n breakdown: PaymentBreakdown;\n paymentNonce: string;\n paidAt: string;\n}\n\n/**\n * Parameters for submitting a deposit tx hash to the gateway.\n *\n * The gateway will decode the `account` from the tx's calldata and\n * credit the identified account once the tx reaches the configured\n * confirmation depth.\n */\nexport interface SubmitDepositParams {\n /** 0x-prefixed 32-byte transaction hash. */\n txHash: `0x${string}`;\n}\n\n/**\n * Parameters for the generic op payment endpoint (`POST /v1/escrow/pay`).\n *\n * The `signature` is an EIP-712 signature over a `GenericPayment` message\n * (see {@link GENERIC_PAYMENT_TYPES} and {@link genericPaymentDomain}).\n * Build and sign the typed data with your wallet before calling\n * {@link EscrowGatewayClient.payForOp}.\n */\nexport interface PayForOpParams {\n payerAddress: `0x${string}`;\n opType: string;\n opId: `0x${string}`;\n asset: `0x${string}`;\n /** Decimal string representation of the uint256 amount. */\n amount: string;\n /** Decimal string representation of the uint256 nonce. */\n paymentNonce: string;\n /** 0x-prefixed 65-byte EIP-712 signature hex string. */\n signature: `0x${string}`;\n /**\n * Optional data-access receipt carried by x402 challenges.\n *\n * The gateway verifies its server signature; this type only describes the\n * wire shape.\n */\n accessRecord?: EscrowAccessRecord;\n}\n\n/** Wire shape of a receipt whose server signature the gateway verifies. */\nexport interface EscrowAccessRecord {\n dataPointId: `0x${string}`;\n version: string;\n accessor: `0x${string}`;\n recordId: `0x${string}`;\n signature: `0x${string}`;\n}\n\n/**\n * Minimal client for the gateway's escrow endpoints.\n *\n * Construct with {@link createEscrowGatewayClient}.\n */\nexport interface EscrowGatewayClient {\n /**\n * Notify the gateway of a submitted deposit transaction.\n *\n * The gateway decodes the credited account from the on-chain tx calldata\n * and starts tracking the deposit. Call this immediately after your\n * `depositNative` or `depositToken` tx is broadcast (it accepts pending\n * mempool txs). Returns `202` while the tx awaits confirmation.\n */\n submitDeposit(params: SubmitDepositParams): Promise<DepositSubmissionResult>;\n\n /**\n * Read the current escrow balance for an account.\n *\n * Pure read — no chain calls. To force a reconciliation pass first,\n * use {@link syncEscrowBalance}.\n */\n getEscrowBalance(account: `0x${string}`): Promise<EscrowBalanceResult>;\n\n /**\n * Force a reconciliation pass then return the updated balance.\n *\n * Triggers the gateway's lazy-confirmation worker for the account — any\n * submitted deposits that have reached the configured confirmation level\n * are credited before the balance is returned. Prefer this over\n * {@link getEscrowBalance} when you need a fresh view after a deposit.\n */\n syncEscrowBalance(account: `0x${string}`): Promise<EscrowBalanceSyncResult>;\n\n /**\n * Authorize a payment against the payer's escrow balance.\n *\n * The caller must:\n * 1. Assemble a {@link GenericPaymentMessage}.\n * 2. Sign it with `signTypedData` using {@link GENERIC_PAYMENT_TYPES} and\n * the domain from {@link genericPaymentDomain}.\n * 3. Pass the message fields + signature here.\n *\n * The gateway verifies the signature, checks the soft-lock balance, and\n * records the payment. Returns 402 if the payer has insufficient balance.\n */\n payForOp(params: PayForOpParams): Promise<EscrowPayResult>;\n}\n\n/**\n * Creates a client for the gateway escrow endpoints.\n *\n * @param baseUrl - Base URL of the DP RPC gateway\n * (e.g. `\"https://dp.vana.org\"`). Trailing slashes are trimmed.\n *\n * @example\n * ```typescript\n * import {\n * createEscrowGatewayClient,\n * genericPaymentDomain,\n * GENERIC_PAYMENT_TYPES,\n * } from \"@opendatalabs/vana-sdk/node\";\n *\n * const escrow = createEscrowGatewayClient(\"https://dp.vana.org\");\n *\n * // 1. Submit your deposit tx hash after broadcasting depositNative on-chain\n * const deposit = await escrow.submitDeposit({ txHash: \"0xabc…\" });\n *\n * // 2. Force-sync and read the updated balance\n * const { balances } = await escrow.syncEscrowBalance(\"0xpayerAddress\");\n *\n * // 3. Sign and authorize a grant payment\n * const sig = await walletClient.signTypedData({\n * domain: genericPaymentDomain(1480, \"0xEscrowContract\"),\n * types: GENERIC_PAYMENT_TYPES,\n * primaryType: \"GenericPayment\",\n * message: {\n * payerAddress: \"0xpayerAddress\",\n * opType: \"grant\",\n * opId: \"0xgrantId\",\n * asset: \"0x0000000000000000000000000000000000000000\",\n * amount: 1000000000000000000n,\n * paymentNonce: 1n,\n * },\n * });\n * const result = await escrow.payForOp({\n * payerAddress: \"0xpayerAddress\",\n * opType: \"grant\",\n * opId: \"0xgrantId\",\n * asset: \"0x0000000000000000000000000000000000000000\",\n * amount: \"1000000000000000000\",\n * paymentNonce: \"1\",\n * signature: sig,\n * });\n * ```\n */\nexport function createEscrowGatewayClient(\n baseUrl: string,\n): EscrowGatewayClient {\n const base = baseUrl.replace(/\\/+$/, \"\");\n\n async function throwOnError(res: Response, context: string): Promise<void> {\n if (!res.ok) {\n let detail = \"\";\n try {\n const body = (await res.json()) as { error?: string };\n if (body.error) detail = `: ${body.error}`;\n } catch {\n // Ignore JSON parse errors; use status text only.\n }\n throw new Error(\n `Escrow gateway error (${context}): ${res.status} ${res.statusText}${detail}`,\n );\n }\n }\n\n return {\n async submitDeposit({ txHash }) {\n const res = await fetch(`${base}/v1/escrow/deposit`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ txHash }),\n });\n // 202 Accepted and 200 OK are both success states for deposit submission.\n if (res.status !== 200 && res.status !== 202) {\n await throwOnError(res, \"POST /v1/escrow/deposit\");\n }\n return res.json() as Promise<DepositSubmissionResult>;\n },\n\n async getEscrowBalance(account) {\n const res = await fetch(\n `${base}/v1/escrow/balance?account=${encodeURIComponent(account)}`,\n );\n await throwOnError(res, \"GET /v1/escrow/balance\");\n return res.json() as Promise<EscrowBalanceResult>;\n },\n\n async syncEscrowBalance(account) {\n const res = await fetch(\n `${base}/v1/escrow/balance/sync?account=${encodeURIComponent(account)}`,\n { method: \"POST\" },\n );\n await throwOnError(res, \"POST /v1/escrow/balance/sync\");\n return res.json() as Promise<EscrowBalanceSyncResult>;\n },\n\n async payForOp({\n payerAddress,\n opType,\n opId,\n asset,\n amount,\n paymentNonce,\n signature,\n accessRecord,\n }) {\n const res = await fetch(`${base}/v1/escrow/pay`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${signature}`,\n },\n body: JSON.stringify({\n payerAddress,\n opType,\n opId,\n asset,\n amount,\n paymentNonce,\n ...(accessRecord ? { accessRecord } : {}),\n }),\n });\n await throwOnError(res, \"POST /v1/escrow/pay\");\n return res.json() as Promise<EscrowPayResult>;\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/protocol/gateway.ts"],"sourcesContent":["import type { EscrowBalanceResult } from \"./escrow\";\n\nexport type {\n EscrowBalanceEntry,\n EscrowBalanceResult,\n FailedDepositEntry as EscrowDepositFailed,\n FinalizedDepositEntry as EscrowDepositFinalized,\n SubmittedDepositEntry as EscrowDepositSubmitted,\n} from \"./escrow\";\n\nexport interface GatewayEnvelope<T> {\n data: T;\n proof: GatewayProof;\n /**\n * Cursor-based pagination metadata, present on list endpoints (e.g.\n * `GET /v1/data`). A sibling of `data`, not nested inside it — so callers\n * that need it must read the full envelope rather than going through\n * `unwrapEnvelope`, which intentionally returns only `data`.\n */\n pagination?: GatewayPagination;\n}\n\nexport interface GatewayPagination {\n limit: number;\n hasMore: boolean;\n /**\n * Opaque cursor for the NEXT page; pass back as the `cursor` query param.\n * Null when there are no further pages.\n */\n nextCursor: string | null;\n}\n\nexport interface GatewayProof {\n signature: string;\n timestamp: string;\n gatewayAddress: string;\n requestHash: string;\n responseHash: string;\n userSignature: string;\n status: string;\n chainBlockHeight: number;\n}\n\nexport interface Builder {\n id: string;\n ownerAddress: string;\n granteeAddress: string;\n publicKey: string;\n appUrl: string;\n addedAt: string;\n}\n\nexport interface Schema {\n id: string;\n ownerAddress: string;\n name: string;\n definitionUrl: string;\n scope: string;\n addedAt: string;\n}\n\n// Row shape returned by `GET /v1/servers?owner=…`. A discovery-only list —\n// the endpoint carries no per-item gateway attestation (use\n// `getServer(serverAddress)` if you need a verifiable single-server proof).\n// `status` is the gateway's chain-sync state ('pending' | 'confirmed' |\n// 'finalized' | 'reorged'); kept as an open string since the gateway may add\n// states without a SDK bump.\nexport interface OwnerServerRecord {\n id: string;\n ownerAddress: string;\n serverAddress: string;\n publicKey: string;\n serverUrl: string;\n status: string;\n chainBlockHeight: string | null;\n // ISO timestamp of the gateway-side upsert.\n addedAt: string;\n // ISO timestamp when the grantor deregistered this server. Always null for\n // entries in the `active` list, always non-null for `revoked`.\n revokedAt: string | null;\n}\n\n// Response from `GET /v1/servers?owner=…`. Split into two arrays; each is\n// ordered newest-first (`addedAt DESC`, `id ASC` tiebreaker) so `active[0]`\n// is unambiguously the newest active server — the sensible default when the\n// caller just needs one URL. The gateway caps the total across both arrays\n// at 200 — per-owner counts are tiny in practice, so no cursor.\nexport interface OwnerServersResult {\n active: OwnerServerRecord[];\n revoked: OwnerServerRecord[];\n count: number;\n}\n\nexport interface ServerInfo {\n id: string;\n ownerAddress: string;\n serverAddress: string;\n publicKey: string;\n serverUrl: string;\n addedAt: string;\n // ISO timestamp when the grantor deregistered this server, null while\n // active. The gateway returns this on /v1/servers/:address GETs since\n // covering revocation in the response keeps the attestation hash\n // authoritative for both states.\n revokedAt: string | null;\n}\n\n// Fee annotation surfaced on every GET grant response. Amounts are decimal\n// uint256 strings to match `/v1/escrow/pay`'s wire format. totalDue is a\n// snapshot — the gateway re-resolves fees at pay time, so clients shouldn't\n// cache this across requests.\nexport interface GatewayGrantFee {\n asset: string;\n registrationFee: string;\n dataAccessFee: string;\n totalDue: string;\n}\n\n// Lifecycle of a grant's on-chain settlement, tracked separately from the\n// fee-payment lifecycle (paymentStatus). Driven by POST /v1/settle:\n// pending — nothing on-chain yet\n// submitting — settle tx broadcast but receipt not yet observed\n// confirmed — settle tx mined successfully\n// finalized — finalized tip past the settle block, reorg-safe\n// reorged — finalized observation reverted; back to 'pending' on next settle\nexport type GatewayGrantStatus =\n | \"pending\"\n | \"submitting\"\n | \"confirmed\"\n | \"finalized\"\n | \"reorged\";\n\nexport interface GatewayGrantResponse {\n id: string;\n grantorAddress: string;\n granteeId: string;\n scopes: string[];\n status: GatewayGrantStatus;\n addedAt: string;\n // Grantor-signed deadline. null = perpetual grant (signed value was 0).\n expiresAt: string | null;\n // Derived at read time from expiresAt vs the gateway's clock — a snapshot,\n // not a cached truth. Re-check against expiresAt locally if you care.\n expired: boolean;\n revokedAt: string | null;\n revocationSignature: string | null;\n // 'pending' until the grant registration fee is settled via /v1/escrow/pay.\n paymentStatus: \"pending\" | \"paid\";\n paidAt: string | null;\n paidBy: string | null;\n // Decimal-string uint256 monotonic nonce; advances on every state change.\n grantVersion: string;\n // Settle metadata — populated as the grant progresses through the chain\n // lifecycle. Null while `status === 'pending'`.\n settleTxHash: string | null;\n settleSubmittedAt: string | null;\n // Revocation metadata — populated independently when the grantor signs\n // and the gateway pushes a deregister tx.\n revocationTxHash: string | null;\n revocationSubmittedAt: string | null;\n fee: GatewayGrantFee;\n}\n\nexport type GrantListItem = GatewayGrantResponse;\n\n// Mirror of a DataRegistryV2 row as the gateway exposes it. `id` is the\n// deterministic `keccak256(abi.encode(owner, scope))` dataPointId — the same\n// value the contract uses as its primary key. `expectedVersion` is the latest\n// version the gateway has accepted; the on-chain row may be one version behind\n// while a settle is still pending. The gateway response intentionally drops\n// `status` from the body — read it from the on-chain contract when you need\n// the canonical lifecycle state.\nexport interface DataPointRecord {\n id: string;\n ownerAddress: string;\n scope: string;\n dataHash: string;\n metadataHash: string;\n // Decimal-string uint256.\n expectedVersion: string;\n // ISO 8601 timestamp of the most recent gateway-side upsert.\n addedAt: string;\n}\n\nexport interface DataPointListResult {\n dataPoints: DataPointRecord[];\n cursor: string | null;\n}\n\nexport interface ListDataPointsOptions {\n /**\n * Only return rows added at or after this ISO 8601 timestamp. Used by sync\n * loops that want incremental tails — pass the last seen `addedAt`.\n */\n since?: string;\n /** Page size. Capped at 1000 by the gateway. */\n limit?: number;\n}\n\n// grantVersion and expiresAt are decimal-string uint256s — same wire format\n// the gateway expects. The caller is responsible for converting their bigint\n// to a decimal string and for signing GRANT_REGISTRATION_TYPES with matching\n// bigint values.\nexport interface CreateGrantParams {\n grantorAddress: string;\n granteeId: string;\n scopes: string[];\n grantVersion: string;\n expiresAt: string;\n signature: string;\n}\n\nexport interface RevokeGrantParams {\n grantId: string;\n grantorAddress: string;\n grantVersion: string;\n signature: string;\n}\n\nexport interface RegisterServerParams {\n ownerAddress: string;\n serverAddress: string;\n publicKey: string;\n serverUrl: string;\n signature: string;\n}\n\nexport interface RegisterServerResult {\n serverId?: string;\n alreadyRegistered: boolean;\n}\n\nexport interface RegisterBuilderParams {\n ownerAddress: string;\n // Wallet the builder authenticates to the Personal Server with. The\n // builderId is deterministically derived from (owner, grantee, publicKey,\n // appUrl) so this triple pins the on-chain identity.\n granteeAddress: string;\n publicKey: string;\n appUrl: string;\n signature: string;\n}\n\nexport interface RegisterBuilderResult {\n builderId?: string;\n alreadyRegistered: boolean;\n}\n\n// AddData on DataRegistryV2. dataHash + metadataHash are bytes32 commitments\n// to the off-chain payload + its metadata. expectedVersion is a CAS knob —\n// the gateway/contract rejects on 409 if a higher version is already stored,\n// and the error body surfaces `currentExpectedVersion` so callers can re-sign.\nexport interface RegisterDataPointParams {\n ownerAddress: string;\n scope: string;\n dataHash: string;\n metadataHash: string;\n expectedVersion: string;\n signature: string;\n}\n\nexport interface RegisterDataPointResult {\n dataPointId?: string;\n expectedVersion?: string;\n}\n\n// ── Escrow / data-access payment path ───────────────────────────────────────\n// /v1/escrow/pay debits the payer's escrow balance for a payable op. For a\n// Legacy grants use opType='grant' and opId=grantId. Standalone receipt-bound\n// reads use opType='data_access' and opId=accessRecord.recordId. amount and\n// paymentNonce are decimal uint256 strings on the wire. The signature is the\n// raw EIP-712 hex of GENERIC_PAYMENT_TYPES against escrowPaymentDomain.\n\n// A server-signed delivery receipt attached to a data-access payment. The\n// signature is over RECORD_DATA_ACCESS_TYPES against dataRegistryDomain; the\n// signer must be a personal server the data point's owner has registered as\n// trusted. Shape validation in clients does not verify this signature; the\n// gateway verifies it before re-using it on-chain in the next /v1/settle pass\n// via DataRegistryV2.recordDataAccess, where `recordId` dedupes via\n// `_usedRecordIds`.\nexport interface AccessRecord {\n dataPointId: string;\n // Decimal-string uint256 — the data point version being attested to.\n version: string;\n // Must equal the enclosing payment's payerAddress (the gateway enforces).\n accessor: string;\n recordId: string;\n signature: string;\n}\n\nexport interface PayForOperationParams {\n payerAddress: string;\n opType: string;\n opId: string;\n asset: string;\n amount: string;\n // Per-payer monotonic; (payer, nonce, kind) must be unique. The gateway\n // returns 409 if reused — bump and re-sign.\n paymentNonce: string;\n signature: string;\n // Optional: attach a server-signed access record so the next /v1/settle\n // pass submits a recordDataAccess tx alongside the payment settlement.\n // Required for data-access payments (the second-and-onward payments per\n // grant) that want their on-chain `totalAccesses` counter to advance.\n accessRecord?: AccessRecord;\n}\n\nexport interface PayForOperationResult {\n opType: string;\n opId: string;\n payerAddress: string;\n asset: string;\n amount: string;\n // Echoes how the gateway split this payment. `registrationPaid` is true on\n // the first payment for a grant (which bundles both fees) and false on\n // subsequent data-access-only payments. Off-chain ledger state only — the\n // on-chain settlement of the registration is tracked by the grant's\n // `status` field, not this flag.\n breakdown: {\n registrationFee: string;\n dataAccessFee: string;\n registrationPaid: boolean;\n };\n paymentNonce: string;\n paidAt: string;\n}\n\n// ── Settle / reconcile ──────────────────────────────────────────────────────\n// POST /v1/settle drains pending-on-chain rows (grants, servers, builders,\n// data points, data-point statuses, access records) to the relayer, then\n// promotes 'submitting' → 'confirmed' and 'confirmed' → 'finalized' for\n// previously-submitted rows. One call does all three; the response surfaces\n// each phase's outcomes.\n\n// The op-types the settle endpoint emits in `items[]`. Kept as a union so\n// callers can narrow inside the discriminated SettleItem shape. Mirrors the\n// gateway's drain phases (drainGrants/drainServers/drainBuilders/\n// drainDataPoints/drainDataPointStatuses/drainAccessRecords) — keep in sync\n// when the gateway adds a drain.\nexport type SettleOpType =\n | \"grant\"\n | \"server\"\n | \"data\"\n | \"access\"\n | \"builder\"\n | \"data-status\";\n\nexport type SettleItem =\n | {\n opType: SettleOpType;\n opId: string;\n // 'confirmed' when the submit function waited for the receipt and it\n // mined (registerAndSettle path); 'submitting' when only the tx was\n // sent (no receipt wait).\n status: \"submitting\" | \"confirmed\";\n settleTxHash: string | null;\n settleSubmittedAt: string | null;\n // Block height the tx mined in; only set when status === 'confirmed'.\n chainBlockHeight: string | null;\n revocationTxHash: string | null;\n revocationSubmittedAt: string | null;\n // True while lib/settle.ts is in placeholder mode for this row's pass.\n placeholder: boolean;\n }\n | {\n opType: SettleOpType;\n opId: string;\n status: \"skipped\";\n reason: string;\n }\n | {\n opType: SettleOpType;\n opId: string;\n status: \"failed\";\n error: string;\n };\n\n// Outcome of the housekeeping pass that retries earlier `submitting` rows\n// whose receipt arrived after the prior /v1/settle's wait budget elapsed.\nexport interface SettlePromoteResult {\n opType: SettleOpType;\n opId: string;\n status: \"confirmed\" | \"failed\" | \"pending\" | \"skipped\";\n txHash: string;\n chainBlockHeight: string | null;\n reason?: string;\n}\n\n// Outcome of the reconcile pass that advances 'confirmed' → 'finalized' once\n// the chain's finalized tip catches up past the tx's block (or reverts to\n// 'pending' on reorg detection).\nexport interface SettleReconcileItem {\n opId: string;\n status: \"finalized\" | \"reorged\" | \"unchanged\";\n chainBlockHeight: string | null;\n settleTxHash: string | null;\n reason?: string;\n}\n\nexport interface SettleParams {\n // Per-phase cap. Bounded by MAX_LIMIT on the gateway side; omit to use\n // the gateway's default BATCH_LIMIT.\n limit?: number;\n}\n\nexport interface SettleResult {\n scanned: number;\n submitted: number;\n confirmed: number;\n skipped: number;\n failed: number;\n items: SettleItem[];\n promoted: { count: number; items: SettlePromoteResult[] };\n reconciled: {\n scanned: number;\n finalized: number;\n reorged: number;\n unchanged: number;\n items: SettleReconcileItem[];\n };\n // Present only when the gateway is configured for paced submission —\n // spreads work across several blocks within one /v1/settle invocation.\n paced?: { iterations: number };\n}\n\n/**\n * Legacy `GatewayClient` name for the canonical `/v1/escrow/balance` response.\n * `availableAmount` is `max(balance − authorizedAmount − withdrawingAmount, 0)`.\n */\nexport type EscrowBalance = EscrowBalanceResult;\n\n// /v1/escrow/deposit announces an on-chain deposit tx so the gateway can\n// reconcile it into the payer's balance. The gateway extracts the credited\n// account from calldata — no off-chain claim about who paid.\nexport interface SubmitDepositParams {\n txHash: string;\n}\n\nexport interface DepositState {\n txHash: string;\n account: string;\n // 'submitted' | 'finalized' | 'failed' — kept open since the gateway adds\n // states (e.g. 'orphaned') as the deposit flow evolves.\n status: string;\n blockNumber: string | null;\n submittedAt: string;\n finalizedAt: string | null;\n lastError: string | null;\n}\n\nexport interface GatewayClient {\n isRegisteredBuilder(address: string): Promise<boolean>;\n getBuilder(address: string): Promise<Builder | null>;\n getGrant(grantId: string): Promise<GatewayGrantResponse | null>;\n listGrantsByUser(userAddress: string): Promise<GrantListItem[]>;\n getSchemaForScope(scope: string): Promise<Schema | null>;\n getServer(address: string): Promise<ServerInfo | null>;\n /**\n * List every personal server an owner has registered — split into `active`\n * (currently trusted) and `revoked` (deregistered). Each list is ordered\n * newest-first; `active[0]` is the sensible default when the caller just\n * needs one URL for the owner. Empty owner returns `{active: [], revoked: [], count: 0}`.\n * Discovery-only endpoint — no per-server attestation; use `getServer` for that.\n */\n listServersByOwner(owner: string): Promise<OwnerServersResult>;\n /**\n * Fetch a single data point by its deterministic id (keccak256 of (owner, scope)).\n * Returns null on 404. The gateway omits `status` from the response body — read it\n * from the on-chain DataRegistryV2 contract when you need the canonical lifecycle state.\n */\n getDataPoint(dataPointId: string): Promise<DataPointRecord | null>;\n /**\n * Page through an owner's data points. Cursor is opaque; pass `null` for the first\n * page and feed back `result.cursor` until it returns null.\n */\n listDataPointsByOwner(\n owner: string,\n cursor: string | null,\n options?: ListDataPointsOptions,\n ): Promise<DataPointListResult>;\n getSchema(schemaId: string): Promise<Schema | null>;\n registerServer(params: RegisterServerParams): Promise<RegisterServerResult>;\n registerBuilder(\n params: RegisterBuilderParams,\n ): Promise<RegisterBuilderResult>;\n registerDataPoint(\n params: RegisterDataPointParams,\n ): Promise<RegisterDataPointResult>;\n createGrant(params: CreateGrantParams): Promise<{ grantId?: string }>;\n revokeGrant(params: RevokeGrantParams): Promise<void>;\n getEscrowBalance(account: string): Promise<EscrowBalanceResult>;\n submitEscrowDeposit(params: SubmitDepositParams): Promise<DepositState>;\n payForOperation(\n params: PayForOperationParams,\n ): Promise<PayForOperationResult>;\n settle(params?: SettleParams): Promise<SettleResult>;\n}\n\nexport function createGatewayClient(baseUrl: string): GatewayClient {\n const base = baseUrl.replace(/\\/+$/, \"\");\n\n async function unwrapEnvelope<T>(res: Response): Promise<T> {\n const envelope = (await res.json()) as GatewayEnvelope<T>;\n return envelope.data;\n }\n\n function getMutationId(\n body: Record<string, unknown>,\n key: string,\n ): string | undefined {\n const value = body[key] ?? body[\"id\"];\n return typeof value === \"string\" ? value : undefined;\n }\n\n return {\n async isRegisteredBuilder(address: string): Promise<boolean> {\n const builder = await this.getBuilder(address);\n return builder !== null;\n },\n\n async getBuilder(address: string): Promise<Builder | null> {\n const res = await fetch(`${base}/v1/builders/${address}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Builder>(res);\n },\n\n async getGrant(grantId: string): Promise<GatewayGrantResponse | null> {\n const res = await fetch(`${base}/v1/grants/${grantId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<GatewayGrantResponse>(res);\n },\n\n async listGrantsByUser(userAddress: string): Promise<GrantListItem[]> {\n const res = await fetch(`${base}/v1/grants?user=${userAddress}`);\n if (res.status === 404) return [];\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<GrantListItem[]>(res);\n },\n\n async getSchemaForScope(scope: string): Promise<Schema | null> {\n const res = await fetch(`${base}/v1/schemas?scope=${scope}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Schema>(res);\n },\n\n async getServer(address: string): Promise<ServerInfo | null> {\n const res = await fetch(`${base}/v1/servers/${address}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<ServerInfo>(res);\n },\n\n async listServersByOwner(owner: string): Promise<OwnerServersResult> {\n // URLSearchParams encodes the owner so a malformed value (e.g.\n // \"0xabc&foo=bar\") can't inject extra query params. Same pattern as\n // listDataPointsByOwner.\n const params = new URLSearchParams({ owner });\n const res = await fetch(`${base}/v1/servers?${params.toString()}`);\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n // Unlike /v1/servers/:address, the list endpoint returns the body\n // directly — no GatewayEnvelope, no attestation (discovery-only).\n return (await res.json()) as OwnerServersResult;\n },\n\n async getDataPoint(dataPointId: string): Promise<DataPointRecord | null> {\n const res = await fetch(`${base}/v1/data/${dataPointId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<DataPointRecord>(res);\n },\n\n async listDataPointsByOwner(\n owner: string,\n cursor: string | null,\n options?: ListDataPointsOptions,\n ): Promise<DataPointListResult> {\n const params = new URLSearchParams({ user: owner });\n if (cursor !== null) {\n params.set(\"cursor\", cursor);\n }\n if (options?.since) {\n params.set(\"since\", options.since);\n }\n if (options?.limit !== undefined) {\n params.set(\"limit\", String(options.limit));\n }\n const res = await fetch(`${base}/v1/data?${params.toString()}`);\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n // Next-page cursor lives in the envelope's `pagination.nextCursor`\n // (a sibling of `data`), so read the full envelope rather than going\n // through `unwrapEnvelope`, which returns only `data`.\n const envelope = (await res.json()) as GatewayEnvelope<{\n dataPoints: DataPointRecord[];\n }>;\n const nextCursor =\n envelope.pagination?.hasMore === false\n ? null\n : (envelope.pagination?.nextCursor ?? null);\n return {\n dataPoints: envelope.data.dataPoints,\n cursor: nextCursor,\n };\n },\n\n async getSchema(schemaId: string): Promise<Schema | null> {\n const res = await fetch(`${base}/v1/schemas/${schemaId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Schema>(res);\n },\n\n async registerServer(\n params: RegisterServerParams,\n ): Promise<RegisterServerResult> {\n const res = await fetch(`${base}/v1/servers`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n serverAddress: params.serverAddress,\n publicKey: params.publicKey,\n serverUrl: params.serverUrl,\n }),\n });\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n serverId: getMutationId(body as Record<string, unknown>, \"serverId\"),\n alreadyRegistered: true,\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json().catch(() => ({}));\n return {\n serverId: getMutationId(body as Record<string, unknown>, \"serverId\"),\n alreadyRegistered: false,\n };\n },\n\n async registerBuilder(\n params: RegisterBuilderParams,\n ): Promise<RegisterBuilderResult> {\n const res = await fetch(`${base}/v1/builders`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n granteeAddress: params.granteeAddress,\n publicKey: params.publicKey,\n appUrl: params.appUrl,\n }),\n });\n // 409 is idempotent — the gateway's current 409 body doesn't include\n // the builderId, but we tolerate it in case that changes (mirrors the\n // registerServer / createGrant shape).\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n builderId: getMutationId(\n body as Record<string, unknown>,\n \"builderId\",\n ),\n alreadyRegistered: true,\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json().catch(() => ({}));\n return {\n builderId: getMutationId(body as Record<string, unknown>, \"builderId\"),\n alreadyRegistered: false,\n };\n },\n\n async registerDataPoint(\n params: RegisterDataPointParams,\n ): Promise<RegisterDataPointResult> {\n const res = await fetch(`${base}/v1/data`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n scope: params.scope,\n dataHash: params.dataHash,\n metadataHash: params.metadataHash,\n expectedVersion: params.expectedVersion,\n }),\n });\n // 409 is a real failure here (stale CAS), not an idempotent replay —\n // surface the gateway's error message verbatim so the caller knows\n // what `currentExpectedVersion` to re-sign against.\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as {\n error?: string;\n };\n const detail = body.error ?? res.statusText;\n throw new Error(`Gateway error: ${res.status} ${detail}`);\n }\n const body = (await res.json().catch(() => ({}))) as {\n dataPointId?: string;\n expectedVersion?: string;\n };\n return {\n dataPointId: getMutationId(\n body as Record<string, unknown>,\n \"dataPointId\",\n ),\n expectedVersion: body.expectedVersion,\n };\n },\n\n async createGrant(\n params: CreateGrantParams,\n ): Promise<{ grantId?: string }> {\n const res = await fetch(`${base}/v1/grants`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n grantorAddress: params.grantorAddress,\n granteeId: params.granteeId,\n scopes: params.scopes,\n grantVersion: params.grantVersion,\n expiresAt: params.expiresAt,\n }),\n });\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n grantId: getMutationId(body as Record<string, unknown>, \"grantId\"),\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json();\n return {\n grantId: getMutationId(body as Record<string, unknown>, \"grantId\"),\n };\n },\n\n async revokeGrant(params: RevokeGrantParams): Promise<void> {\n const res = await fetch(`${base}/v1/grants/${params.grantId}`, {\n method: \"DELETE\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n grantorAddress: params.grantorAddress,\n grantVersion: params.grantVersion,\n }),\n });\n if (res.status === 409) return;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n },\n\n async getEscrowBalance(account: string): Promise<EscrowBalanceResult> {\n const res = await fetch(`${base}/v1/escrow/balance?account=${account}`);\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n // Unlike the rest of /v1, the balance endpoint returns the body\n // directly (no GatewayEnvelope wrap) — it's a pure read with no\n // gateway-signed attestation. See data-gateway api/v1/escrow/balance.ts.\n return (await res.json()) as EscrowBalanceResult;\n },\n\n async submitEscrowDeposit(\n params: SubmitDepositParams,\n ): Promise<DepositState> {\n const res = await fetch(`${base}/v1/escrow/deposit`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ txHash: params.txHash }),\n });\n // The gateway returns 202 for \"accepted (still confirming)\" and 200 for\n // duplicate idempotent replays. Both carry the deposit's current state.\n if (res.status !== 200 && res.status !== 202) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as DepositState;\n },\n\n async payForOperation(\n params: PayForOperationParams,\n ): Promise<PayForOperationResult> {\n // Build the body without the accessRecord key when absent so the\n // gateway's \"missing optional\" branch matches the no-receipt case\n // exactly (an explicit `accessRecord: undefined` would JSON-serialize\n // to nothing — same result — but keeping it conditional makes wire\n // traces easier to read).\n const body: Record<string, unknown> = {\n payerAddress: params.payerAddress,\n opType: params.opType,\n opId: params.opId,\n asset: params.asset,\n amount: params.amount,\n paymentNonce: params.paymentNonce,\n };\n if (params.accessRecord) {\n body[\"accessRecord\"] = params.accessRecord;\n }\n const res = await fetch(`${base}/v1/escrow/pay`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as PayForOperationResult;\n },\n\n async settle(params?: SettleParams): Promise<SettleResult> {\n const res = await fetch(`${base}/v1/settle`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n // The gateway accepts an empty body; only `limit` is recognised.\n // Always send a JSON body so the gateway's req.body shape parse\n // doesn't have to deal with an undefined.\n body: JSON.stringify(params ?? {}),\n });\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as SettleResult;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkfO,SAAS,oBAAoB,SAAgC;AAClE,QAAM,OAAO,QAAQ,QAAQ,QAAQ,EAAE;AAEvC,iBAAe,eAAkB,KAA2B;AAC1D,UAAM,WAAY,MAAM,IAAI,KAAK;AACjC,WAAO,SAAS;AAAA,EAClB;AAEA,WAAS,cACP,MACA,KACoB;AACpB,UAAM,QAAQ,KAAK,GAAG,KAAK,KAAK,IAAI;AACpC,WAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,EAC7C;AAEA,SAAO;AAAA,IACL,MAAM,oBAAoB,SAAmC;AAC3D,YAAM,UAAU,MAAM,KAAK,WAAW,OAAO;AAC7C,aAAO,YAAY;AAAA,IACrB;AAAA,IAEA,MAAM,WAAW,SAA0C;AACzD,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,gBAAgB,OAAO,EAAE;AACxD,UAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,aAAO,eAAwB,GAAG;AAAA,IACpC;AAAA,IAEA,MAAM,SAAS,SAAuD;AACpE,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,cAAc,OAAO,EAAE;AACtD,UAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,aAAO,eAAqC,GAAG;AAAA,IACjD;AAAA,IAEA,MAAM,iBAAiB,aAA+C;AACpE,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,mBAAmB,WAAW,EAAE;AAC/D,UAAI,IAAI,WAAW,IAAK,QAAO,CAAC;AAChC,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,aAAO,eAAgC,GAAG;AAAA,IAC5C;AAAA,IAEA,MAAM,kBAAkB,OAAuC;AAC7D,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,qBAAqB,KAAK,EAAE;AAC3D,UAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,aAAO,eAAuB,GAAG;AAAA,IACnC;AAAA,IAEA,MAAM,UAAU,SAA6C;AAC3D,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,eAAe,OAAO,EAAE;AACvD,UAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,aAAO,eAA2B,GAAG;AAAA,IACvC;AAAA,IAEA,MAAM,mBAAmB,OAA4C;AAInE,YAAM,SAAS,IAAI,gBAAgB,EAAE,MAAM,CAAC;AAC5C,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,eAAe,OAAO,SAAS,CAAC,EAAE;AACjE,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AAGA,aAAQ,MAAM,IAAI,KAAK;AAAA,IACzB;AAAA,IAEA,MAAM,aAAa,aAAsD;AACvE,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,YAAY,WAAW,EAAE;AACxD,UAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,aAAO,eAAgC,GAAG;AAAA,IAC5C;AAAA,IAEA,MAAM,sBACJ,OACA,QACA,SAC8B;AAC9B,YAAM,SAAS,IAAI,gBAAgB,EAAE,MAAM,MAAM,CAAC;AAClD,UAAI,WAAW,MAAM;AACnB,eAAO,IAAI,UAAU,MAAM;AAAA,MAC7B;AACA,UAAI,SAAS,OAAO;AAClB,eAAO,IAAI,SAAS,QAAQ,KAAK;AAAA,MACnC;AACA,UAAI,SAAS,UAAU,QAAW;AAChC,eAAO,IAAI,SAAS,OAAO,QAAQ,KAAK,CAAC;AAAA,MAC3C;AACA,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,YAAY,OAAO,SAAS,CAAC,EAAE;AAC9D,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AAIA,YAAM,WAAY,MAAM,IAAI,KAAK;AAGjC,YAAM,aACJ,SAAS,YAAY,YAAY,QAC7B,OACC,SAAS,YAAY,cAAc;AAC1C,aAAO;AAAA,QACL,YAAY,SAAS,KAAK;AAAA,QAC1B,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IAEA,MAAM,UAAU,UAA0C;AACxD,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,eAAe,QAAQ,EAAE;AACxD,UAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,aAAO,eAAuB,GAAG;AAAA,IACnC;AAAA,IAEA,MAAM,eACJ,QAC+B;AAC/B,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,eAAe;AAAA,QAC5C,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,cAAc,OAAO,SAAS;AAAA,QAC/C;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,cAAc,OAAO;AAAA,UACrB,eAAe,OAAO;AAAA,UACtB,WAAW,OAAO;AAAA,UAClB,WAAW,OAAO;AAAA,QACpB,CAAC;AAAA,MACH,CAAC;AACD,UAAI,IAAI,WAAW,KAAK;AACtB,cAAMA,QAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,eAAO;AAAA,UACL,UAAU,cAAcA,OAAiC,UAAU;AAAA,UACnE,mBAAmB;AAAA,QACrB;AAAA,MACF;AACA,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,aAAO;AAAA,QACL,UAAU,cAAc,MAAiC,UAAU;AAAA,QACnE,mBAAmB;AAAA,MACrB;AAAA,IACF;AAAA,IAEA,MAAM,gBACJ,QACgC;AAChC,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,gBAAgB;AAAA,QAC7C,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,cAAc,OAAO,SAAS;AAAA,QAC/C;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,cAAc,OAAO;AAAA,UACrB,gBAAgB,OAAO;AAAA,UACvB,WAAW,OAAO;AAAA,UAClB,QAAQ,OAAO;AAAA,QACjB,CAAC;AAAA,MACH,CAAC;AAID,UAAI,IAAI,WAAW,KAAK;AACtB,cAAMA,QAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,eAAO;AAAA,UACL,WAAW;AAAA,YACTA;AAAA,YACA;AAAA,UACF;AAAA,UACA,mBAAmB;AAAA,QACrB;AAAA,MACF;AACA,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,aAAO;AAAA,QACL,WAAW,cAAc,MAAiC,WAAW;AAAA,QACrE,mBAAmB;AAAA,MACrB;AAAA,IACF;AAAA,IAEA,MAAM,kBACJ,QACkC;AAClC,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,YAAY;AAAA,QACzC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,cAAc,OAAO,SAAS;AAAA,QAC/C;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,cAAc,OAAO;AAAA,UACrB,OAAO,OAAO;AAAA,UACd,UAAU,OAAO;AAAA,UACjB,cAAc,OAAO;AAAA,UACrB,iBAAiB,OAAO;AAAA,QAC1B,CAAC;AAAA,MACH,CAAC;AAID,UAAI,CAAC,IAAI,IAAI;AACX,cAAMA,QAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAG/C,cAAM,SAASA,MAAK,SAAS,IAAI;AACjC,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,MAAM,EAAE;AAAA,MAC1D;AACA,YAAM,OAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAI/C,aAAO;AAAA,QACL,aAAa;AAAA,UACX;AAAA,UACA;AAAA,QACF;AAAA,QACA,iBAAiB,KAAK;AAAA,MACxB;AAAA,IACF;AAAA,IAEA,MAAM,YACJ,QAC+B;AAC/B,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,cAAc;AAAA,QAC3C,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,cAAc,OAAO,SAAS;AAAA,QAC/C;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,gBAAgB,OAAO;AAAA,UACvB,WAAW,OAAO;AAAA,UAClB,QAAQ,OAAO;AAAA,UACf,cAAc,OAAO;AAAA,UACrB,WAAW,OAAO;AAAA,QACpB,CAAC;AAAA,MACH,CAAC;AACD,UAAI,IAAI,WAAW,KAAK;AACtB,cAAMA,QAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,eAAO;AAAA,UACL,SAAS,cAAcA,OAAiC,SAAS;AAAA,QACnE;AAAA,MACF;AACA,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,aAAO;AAAA,QACL,SAAS,cAAc,MAAiC,SAAS;AAAA,MACnE;AAAA,IACF;AAAA,IAEA,MAAM,YAAY,QAA0C;AAC1D,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,cAAc,OAAO,OAAO,IAAI;AAAA,QAC7D,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,cAAc,OAAO,SAAS;AAAA,QAC/C;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,gBAAgB,OAAO;AAAA,UACvB,cAAc,OAAO;AAAA,QACvB,CAAC;AAAA,MACH,CAAC;AACD,UAAI,IAAI,WAAW,IAAK;AACxB,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AAAA,IACF;AAAA,IAEA,MAAM,iBAAiB,SAA+C;AACpE,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,8BAA8B,OAAO,EAAE;AACtE,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AAIA,aAAQ,MAAM,IAAI,KAAK;AAAA,IACzB;AAAA,IAEA,MAAM,oBACJ,QACuB;AACvB,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,sBAAsB;AAAA,QACnD,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,QAAQ,OAAO,OAAO,CAAC;AAAA,MAChD,CAAC;AAGD,UAAI,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;AAC5C,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,aAAQ,MAAM,IAAI,KAAK;AAAA,IACzB;AAAA,IAEA,MAAM,gBACJ,QACgC;AAMhC,YAAM,OAAgC;AAAA,QACpC,cAAc,OAAO;AAAA,QACrB,QAAQ,OAAO;AAAA,QACf,MAAM,OAAO;AAAA,QACb,OAAO,OAAO;AAAA,QACd,QAAQ,OAAO;AAAA,QACf,cAAc,OAAO;AAAA,MACvB;AACA,UAAI,OAAO,cAAc;AACvB,aAAK,cAAc,IAAI,OAAO;AAAA,MAChC;AACA,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,kBAAkB;AAAA,QAC/C,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,cAAc,OAAO,SAAS;AAAA,QAC/C;AAAA,QACA,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,aAAQ,MAAM,IAAI,KAAK;AAAA,IACzB;AAAA,IAEA,MAAM,OAAO,QAA8C;AACzD,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,cAAc;AAAA,QAC3C,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA;AAAA;AAAA;AAAA,QAI9C,MAAM,KAAK,UAAU,UAAU,CAAC,CAAC;AAAA,MACnC,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,MAClE;AACA,aAAQ,MAAM,IAAI,KAAK;AAAA,IACzB;AAAA,EACF;AACF;","names":["body"]}
|
|
1
|
+
{"version":3,"sources":["../../src/protocol/gateway.ts"],"sourcesContent":["export interface GatewayEnvelope<T> {\n data: T;\n proof: GatewayProof;\n /**\n * Cursor-based pagination metadata, present on list endpoints (e.g.\n * `GET /v1/data`). A sibling of `data`, not nested inside it — so callers\n * that need it must read the full envelope rather than going through\n * `unwrapEnvelope`, which intentionally returns only `data`.\n */\n pagination?: GatewayPagination;\n}\n\nexport interface GatewayPagination {\n limit: number;\n hasMore: boolean;\n /**\n * Opaque cursor for the NEXT page; pass back as the `cursor` query param.\n * Null when there are no further pages.\n */\n nextCursor: string | null;\n}\n\nexport interface GatewayProof {\n signature: string;\n timestamp: string;\n gatewayAddress: string;\n requestHash: string;\n responseHash: string;\n userSignature: string;\n status: string;\n chainBlockHeight: number;\n}\n\nexport interface Builder {\n id: string;\n ownerAddress: string;\n granteeAddress: string;\n publicKey: string;\n appUrl: string;\n addedAt: string;\n}\n\nexport interface Schema {\n id: string;\n ownerAddress: string;\n name: string;\n definitionUrl: string;\n scope: string;\n addedAt: string;\n}\n\n// Row shape returned by `GET /v1/servers?owner=…`. A discovery-only list —\n// the endpoint carries no per-item gateway attestation (use\n// `getServer(serverAddress)` if you need a verifiable single-server proof).\n// `status` is the gateway's chain-sync state ('pending' | 'confirmed' |\n// 'finalized' | 'reorged'); kept as an open string since the gateway may add\n// states without a SDK bump.\nexport interface OwnerServerRecord {\n id: string;\n ownerAddress: string;\n serverAddress: string;\n publicKey: string;\n serverUrl: string;\n status: string;\n chainBlockHeight: string | null;\n // ISO timestamp of the gateway-side upsert.\n addedAt: string;\n // ISO timestamp when the grantor deregistered this server. Always null for\n // entries in the `active` list, always non-null for `revoked`.\n revokedAt: string | null;\n}\n\n// Response from `GET /v1/servers?owner=…`. Split into two arrays; each is\n// ordered newest-first (`addedAt DESC`, `id ASC` tiebreaker) so `active[0]`\n// is unambiguously the newest active server — the sensible default when the\n// caller just needs one URL. The gateway caps the total across both arrays\n// at 200 — per-owner counts are tiny in practice, so no cursor.\nexport interface OwnerServersResult {\n active: OwnerServerRecord[];\n revoked: OwnerServerRecord[];\n count: number;\n}\n\nexport interface ServerInfo {\n id: string;\n ownerAddress: string;\n serverAddress: string;\n publicKey: string;\n serverUrl: string;\n addedAt: string;\n // ISO timestamp when the grantor deregistered this server, null while\n // active. The gateway returns this on /v1/servers/:address GETs since\n // covering revocation in the response keeps the attestation hash\n // authoritative for both states.\n revokedAt: string | null;\n}\n\n// Fee annotation surfaced on every GET grant response. Amounts are decimal\n// uint256 strings to match `/v1/escrow/pay`'s wire format. totalDue is a\n// snapshot — the gateway re-resolves fees at pay time, so clients shouldn't\n// cache this across requests.\nexport interface GatewayGrantFee {\n asset: string;\n registrationFee: string;\n dataAccessFee: string;\n totalDue: string;\n}\n\n// Lifecycle of a grant's on-chain settlement, tracked separately from the\n// fee-payment lifecycle (paymentStatus). Driven by POST /v1/settle:\n// pending — nothing on-chain yet\n// submitting — settle tx broadcast but receipt not yet observed\n// confirmed — settle tx mined successfully\n// finalized — finalized tip past the settle block, reorg-safe\n// reorged — finalized observation reverted; back to 'pending' on next settle\nexport type GatewayGrantStatus =\n | \"pending\"\n | \"submitting\"\n | \"confirmed\"\n | \"finalized\"\n | \"reorged\";\n\nexport interface GatewayGrantResponse {\n id: string;\n grantorAddress: string;\n granteeId: string;\n scopes: string[];\n status: GatewayGrantStatus;\n addedAt: string;\n // Grantor-signed deadline. null = perpetual grant (signed value was 0).\n expiresAt: string | null;\n // Derived at read time from expiresAt vs the gateway's clock — a snapshot,\n // not a cached truth. Re-check against expiresAt locally if you care.\n expired: boolean;\n revokedAt: string | null;\n revocationSignature: string | null;\n // 'pending' until the grant registration fee is settled via /v1/escrow/pay.\n paymentStatus: \"pending\" | \"paid\";\n paidAt: string | null;\n paidBy: string | null;\n // Decimal-string uint256 monotonic nonce; advances on every state change.\n grantVersion: string;\n // Settle metadata — populated as the grant progresses through the chain\n // lifecycle. Null while `status === 'pending'`.\n settleTxHash: string | null;\n settleSubmittedAt: string | null;\n // Revocation metadata — populated independently when the grantor signs\n // and the gateway pushes a deregister tx.\n revocationTxHash: string | null;\n revocationSubmittedAt: string | null;\n fee: GatewayGrantFee;\n}\n\nexport type GrantListItem = GatewayGrantResponse;\n\n// Mirror of a DataRegistryV2 row as the gateway exposes it. `id` is the\n// deterministic `keccak256(abi.encode(owner, scope))` dataPointId — the same\n// value the contract uses as its primary key. `expectedVersion` is the latest\n// version the gateway has accepted; the on-chain row may be one version behind\n// while a settle is still pending. The gateway response intentionally drops\n// `status` from the body — read it from the on-chain contract when you need\n// the canonical lifecycle state.\nexport interface DataPointRecord {\n id: string;\n ownerAddress: string;\n scope: string;\n dataHash: string;\n metadataHash: string;\n // Decimal-string uint256.\n expectedVersion: string;\n // ISO 8601 timestamp of the most recent gateway-side upsert.\n addedAt: string;\n}\n\nexport interface DataPointListResult {\n dataPoints: DataPointRecord[];\n cursor: string | null;\n}\n\nexport interface ListDataPointsOptions {\n /**\n * Only return rows added at or after this ISO 8601 timestamp. Used by sync\n * loops that want incremental tails — pass the last seen `addedAt`.\n */\n since?: string;\n /** Page size. Capped at 1000 by the gateway. */\n limit?: number;\n}\n\n// grantVersion and expiresAt are decimal-string uint256s — same wire format\n// the gateway expects. The caller is responsible for converting their bigint\n// to a decimal string and for signing GRANT_REGISTRATION_TYPES with matching\n// bigint values.\nexport interface CreateGrantParams {\n grantorAddress: string;\n granteeId: string;\n scopes: string[];\n grantVersion: string;\n expiresAt: string;\n signature: string;\n}\n\nexport interface RevokeGrantParams {\n grantId: string;\n grantorAddress: string;\n grantVersion: string;\n signature: string;\n}\n\nexport interface RegisterServerParams {\n ownerAddress: string;\n serverAddress: string;\n publicKey: string;\n serverUrl: string;\n signature: string;\n}\n\nexport interface RegisterServerResult {\n serverId?: string;\n alreadyRegistered: boolean;\n}\n\nexport interface RegisterBuilderParams {\n ownerAddress: string;\n // Wallet the builder authenticates to the Personal Server with. The\n // builderId is deterministically derived from (owner, grantee, publicKey,\n // appUrl) so this triple pins the on-chain identity.\n granteeAddress: string;\n publicKey: string;\n appUrl: string;\n signature: string;\n}\n\nexport interface RegisterBuilderResult {\n builderId?: string;\n alreadyRegistered: boolean;\n}\n\n// AddData on DataRegistryV2. dataHash + metadataHash are bytes32 commitments\n// to the off-chain payload + its metadata. expectedVersion is a CAS knob —\n// the gateway/contract rejects on 409 if a higher version is already stored,\n// and the error body surfaces `currentExpectedVersion` so callers can re-sign.\nexport interface RegisterDataPointParams {\n ownerAddress: string;\n scope: string;\n dataHash: string;\n metadataHash: string;\n expectedVersion: string;\n signature: string;\n}\n\nexport interface RegisterDataPointResult {\n dataPointId?: string;\n expectedVersion?: string;\n}\n\n// ── Escrow / data-access payment path ───────────────────────────────────────\n// /v1/escrow/pay debits the payer's escrow balance for a payable op. For a\n// Legacy grants use opType='grant' and opId=grantId. Standalone receipt-bound\n// reads use opType='data_access' and opId=accessRecord.recordId. amount and\n// paymentNonce are decimal uint256 strings on the wire. The signature is the\n// raw EIP-712 hex of GENERIC_PAYMENT_TYPES against escrowPaymentDomain.\n\n// A server-signed delivery receipt attached to a data-access payment. The\n// signature is over RECORD_DATA_ACCESS_TYPES against dataRegistryDomain; the\n// signer must be a personal server the data point's owner has registered as\n// trusted. Shape validation in clients does not verify this signature; the\n// gateway verifies it before re-using it on-chain in the next /v1/settle pass\n// via DataRegistryV2.recordDataAccess, where `recordId` dedupes via\n// `_usedRecordIds`.\nexport interface AccessRecord {\n dataPointId: string;\n // Decimal-string uint256 — the data point version being attested to.\n version: string;\n // Must equal the enclosing payment's payerAddress (the gateway enforces).\n accessor: string;\n recordId: string;\n signature: string;\n}\n\nexport interface PayForOperationParams {\n payerAddress: string;\n opType: string;\n opId: string;\n asset: string;\n amount: string;\n // Per-payer monotonic; (payer, nonce, kind) must be unique. The gateway\n // returns 409 if reused — bump and re-sign.\n paymentNonce: string;\n signature: string;\n // Optional: attach a server-signed access record so the next /v1/settle\n // pass submits a recordDataAccess tx alongside the payment settlement.\n // Required for data-access payments (the second-and-onward payments per\n // grant) that want their on-chain `totalAccesses` counter to advance.\n accessRecord?: AccessRecord;\n}\n\nexport interface PayForOperationResult {\n opType: string;\n opId: string;\n payerAddress: string;\n asset: string;\n amount: string;\n // Echoes how the gateway split this payment. `registrationPaid` is true on\n // the first payment for a grant (which bundles both fees) and false on\n // subsequent data-access-only payments. Off-chain ledger state only — the\n // on-chain settlement of the registration is tracked by the grant's\n // `status` field, not this flag.\n breakdown: {\n registrationFee: string;\n dataAccessFee: string;\n registrationPaid: boolean;\n };\n paymentNonce: string;\n paidAt: string;\n}\n\n// ── Settle / reconcile ──────────────────────────────────────────────────────\n// POST /v1/settle drains pending-on-chain rows (grants, servers, builders,\n// data points, data-point statuses, access records) to the relayer, then\n// promotes 'submitting' → 'confirmed' and 'confirmed' → 'finalized' for\n// previously-submitted rows. One call does all three; the response surfaces\n// each phase's outcomes.\n\n// The op-types the settle endpoint emits in `items[]`. Kept as a union so\n// callers can narrow inside the discriminated SettleItem shape. Mirrors the\n// gateway's drain phases (drainGrants/drainServers/drainBuilders/\n// drainDataPoints/drainDataPointStatuses/drainAccessRecords) — keep in sync\n// when the gateway adds a drain.\nexport type SettleOpType =\n | \"grant\"\n | \"server\"\n | \"data\"\n | \"access\"\n | \"builder\"\n | \"data-status\";\n\nexport type SettleItem =\n | {\n opType: SettleOpType;\n opId: string;\n // 'confirmed' when the submit function waited for the receipt and it\n // mined (registerAndSettle path); 'submitting' when only the tx was\n // sent (no receipt wait).\n status: \"submitting\" | \"confirmed\";\n settleTxHash: string | null;\n settleSubmittedAt: string | null;\n // Block height the tx mined in; only set when status === 'confirmed'.\n chainBlockHeight: string | null;\n revocationTxHash: string | null;\n revocationSubmittedAt: string | null;\n // True while lib/settle.ts is in placeholder mode for this row's pass.\n placeholder: boolean;\n }\n | {\n opType: SettleOpType;\n opId: string;\n status: \"skipped\";\n reason: string;\n }\n | {\n opType: SettleOpType;\n opId: string;\n status: \"failed\";\n error: string;\n };\n\n// Outcome of the housekeeping pass that retries earlier `submitting` rows\n// whose receipt arrived after the prior /v1/settle's wait budget elapsed.\nexport interface SettlePromoteResult {\n opType: SettleOpType;\n opId: string;\n status: \"confirmed\" | \"failed\" | \"pending\" | \"skipped\";\n txHash: string;\n chainBlockHeight: string | null;\n reason?: string;\n}\n\n// Outcome of the reconcile pass that advances 'confirmed' → 'finalized' once\n// the chain's finalized tip catches up past the tx's block (or reverts to\n// 'pending' on reorg detection).\nexport interface SettleReconcileItem {\n opId: string;\n status: \"finalized\" | \"reorged\" | \"unchanged\";\n chainBlockHeight: string | null;\n settleTxHash: string | null;\n reason?: string;\n}\n\nexport interface SettleParams {\n // Per-phase cap. Bounded by MAX_LIMIT on the gateway side; omit to use\n // the gateway's default BATCH_LIMIT.\n limit?: number;\n}\n\nexport interface SettleResult {\n scanned: number;\n submitted: number;\n confirmed: number;\n skipped: number;\n failed: number;\n items: SettleItem[];\n promoted: { count: number; items: SettlePromoteResult[] };\n reconciled: {\n scanned: number;\n finalized: number;\n reorged: number;\n unchanged: number;\n items: SettleReconcileItem[];\n };\n // Present only when the gateway is configured for paced submission —\n // spreads work across several blocks within one /v1/settle invocation.\n paced?: { iterations: number };\n}\n\n// /v1/escrow/balance?account=... — pure read. Returns finalized balances by\n// asset, plus the lifecycle breakdown of deposits.\nexport interface EscrowBalanceEntry {\n asset: string;\n // Gross credited deposits for (account, asset). Decremented only when the\n // reconcile pass marks a payment finalized — NOT on /v1/escrow/pay.\n balance: string;\n // Sum of claimedAmount for deposits still in 'submitted' status — surfaced\n // separately so clients don't conflate \"credited\" with \"deposit announced\n // but not yet confirmed.\"\n pendingAmount: string;\n // Sum of payments.amount for (account, asset) regardless of settled status —\n // mirrors the /v1/escrow/pay handler's soft-lock counter. Subtract from\n // `balance` to see how much the payer can still authorise.\n authorizedAmount: string;\n // `max(balance − authorizedAmount, 0)`. The headroom a payer has against\n // the soft-lock before /v1/escrow/pay starts returning 402.\n availableAmount: string;\n updatedAt: string | null;\n}\n\nexport interface EscrowDepositSubmitted {\n txHash: string;\n submittedAt: string;\n claimedAsset: string;\n claimedAmount: string;\n}\n\nexport interface EscrowDepositFinalized {\n txHash: string;\n finalizedAt: string | null;\n blockNumber: string | null;\n claimedAsset: string;\n claimedAmount: string;\n}\n\nexport interface EscrowDepositFailed {\n txHash: string;\n submittedAt: string;\n claimedAsset: string;\n claimedAmount: string;\n lastError: string | null;\n}\n\nexport interface EscrowBalance {\n account: string;\n balances: EscrowBalanceEntry[];\n deposits: {\n submitted: EscrowDepositSubmitted[];\n finalized: EscrowDepositFinalized[];\n failed: EscrowDepositFailed[];\n };\n}\n\n// /v1/escrow/deposit announces an on-chain deposit tx so the gateway can\n// reconcile it into the payer's balance. The gateway extracts the credited\n// account from calldata — no off-chain claim about who paid.\nexport interface SubmitDepositParams {\n txHash: string;\n}\n\nexport interface DepositState {\n txHash: string;\n account: string;\n // 'submitted' | 'finalized' | 'failed' — kept open since the gateway adds\n // states (e.g. 'orphaned') as the deposit flow evolves.\n status: string;\n blockNumber: string | null;\n submittedAt: string;\n finalizedAt: string | null;\n lastError: string | null;\n}\n\nexport interface GatewayClient {\n isRegisteredBuilder(address: string): Promise<boolean>;\n getBuilder(address: string): Promise<Builder | null>;\n getGrant(grantId: string): Promise<GatewayGrantResponse | null>;\n listGrantsByUser(userAddress: string): Promise<GrantListItem[]>;\n getSchemaForScope(scope: string): Promise<Schema | null>;\n getServer(address: string): Promise<ServerInfo | null>;\n /**\n * List every personal server an owner has registered — split into `active`\n * (currently trusted) and `revoked` (deregistered). Each list is ordered\n * newest-first; `active[0]` is the sensible default when the caller just\n * needs one URL for the owner. Empty owner returns `{active: [], revoked: [], count: 0}`.\n * Discovery-only endpoint — no per-server attestation; use `getServer` for that.\n */\n listServersByOwner(owner: string): Promise<OwnerServersResult>;\n /**\n * Fetch a single data point by its deterministic id (keccak256 of (owner, scope)).\n * Returns null on 404. The gateway omits `status` from the response body — read it\n * from the on-chain DataRegistryV2 contract when you need the canonical lifecycle state.\n */\n getDataPoint(dataPointId: string): Promise<DataPointRecord | null>;\n /**\n * Page through an owner's data points. Cursor is opaque; pass `null` for the first\n * page and feed back `result.cursor` until it returns null.\n */\n listDataPointsByOwner(\n owner: string,\n cursor: string | null,\n options?: ListDataPointsOptions,\n ): Promise<DataPointListResult>;\n getSchema(schemaId: string): Promise<Schema | null>;\n registerServer(params: RegisterServerParams): Promise<RegisterServerResult>;\n registerBuilder(\n params: RegisterBuilderParams,\n ): Promise<RegisterBuilderResult>;\n registerDataPoint(\n params: RegisterDataPointParams,\n ): Promise<RegisterDataPointResult>;\n createGrant(params: CreateGrantParams): Promise<{ grantId?: string }>;\n revokeGrant(params: RevokeGrantParams): Promise<void>;\n getEscrowBalance(account: string): Promise<EscrowBalance>;\n submitEscrowDeposit(params: SubmitDepositParams): Promise<DepositState>;\n payForOperation(\n params: PayForOperationParams,\n ): Promise<PayForOperationResult>;\n settle(params?: SettleParams): Promise<SettleResult>;\n}\n\nexport function createGatewayClient(baseUrl: string): GatewayClient {\n const base = baseUrl.replace(/\\/+$/, \"\");\n\n async function unwrapEnvelope<T>(res: Response): Promise<T> {\n const envelope = (await res.json()) as GatewayEnvelope<T>;\n return envelope.data;\n }\n\n function getMutationId(\n body: Record<string, unknown>,\n key: string,\n ): string | undefined {\n const value = body[key] ?? body[\"id\"];\n return typeof value === \"string\" ? value : undefined;\n }\n\n return {\n async isRegisteredBuilder(address: string): Promise<boolean> {\n const builder = await this.getBuilder(address);\n return builder !== null;\n },\n\n async getBuilder(address: string): Promise<Builder | null> {\n const res = await fetch(`${base}/v1/builders/${address}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Builder>(res);\n },\n\n async getGrant(grantId: string): Promise<GatewayGrantResponse | null> {\n const res = await fetch(`${base}/v1/grants/${grantId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<GatewayGrantResponse>(res);\n },\n\n async listGrantsByUser(userAddress: string): Promise<GrantListItem[]> {\n const res = await fetch(`${base}/v1/grants?user=${userAddress}`);\n if (res.status === 404) return [];\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<GrantListItem[]>(res);\n },\n\n async getSchemaForScope(scope: string): Promise<Schema | null> {\n const res = await fetch(`${base}/v1/schemas?scope=${scope}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Schema>(res);\n },\n\n async getServer(address: string): Promise<ServerInfo | null> {\n const res = await fetch(`${base}/v1/servers/${address}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<ServerInfo>(res);\n },\n\n async listServersByOwner(owner: string): Promise<OwnerServersResult> {\n // URLSearchParams encodes the owner so a malformed value (e.g.\n // \"0xabc&foo=bar\") can't inject extra query params. Same pattern as\n // listDataPointsByOwner.\n const params = new URLSearchParams({ owner });\n const res = await fetch(`${base}/v1/servers?${params.toString()}`);\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n // Unlike /v1/servers/:address, the list endpoint returns the body\n // directly — no GatewayEnvelope, no attestation (discovery-only).\n return (await res.json()) as OwnerServersResult;\n },\n\n async getDataPoint(dataPointId: string): Promise<DataPointRecord | null> {\n const res = await fetch(`${base}/v1/data/${dataPointId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<DataPointRecord>(res);\n },\n\n async listDataPointsByOwner(\n owner: string,\n cursor: string | null,\n options?: ListDataPointsOptions,\n ): Promise<DataPointListResult> {\n const params = new URLSearchParams({ user: owner });\n if (cursor !== null) {\n params.set(\"cursor\", cursor);\n }\n if (options?.since) {\n params.set(\"since\", options.since);\n }\n if (options?.limit !== undefined) {\n params.set(\"limit\", String(options.limit));\n }\n const res = await fetch(`${base}/v1/data?${params.toString()}`);\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n // Next-page cursor lives in the envelope's `pagination.nextCursor`\n // (a sibling of `data`), so read the full envelope rather than going\n // through `unwrapEnvelope`, which returns only `data`.\n const envelope = (await res.json()) as GatewayEnvelope<{\n dataPoints: DataPointRecord[];\n }>;\n const nextCursor =\n envelope.pagination?.hasMore === false\n ? null\n : (envelope.pagination?.nextCursor ?? null);\n return {\n dataPoints: envelope.data.dataPoints,\n cursor: nextCursor,\n };\n },\n\n async getSchema(schemaId: string): Promise<Schema | null> {\n const res = await fetch(`${base}/v1/schemas/${schemaId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Schema>(res);\n },\n\n async registerServer(\n params: RegisterServerParams,\n ): Promise<RegisterServerResult> {\n const res = await fetch(`${base}/v1/servers`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n serverAddress: params.serverAddress,\n publicKey: params.publicKey,\n serverUrl: params.serverUrl,\n }),\n });\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n serverId: getMutationId(body as Record<string, unknown>, \"serverId\"),\n alreadyRegistered: true,\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json().catch(() => ({}));\n return {\n serverId: getMutationId(body as Record<string, unknown>, \"serverId\"),\n alreadyRegistered: false,\n };\n },\n\n async registerBuilder(\n params: RegisterBuilderParams,\n ): Promise<RegisterBuilderResult> {\n const res = await fetch(`${base}/v1/builders`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n granteeAddress: params.granteeAddress,\n publicKey: params.publicKey,\n appUrl: params.appUrl,\n }),\n });\n // 409 is idempotent — the gateway's current 409 body doesn't include\n // the builderId, but we tolerate it in case that changes (mirrors the\n // registerServer / createGrant shape).\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n builderId: getMutationId(\n body as Record<string, unknown>,\n \"builderId\",\n ),\n alreadyRegistered: true,\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json().catch(() => ({}));\n return {\n builderId: getMutationId(body as Record<string, unknown>, \"builderId\"),\n alreadyRegistered: false,\n };\n },\n\n async registerDataPoint(\n params: RegisterDataPointParams,\n ): Promise<RegisterDataPointResult> {\n const res = await fetch(`${base}/v1/data`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n scope: params.scope,\n dataHash: params.dataHash,\n metadataHash: params.metadataHash,\n expectedVersion: params.expectedVersion,\n }),\n });\n // 409 is a real failure here (stale CAS), not an idempotent replay —\n // surface the gateway's error message verbatim so the caller knows\n // what `currentExpectedVersion` to re-sign against.\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as {\n error?: string;\n };\n const detail = body.error ?? res.statusText;\n throw new Error(`Gateway error: ${res.status} ${detail}`);\n }\n const body = (await res.json().catch(() => ({}))) as {\n dataPointId?: string;\n expectedVersion?: string;\n };\n return {\n dataPointId: getMutationId(\n body as Record<string, unknown>,\n \"dataPointId\",\n ),\n expectedVersion: body.expectedVersion,\n };\n },\n\n async createGrant(\n params: CreateGrantParams,\n ): Promise<{ grantId?: string }> {\n const res = await fetch(`${base}/v1/grants`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n grantorAddress: params.grantorAddress,\n granteeId: params.granteeId,\n scopes: params.scopes,\n grantVersion: params.grantVersion,\n expiresAt: params.expiresAt,\n }),\n });\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n grantId: getMutationId(body as Record<string, unknown>, \"grantId\"),\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json();\n return {\n grantId: getMutationId(body as Record<string, unknown>, \"grantId\"),\n };\n },\n\n async revokeGrant(params: RevokeGrantParams): Promise<void> {\n const res = await fetch(`${base}/v1/grants/${params.grantId}`, {\n method: \"DELETE\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n grantorAddress: params.grantorAddress,\n grantVersion: params.grantVersion,\n }),\n });\n if (res.status === 409) return;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n },\n\n async getEscrowBalance(account: string): Promise<EscrowBalance> {\n const res = await fetch(`${base}/v1/escrow/balance?account=${account}`);\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n // Unlike the rest of /v1, the balance endpoint returns the body\n // directly (no GatewayEnvelope wrap) — it's a pure read with no\n // gateway-signed attestation. See data-gateway api/v1/escrow/balance.ts.\n return (await res.json()) as EscrowBalance;\n },\n\n async submitEscrowDeposit(\n params: SubmitDepositParams,\n ): Promise<DepositState> {\n const res = await fetch(`${base}/v1/escrow/deposit`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ txHash: params.txHash }),\n });\n // The gateway returns 202 for \"accepted (still confirming)\" and 200 for\n // duplicate idempotent replays. Both carry the deposit's current state.\n if (res.status !== 200 && res.status !== 202) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as DepositState;\n },\n\n async payForOperation(\n params: PayForOperationParams,\n ): Promise<PayForOperationResult> {\n // Build the body without the accessRecord key when absent so the\n // gateway's \"missing optional\" branch matches the no-receipt case\n // exactly (an explicit `accessRecord: undefined` would JSON-serialize\n // to nothing — same result — but keeping it conditional makes wire\n // traces easier to read).\n const body: Record<string, unknown> = {\n payerAddress: params.payerAddress,\n opType: params.opType,\n opId: params.opId,\n asset: params.asset,\n amount: params.amount,\n paymentNonce: params.paymentNonce,\n };\n if (params.accessRecord) {\n body[\"accessRecord\"] = params.accessRecord;\n }\n const res = await fetch(`${base}/v1/escrow/pay`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as PayForOperationResult;\n },\n\n async settle(params?: SettleParams): Promise<SettleResult> {\n const res = await fetch(`${base}/v1/settle`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n // The gateway accepts an empty body; only `limit` is recognised.\n // Always send a JSON body so the gateway's req.body shape parse\n // doesn't have to deal with an undefined.\n body: JSON.stringify(params ?? {}),\n });\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as SettleResult;\n },\n };\n}\n"],"mappings":"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","names":["body"]}
|