@opendatalabs/vana-sdk 4.1.0 → 4.3.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.
Files changed (46) hide show
  1. package/README.md +47 -0
  2. package/dist/direct/access-request-client.cjs +3 -0
  3. package/dist/direct/access-request-client.cjs.map +1 -1
  4. package/dist/direct/access-request-client.js +3 -0
  5. package/dist/direct/access-request-client.js.map +1 -1
  6. package/dist/direct/controller.cjs +43 -2
  7. package/dist/direct/controller.cjs.map +1 -1
  8. package/dist/direct/controller.d.ts +33 -0
  9. package/dist/direct/controller.js +46 -2
  10. package/dist/direct/controller.js.map +1 -1
  11. package/dist/direct/grant-union.cjs +129 -0
  12. package/dist/direct/grant-union.cjs.map +1 -0
  13. package/dist/direct/grant-union.d.ts +138 -0
  14. package/dist/direct/grant-union.js +102 -0
  15. package/dist/direct/grant-union.js.map +1 -0
  16. package/dist/direct/grant-union.test.d.ts +1 -0
  17. package/dist/direct/types.cjs.map +1 -1
  18. package/dist/direct/types.d.ts +43 -0
  19. package/dist/direct/types.js.map +1 -1
  20. package/dist/errors.cjs +2 -2
  21. package/dist/errors.cjs.map +1 -1
  22. package/dist/errors.d.ts +7 -1
  23. package/dist/errors.js +2 -2
  24. package/dist/errors.js.map +1 -1
  25. package/dist/index.browser.d.ts +2 -1
  26. package/dist/index.browser.js +99 -0
  27. package/dist/index.browser.js.map +3 -3
  28. package/dist/index.node.cjs +945 -418
  29. package/dist/index.node.cjs.map +4 -4
  30. package/dist/index.node.d.ts +2 -1
  31. package/dist/index.node.js +801 -276
  32. package/dist/index.node.js.map +4 -4
  33. package/dist/protocol/jobs-client.cjs +196 -25
  34. package/dist/protocol/jobs-client.cjs.map +1 -1
  35. package/dist/protocol/jobs-client.d.ts +39 -1
  36. package/dist/protocol/jobs-client.js +199 -26
  37. package/dist/protocol/jobs-client.js.map +1 -1
  38. package/dist/protocol/jobs.cjs.map +1 -1
  39. package/dist/protocol/jobs.d.ts +71 -1
  40. package/dist/protocol/jobs.js.map +1 -1
  41. package/dist/server.cjs +9 -0
  42. package/dist/server.cjs.map +1 -1
  43. package/dist/server.d.ts +2 -1
  44. package/dist/server.js +10 -0
  45. package/dist/server.js.map +1 -1
  46. package/package.json +1 -1
@@ -32288,7 +32288,9 @@ import {
32288
32288
  bytesToHex as bytesToHex3,
32289
32289
  isAddress as isAddress2,
32290
32290
  isAddressEqual as isAddressEqual2,
32291
- isHex as isHex2
32291
+ isHex as isHex3,
32292
+ keccak256 as keccak2562,
32293
+ toHex as toHex9
32292
32294
  } from "viem";
32293
32295
  import { privateKeyToAccount, publicKeyToAddress as publicKeyToAddress2 } from "viem/accounts";
32294
32296
 
@@ -33077,6 +33079,517 @@ import {
33077
33079
  JobTransportError,
33078
33080
  OwnerNotReadyError
33079
33081
  } from "./errors.js";
33082
+ import { PaymentRequiredError } from "./direct/errors.js";
33083
+
33084
+ // src/config/contracts.config.ts
33085
+ var CONTRACTS2 = {
33086
+ // ========================================
33087
+ // DATA PORTABILITY CONTRACTS
33088
+ // ========================================
33089
+ DataPortabilityEscrow: {
33090
+ addresses: {
33091
+ 14800: "0x07d7769081adc3a3DBe91f5E4B98E9A5a6B292e3",
33092
+ 1480: "0x07d7769081adc3a3DBe91f5E4B98E9A5a6B292e3"
33093
+ }
33094
+ },
33095
+ FeeRegistry: {
33096
+ addresses: {
33097
+ 14800: "0xb4FA18443E0FA6cdC0280D20b8cCDB2377D13Bf2",
33098
+ 1480: "0xb4FA18443E0FA6cdC0280D20b8cCDB2377D13Bf2"
33099
+ }
33100
+ },
33101
+ // V2 deployment (DataPortabilityPermissionsV2Proxy). The gateway is the source
33102
+ // of truth for which deployment is live; verify with
33103
+ // `cast call <address> "eip712Domain()(bytes1,string,string,uint256,address,bytes32,uint256[])"`
33104
+ // which must return the domain name "Vana Data Portability".
33105
+ DataPortabilityPermissions: {
33106
+ addresses: {
33107
+ 14800: "0x4d3FA76064D88e0454cFc4CaD7e5FeC3e3124011",
33108
+ 1480: "0x4d3FA76064D88e0454cFc4CaD7e5FeC3e3124011"
33109
+ }
33110
+ },
33111
+ // V2 deployment (DataPortabilityServersV2Proxy) on both chains.
33112
+ DataPortabilityServers: {
33113
+ addresses: {
33114
+ 14800: "0xCae2CE0e9caa6643ed28186cF57bd40Bd9E17Eab",
33115
+ 1480: "0xCae2CE0e9caa6643ed28186cF57bd40Bd9E17Eab"
33116
+ }
33117
+ },
33118
+ DataPortabilityGrantees: {
33119
+ addresses: {
33120
+ 14800: "0x8325C0A0948483EdA023A1A2Fd895e62C5131234",
33121
+ 1480: "0x8325C0A0948483EdA023A1A2Fd895e62C5131234"
33122
+ }
33123
+ },
33124
+ DataRegistry: {
33125
+ addresses: {
33126
+ 14800: "0x8C8788f98385F6ba1adD4234e551ABba0f82Cb7C",
33127
+ 1480: "0x8C8788f98385F6ba1adD4234e551ABba0f82Cb7C"
33128
+ }
33129
+ },
33130
+ // ========================================
33131
+ // COMPUTING INFRASTRUCTURE
33132
+ // ========================================
33133
+ ComputeEngine: {
33134
+ addresses: {
33135
+ 14800: "0xb2BFe33FA420c45F1Cf1287542ad81ae935447bd",
33136
+ 1480: "0xb2BFe33FA420c45F1Cf1287542ad81ae935447bd"
33137
+ }
33138
+ },
33139
+ ComputeEngineTreasury: {
33140
+ addresses: {
33141
+ 14800: "0xceB33C501B624D984bD1Ed3298f6D1d8F7CE03d1",
33142
+ 1480: "0xceB33C501B624D984bD1Ed3298f6D1d8F7CE03d1"
33143
+ },
33144
+ discovery: {
33145
+ parent: "ComputeEngine",
33146
+ getter: "computeEngineTreasury"
33147
+ }
33148
+ },
33149
+ QueryEngine: {
33150
+ addresses: {
33151
+ 14800: "0xd25Eb66EA2452cf3238A2eC6C1FD1B7F5B320490",
33152
+ 1480: "0xd25Eb66EA2452cf3238A2eC6C1FD1B7F5B320490"
33153
+ }
33154
+ },
33155
+ VanaTreasury: {
33156
+ addresses: {
33157
+ 14800: "0x8B32Ef32f22e72cc25D53f6E858f57cAe7E198f9",
33158
+ 1480: "0x8B32Ef32f22e72cc25D53f6E858f57cAe7E198f9"
33159
+ },
33160
+ discovery: {
33161
+ parent: "QueryEngine",
33162
+ getter: "queryEngineTreasury"
33163
+ }
33164
+ },
33165
+ DataRefinerRegistry: {
33166
+ addresses: {
33167
+ 14800: "0x93c3EF89369fDcf08Be159D9DeF0F18AB6Be008c",
33168
+ 1480: "0x93c3EF89369fDcf08Be159D9DeF0F18AB6Be008c"
33169
+ }
33170
+ },
33171
+ ComputeInstructionRegistry: {
33172
+ addresses: {
33173
+ 14800: "0x5786B12b4c6Ba2bFAF0e77Ed30Bf6d32805563A5",
33174
+ 1480: "0x5786B12b4c6Ba2bFAF0e77Ed30Bf6d32805563A5"
33175
+ }
33176
+ },
33177
+ // ========================================
33178
+ // TEE POOLS (Canonical Deployments)
33179
+ // ========================================
33180
+ TeePoolPhala: {
33181
+ addresses: {
33182
+ 14800: "0xE8EC6BD73b23Ad40E6B9a6f4bD343FAc411bD99A",
33183
+ 1480: "0xE8EC6BD73b23Ad40E6B9a6f4bD343FAc411bD99A"
33184
+ }
33185
+ },
33186
+ TeePoolEphemeralStandard: {
33187
+ addresses: {
33188
+ 14800: "0xe124bae846D5ec157f75Bd9e68ca87C4d2AB835A",
33189
+ 1480: "0xe124bae846D5ec157f75Bd9e68ca87C4d2AB835A"
33190
+ }
33191
+ },
33192
+ TeePoolPersistentStandard: {
33193
+ addresses: {
33194
+ 14800: "0xe8bB8d0629651Cf33e0845d743976Dc1f0971d76",
33195
+ 1480: "0xe8bB8d0629651Cf33e0845d743976Dc1f0971d76"
33196
+ }
33197
+ },
33198
+ TeePoolPersistentGpu: {
33199
+ addresses: {
33200
+ 14800: "0x1c346Cd74f8551f8fa13f3F4b6b8dAE22338E6a9",
33201
+ 1480: "0x1c346Cd74f8551f8fa13f3F4b6b8dAE22338E6a9"
33202
+ }
33203
+ },
33204
+ TeePoolDedicatedStandard: {
33205
+ addresses: {
33206
+ 14800: "0xf024b7ac5E8417416f53B41ecfa58C8e9396687d",
33207
+ 1480: "0xf024b7ac5E8417416f53B41ecfa58C8e9396687d"
33208
+ }
33209
+ },
33210
+ TeePoolDedicatedGpu: {
33211
+ addresses: {
33212
+ 14800: "0xB1686FA9620bBf851714d1cB47b8a4Bf4664644E",
33213
+ 1480: "0xB1686FA9620bBf851714d1cB47b8a4Bf4664644E"
33214
+ }
33215
+ },
33216
+ // ========================================
33217
+ // VANA EPOCH / DLP REGISTRY
33218
+ // ========================================
33219
+ // Note: DLP rewards-specific contracts (DLPPerformance, DLPRewardDeployer,
33220
+ // DLPRewardDeployerTreasury, DLPRewardSwap, SwapHelper) were removed in the
33221
+ // protocol unification cleanup. VanaEpoch, DLPRegistry, and DLPRegistryTreasury
33222
+ // are kept because they may be referenced beyond the rewards system.
33223
+ VanaEpoch: {
33224
+ addresses: {
33225
+ 14800: "0x2063cFF0609D59bCCc196E20Eb58A8696a6b15A0",
33226
+ 1480: "0x2063cFF0609D59bCCc196E20Eb58A8696a6b15A0"
33227
+ }
33228
+ },
33229
+ DLPRegistry: {
33230
+ addresses: {
33231
+ 14800: "0x4D59880a924526d1dD33260552Ff4328b1E18a43",
33232
+ 1480: "0x4D59880a924526d1dD33260552Ff4328b1E18a43"
33233
+ }
33234
+ },
33235
+ DLPRegistryTreasury: {
33236
+ addresses: {
33237
+ 14800: "0xb12ce1d27bEeFe39b6F0110b1AB77C21Aa0c9F9a",
33238
+ 1480: "0xb12ce1d27bEeFe39b6F0110b1AB77C21Aa0c9F9a"
33239
+ },
33240
+ discovery: {
33241
+ parent: "DLPRegistry",
33242
+ getter: "treasury"
33243
+ }
33244
+ },
33245
+ // ========================================
33246
+ // VANA POOL (STAKING)
33247
+ // ========================================
33248
+ VanaPoolStaking: {
33249
+ addresses: {
33250
+ 14800: "0x641C18E2F286c86f96CE95C8ec1EB9fC0415Ca0e",
33251
+ 1480: "0x641C18E2F286c86f96CE95C8ec1EB9fC0415Ca0e"
33252
+ }
33253
+ },
33254
+ VanaPoolTreasury: {
33255
+ addresses: {
33256
+ 14800: "0x143BE72CF2541604A7691933CAccd6D9cC17c003",
33257
+ 1480: "0x143BE72CF2541604A7691933CAccd6D9cC17c003"
33258
+ },
33259
+ discovery: {
33260
+ parent: "VanaPoolStaking",
33261
+ getter: "vanaPoolTreasury"
33262
+ }
33263
+ },
33264
+ VanaPoolEntity: {
33265
+ addresses: {
33266
+ 14800: "0x44f20490A82e1f1F1cC25Dd3BA8647034eDdce30",
33267
+ 1480: "0x44f20490A82e1f1F1cC25Dd3BA8647034eDdce30"
33268
+ },
33269
+ discovery: {
33270
+ parent: "VanaPoolStaking",
33271
+ getter: "vanaPoolEntity"
33272
+ }
33273
+ },
33274
+ // ========================================
33275
+ // DLP DEPLOYMENT & TOKEN SYSTEM
33276
+ // ========================================
33277
+ DATFactory: {
33278
+ addresses: {
33279
+ 14800: "0x40f8bccF35a75ecef63BC3B1B3E06ffEB9220644",
33280
+ 1480: "0x40f8bccF35a75ecef63BC3B1B3E06ffEB9220644"
33281
+ }
33282
+ },
33283
+ DAT: {
33284
+ addresses: {
33285
+ 14800: "0xA706b93ccED89f13340673889e29F0a5cd84212d",
33286
+ 1480: "0xA706b93ccED89f13340673889e29F0a5cd84212d"
33287
+ }
33288
+ },
33289
+ DATPausable: {
33290
+ addresses: {
33291
+ 14800: "0xe69FE86f0B95cC2f8416Fe22815c85DC8887e76e",
33292
+ 1480: "0xe69FE86f0B95cC2f8416Fe22815c85DC8887e76e"
33293
+ }
33294
+ },
33295
+ DATVotes: {
33296
+ addresses: {
33297
+ 14800: "0xaE04c8A77E9B27869eb563720524A9aE0baf1831",
33298
+ 1480: "0xaE04c8A77E9B27869eb563720524A9aE0baf1831"
33299
+ }
33300
+ },
33301
+ // ========================================
33302
+ // EXTERNAL DEPENDENCIES (DeFi)
33303
+ // ========================================
33304
+ WVANA: {
33305
+ addresses: {
33306
+ 14800: "0xbccc4b4c6530F82FE309c5E845E50b5E9C89f2AD",
33307
+ 1480: "0x00EDdD9621Fb08436d0331c149D1690909a5906d"
33308
+ }
33309
+ },
33310
+ UniswapV3NonfungiblePositionManager: {
33311
+ addresses: {
33312
+ 14800: "0x48Bd633f4B9128a38Ebb4a48b6975EB3Eaf1931b",
33313
+ 1480: "0x45a2992e1bFdCF9b9AcE0a84A238f2E56F481816"
33314
+ }
33315
+ },
33316
+ UniswapV3QuoterV2: {
33317
+ addresses: {
33318
+ 14800: "0x3152246f3CD4dD465292Dd4Ffd792E2Cf602e332",
33319
+ 1480: "0x1b13728ea3C90863990aC0e05987CfeC1888908c"
33320
+ }
33321
+ },
33322
+ // ========================================
33323
+ // UTILITY CONTRACTS
33324
+ // ========================================
33325
+ Multicall3: {
33326
+ addresses: {
33327
+ 14800: "0xD8d2dFca27E8797fd779F8547166A2d3B29d360E",
33328
+ 1480: "0xD8d2dFca27E8797fd779F8547166A2d3B29d360E"
33329
+ }
33330
+ },
33331
+ Multisend: {
33332
+ addresses: {
33333
+ 14800: "0x8807e8BCDFbaA8c2761760f3FBA37F6f7F2C5b2d",
33334
+ 1480: "0x8807e8BCDFbaA8c2761760f3FBA37F6f7F2C5b2d"
33335
+ }
33336
+ }
33337
+ };
33338
+
33339
+ // src/protocol/escrow.ts
33340
+ import { isHex as isHex2 } from "viem";
33341
+ var GENERIC_PAYMENT_TYPES = {
33342
+ GenericPayment: [
33343
+ { name: "payerAddress", type: "address" },
33344
+ { name: "opType", type: "string" },
33345
+ { name: "opId", type: "bytes32" },
33346
+ { name: "asset", type: "address" },
33347
+ { name: "amount", type: "uint256" },
33348
+ { name: "paymentNonce", type: "uint256" }
33349
+ ]
33350
+ };
33351
+ function genericPaymentDomain(chainId, escrowContract) {
33352
+ return {
33353
+ name: "Vana Data Portability",
33354
+ version: "1",
33355
+ chainId,
33356
+ verifyingContract: escrowContract
33357
+ };
33358
+ }
33359
+ var ESCROW_DEPOSIT_ABI = [
33360
+ {
33361
+ type: "function",
33362
+ name: "depositNative",
33363
+ stateMutability: "payable",
33364
+ inputs: [{ name: "account", type: "address" }],
33365
+ outputs: []
33366
+ },
33367
+ {
33368
+ type: "function",
33369
+ name: "depositToken",
33370
+ stateMutability: "nonpayable",
33371
+ inputs: [
33372
+ { name: "account", type: "address" },
33373
+ { name: "token", type: "address" },
33374
+ { name: "amount", type: "uint256" }
33375
+ ],
33376
+ outputs: []
33377
+ }
33378
+ ];
33379
+ var NATIVE_ASSET_ADDRESS = "0x0000000000000000000000000000000000000000";
33380
+ var EscrowWithdrawalLifecycleError = class extends Error {
33381
+ constructor(httpStatus, result) {
33382
+ super(result.error);
33383
+ this.httpStatus = httpStatus;
33384
+ this.result = result;
33385
+ }
33386
+ httpStatus;
33387
+ result;
33388
+ name = "EscrowWithdrawalLifecycleError";
33389
+ };
33390
+ var EscrowWithdrawalRejectionError = class extends Error {
33391
+ constructor(httpStatus, result) {
33392
+ super(result.error);
33393
+ this.httpStatus = httpStatus;
33394
+ this.result = result;
33395
+ }
33396
+ httpStatus;
33397
+ result;
33398
+ name = "EscrowWithdrawalRejectionError";
33399
+ };
33400
+ function createEscrowGatewayClient(baseUrl) {
33401
+ const base = baseUrl.replace(/\/+$/, "");
33402
+ async function throwOnError(res, context) {
33403
+ if (!res.ok) {
33404
+ let detail = "";
33405
+ try {
33406
+ const body = await res.json();
33407
+ if (body.error) detail = `: ${body.error}`;
33408
+ } catch {
33409
+ }
33410
+ throw new Error(
33411
+ `Escrow gateway error (${context}): ${res.status} ${res.statusText}${detail}`
33412
+ );
33413
+ }
33414
+ }
33415
+ async function throwOnWithdrawError(res) {
33416
+ if (res.ok) return;
33417
+ let body;
33418
+ try {
33419
+ body = await res.json();
33420
+ } catch {
33421
+ throw new Error(
33422
+ `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}`
33423
+ );
33424
+ }
33425
+ if (isEscrowWithdrawalFailureResult(body)) {
33426
+ throw new EscrowWithdrawalLifecycleError(res.status, body);
33427
+ }
33428
+ if (isEscrowWithdrawalRejectedResult(body)) {
33429
+ throw new EscrowWithdrawalRejectionError(res.status, body);
33430
+ }
33431
+ const error = getGatewayErrorMessage(body);
33432
+ throw new Error(
33433
+ `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}${error ? `: ${error}` : ""}`
33434
+ );
33435
+ }
33436
+ return {
33437
+ async submitDeposit({ txHash }) {
33438
+ const res = await fetch(`${base}/v1/escrow/deposit`, {
33439
+ method: "POST",
33440
+ headers: { "Content-Type": "application/json" },
33441
+ body: JSON.stringify({ txHash })
33442
+ });
33443
+ if (res.status !== 200 && res.status !== 202) {
33444
+ await throwOnError(res, "POST /v1/escrow/deposit");
33445
+ }
33446
+ return res.json();
33447
+ },
33448
+ async getEscrowBalance(account) {
33449
+ const res = await fetch(
33450
+ `${base}/v1/escrow/balance?account=${encodeURIComponent(account)}`
33451
+ );
33452
+ await throwOnError(res, "GET /v1/escrow/balance");
33453
+ return res.json();
33454
+ },
33455
+ async syncEscrowBalance(account) {
33456
+ const res = await fetch(
33457
+ `${base}/v1/escrow/balance/sync?account=${encodeURIComponent(account)}`,
33458
+ { method: "POST" }
33459
+ );
33460
+ await throwOnError(res, "POST /v1/escrow/balance/sync");
33461
+ return res.json();
33462
+ },
33463
+ async payForOp({
33464
+ payerAddress,
33465
+ opType,
33466
+ opId,
33467
+ asset,
33468
+ amount,
33469
+ paymentNonce,
33470
+ signature,
33471
+ accessRecord
33472
+ }) {
33473
+ const res = await fetch(`${base}/v1/escrow/pay`, {
33474
+ method: "POST",
33475
+ headers: {
33476
+ "Content-Type": "application/json",
33477
+ Authorization: `Web3Signed ${signature}`
33478
+ },
33479
+ body: JSON.stringify({
33480
+ payerAddress,
33481
+ opType,
33482
+ opId,
33483
+ asset,
33484
+ amount,
33485
+ paymentNonce,
33486
+ ...accessRecord ? { accessRecord } : {}
33487
+ })
33488
+ });
33489
+ await throwOnError(res, "POST /v1/escrow/pay");
33490
+ return res.json();
33491
+ },
33492
+ async withdraw({
33493
+ account,
33494
+ asset,
33495
+ amount,
33496
+ withdrawNonce,
33497
+ deadline,
33498
+ signature
33499
+ }) {
33500
+ const res = await fetch(`${base}/v1/escrow/withdraw`, {
33501
+ method: "POST",
33502
+ headers: {
33503
+ "Content-Type": "application/json",
33504
+ Authorization: `Web3Signed ${signature}`
33505
+ },
33506
+ body: JSON.stringify({
33507
+ account,
33508
+ asset,
33509
+ amount,
33510
+ withdrawNonce,
33511
+ deadline
33512
+ })
33513
+ });
33514
+ await throwOnWithdrawError(res);
33515
+ return res.json();
33516
+ },
33517
+ async getWithdrawNonce(account) {
33518
+ const res = await fetch(
33519
+ `${base}/v1/escrow/withdraw/nonce?account=${encodeURIComponent(account)}`,
33520
+ { cache: "no-store" }
33521
+ );
33522
+ await throwOnError(res, "GET /v1/escrow/withdraw/nonce");
33523
+ const body = await res.json();
33524
+ if (!isWithdrawNonceResponse(body, account)) {
33525
+ throw new Error(
33526
+ "GET /v1/escrow/withdraw/nonce: invalid response structure"
33527
+ );
33528
+ }
33529
+ return body;
33530
+ }
33531
+ };
33532
+ }
33533
+ function getGatewayErrorMessage(body) {
33534
+ if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
33535
+ return body.error;
33536
+ }
33537
+ return void 0;
33538
+ }
33539
+ function isEscrowWithdrawalFailureResult(body) {
33540
+ if (typeof body !== "object" || body === null) return false;
33541
+ const value = body;
33542
+ 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));
33543
+ }
33544
+ function isEscrowWithdrawalRejectedResult(body) {
33545
+ if (typeof body !== "object" || body === null) return false;
33546
+ const value = body;
33547
+ 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);
33548
+ }
33549
+ function isWithdrawalRejectionCode(value) {
33550
+ return value === "below_minimum" || value === "deadline_too_far" || value === "expired" || value === "insufficient_available" || value === "stale_nonce";
33551
+ }
33552
+ function optionalUint256Decimal(value) {
33553
+ return value === void 0 || isUint256Decimal(value);
33554
+ }
33555
+ function isAddressHex(value) {
33556
+ return typeof value === "string" && isHex2(value, { strict: true }) && value.length === 42;
33557
+ }
33558
+ function isHash(value) {
33559
+ return typeof value === "string" && isHex2(value, { strict: true }) && value.length === 66;
33560
+ }
33561
+ function isUint256Decimal(value) {
33562
+ if (typeof value !== "string" || value.length === 0 || value.length > 78) {
33563
+ return false;
33564
+ }
33565
+ if (!/^(0|[1-9]\d*)$/.test(value)) return false;
33566
+ return BigInt(value) <= 2n ** 256n - 1n;
33567
+ }
33568
+ function isBlockNumber(value) {
33569
+ return value === null || isUint256Decimal(value);
33570
+ }
33571
+ function isWithdrawNonceResponse(body, requestedAccount) {
33572
+ if (typeof body !== "object" || body === null) return false;
33573
+ const value = body;
33574
+ if (value.success !== true) return false;
33575
+ if (!isAddressHex(value.account)) return false;
33576
+ if (value.account.toLowerCase() !== requestedAccount.toLowerCase())
33577
+ return false;
33578
+ if (typeof value.chainId !== "string") return false;
33579
+ if (!/^(0|[1-9]\d*)$/.test(value.chainId)) return false;
33580
+ const isLastNull = value.lastWithdrawNonce === null;
33581
+ const lastNonceValid = isLastNull || isUint256Decimal(value.lastWithdrawNonce);
33582
+ if (!lastNonceValid) return false;
33583
+ if (!isUint256Decimal(value.nextWithdrawNonce)) return false;
33584
+ if (isLastNull) {
33585
+ return value.nextWithdrawNonce === "1";
33586
+ }
33587
+ const lastNonce = BigInt(value.lastWithdrawNonce);
33588
+ const nextNonce = BigInt(value.nextWithdrawNonce);
33589
+ const expectedNextNonce = lastNonce + 1n;
33590
+ if (expectedNextNonce > 2n ** 256n - 1n) return false;
33591
+ return nextNonce === expectedNextNonce;
33592
+ }
33080
33593
 
33081
33594
  // src/protocol/write-signer.ts
33082
33595
  import { WriteRequestError } from "./errors.js";
@@ -33122,7 +33635,9 @@ function resolveWriteSigner(source, options = {}) {
33122
33635
  // src/protocol/jobs-client.ts
33123
33636
  var IDENTITY_PATH = "/v1/identity";
33124
33637
  var JOBS_PATH = "/v1/jobs";
33638
+ var JOB_QUOTE_PATH = "/v1/jobs/quote";
33125
33639
  var JOB_EXECUTE_PATH = "/v1/jobs/execute";
33640
+ var JOB_ACCESS_OP_TYPE = "job_access";
33126
33641
  var AUTHORIZATION_HEADER = "Authorization";
33127
33642
  var CONTENT_TYPE_HEADER = "Content-Type";
33128
33643
  var JSON_CONTENT_TYPE = "application/json";
@@ -33136,7 +33651,11 @@ var HTTP_UNAUTHORIZED = 401;
33136
33651
  var HTTP_FORBIDDEN = 403;
33137
33652
  var HTTP_NOT_FOUND = 404;
33138
33653
  var HTTP_CONFLICT = 409;
33654
+ var HTTP_PAYMENT_REQUIRED = 402;
33139
33655
  var HTTP_PAYLOAD_TOO_LARGE = 413;
33656
+ var NONCE_TIMESTAMP_SHIFT = 32n;
33657
+ var UINT256_DECIMAL = /^(0|[1-9]\d*)$/;
33658
+ var POSITIVE_UINT256_DECIMAL = /^[1-9]\d*$/;
33140
33659
  var MILLISECONDS_PER_SECOND = 1e3;
33141
33660
  var DEFAULT_JOB_TIMEOUT_MS = 12e4;
33142
33661
  var DEFAULT_JOB_POLL_MS = CLAIM_POLL_FLOOR_MS;
@@ -33219,11 +33738,17 @@ function resolveBuilder(options) {
33219
33738
  "Builder signer must expose both address and publicKey"
33220
33739
  );
33221
33740
  }
33741
+ const typedDataSigner = source.signTypedData;
33222
33742
  return {
33223
33743
  builder: {
33224
33744
  address: signer.address,
33225
33745
  publicKey,
33226
- signMessage: signer.signMessage
33746
+ signMessage: signer.signMessage,
33747
+ ...typedDataSigner ? {
33748
+ signTypedData: typedDataSigner.bind(
33749
+ source
33750
+ )
33751
+ } : {}
33227
33752
  },
33228
33753
  ...options.builderPrivateKey ? { privateKey: options.builderPrivateKey } : {}
33229
33754
  };
@@ -33307,7 +33832,7 @@ function isResultHandle(value) {
33307
33832
  function hasMatchingIdentityKey(value) {
33308
33833
  const address = value["address"];
33309
33834
  const publicKey = value["publicKey"];
33310
- if (typeof address !== "string" || !isAddress2(address) || typeof publicKey !== "string" || !isHex2(publicKey)) {
33835
+ if (typeof address !== "string" || !isAddress2(address) || typeof publicKey !== "string" || !isHex3(publicKey)) {
33311
33836
  return false;
33312
33837
  }
33313
33838
  try {
@@ -33320,7 +33845,7 @@ function hasExpectedIdentity(value, owner, chainId) {
33320
33845
  const identityOwner = value["ownerAddress"];
33321
33846
  const identityChainId = value["chainId"];
33322
33847
  const identityUserPsId = value["userPsId"];
33323
- if (!hasMatchingIdentityKey(value) || typeof identityOwner !== "string" || !isAddress2(identityOwner) || typeof identityChainId !== "number" || typeof identityUserPsId !== "string" || !isHex2(identityUserPsId)) {
33848
+ if (!hasMatchingIdentityKey(value) || typeof identityOwner !== "string" || !isAddress2(identityOwner) || typeof identityChainId !== "number" || typeof identityUserPsId !== "string" || !isHex3(identityUserPsId)) {
33324
33849
  return false;
33325
33850
  }
33326
33851
  return isAddressEqual2(identityOwner, owner) && identityChainId === chainId && identityUserPsId.toLowerCase() === userPsId(chainId, owner).toLowerCase();
@@ -33328,6 +33853,51 @@ function hasExpectedIdentity(value, owner, chainId) {
33328
33853
  function sleep2(ms) {
33329
33854
  return new Promise((resolve) => setTimeout(resolve, ms));
33330
33855
  }
33856
+ function resolveEscrowContract(options) {
33857
+ if (options.escrowContract) return options.escrowContract;
33858
+ const addresses = CONTRACTS2["DataPortabilityEscrow"]?.addresses;
33859
+ const address = addresses?.[options.chainId];
33860
+ if (!address || !isAddress2(address)) {
33861
+ throw new JobRejectedError(
33862
+ `No DataPortabilityEscrow address for chain ${options.chainId}; pass escrowContract`
33863
+ );
33864
+ }
33865
+ return address;
33866
+ }
33867
+ function nextPaymentNonce() {
33868
+ const random = new Uint32Array(1);
33869
+ globalThis.crypto.getRandomValues(random);
33870
+ return (BigInt(Date.now()) << NONCE_TIMESTAMP_SHIFT) + BigInt(random[0] ?? 0);
33871
+ }
33872
+ function parseJobQuote(body) {
33873
+ if (!isRecord2(body)) return null;
33874
+ const { chainId, price, asset, payable, enforced } = body;
33875
+ if (typeof chainId !== "number" || !Number.isSafeInteger(chainId))
33876
+ return null;
33877
+ if (typeof price !== "string" || !UINT256_DECIMAL.test(price)) return null;
33878
+ if (typeof asset !== "string" || !isAddress2(asset)) return null;
33879
+ if (typeof payable !== "boolean" || typeof enforced !== "boolean")
33880
+ return null;
33881
+ return { chainId, price, asset, payable, enforced };
33882
+ }
33883
+ async function paymentQuote(response) {
33884
+ const body = await responseBody(response);
33885
+ const asset = isRecord2(body) ? body["asset"] : void 0;
33886
+ const amount = isRecord2(body) ? body["amount"] : void 0;
33887
+ if (typeof asset !== "string" || !isAddress2(asset) || typeof amount !== "string" || !POSITIVE_UINT256_DECIMAL.test(amount)) {
33888
+ throw new JobRejectedError(
33889
+ "Gateway asked for payment without a usable quote",
33890
+ response.status
33891
+ );
33892
+ }
33893
+ return { asset, amount };
33894
+ }
33895
+ async function paymentRefusal(response) {
33896
+ const body = await responseBody(response);
33897
+ const parsed = isRecord2(body) ? body : {};
33898
+ const message = typeof parsed["error"] === "string" ? parsed["error"] : "This read requires payment the builder escrow cannot back";
33899
+ return { message, details: parsed };
33900
+ }
33331
33901
  function requireFiniteDuration(value, field) {
33332
33902
  if (!Number.isFinite(value)) {
33333
33903
  throw new JobRejectedError(`${field} must be a finite number`);
@@ -33340,6 +33910,73 @@ function createJobsClient(options) {
33340
33910
  const { builder, privateKey } = resolveBuilder(options);
33341
33911
  const ecies = options.ecies ?? new NodeECIESUint8Provider();
33342
33912
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
33913
+ async function signQuote(jobId, quote) {
33914
+ if (!builder.signTypedData) {
33915
+ throw new JobRejectedError(
33916
+ "This read is charged, but the builder signer cannot sign typed data"
33917
+ );
33918
+ }
33919
+ const paymentNonce = nextPaymentNonce();
33920
+ const signature = await builder.signTypedData({
33921
+ domain: genericPaymentDomain(
33922
+ options.chainId,
33923
+ resolveEscrowContract(options)
33924
+ ),
33925
+ types: GENERIC_PAYMENT_TYPES,
33926
+ primaryType: "GenericPayment",
33927
+ message: {
33928
+ payerAddress: builder.address,
33929
+ opType: JOB_ACCESS_OP_TYPE,
33930
+ opId: keccak2562(toHex9(jobId.toLowerCase())),
33931
+ asset: quote.asset,
33932
+ amount: BigInt(quote.amount),
33933
+ paymentNonce
33934
+ }
33935
+ });
33936
+ return {
33937
+ signature,
33938
+ amount: quote.amount,
33939
+ asset: quote.asset,
33940
+ paymentNonce: paymentNonce.toString()
33941
+ };
33942
+ }
33943
+ async function postSubmission(submission, wait) {
33944
+ const identifiers = {
33945
+ jobId: submission.jobId,
33946
+ idempotencyKey: submission.idempotencyKey
33947
+ };
33948
+ const bodyBytes = new TextEncoder().encode(JSON.stringify(submission));
33949
+ const authorization = await buildWeb3SignedHeader({
33950
+ signMessage: builder.signMessage,
33951
+ aud: audience,
33952
+ method: POST_METHOD,
33953
+ uri: JOBS_PATH,
33954
+ body: bodyBytes,
33955
+ nonce: randomUUID()
33956
+ });
33957
+ try {
33958
+ return await request(
33959
+ `${baseUrl}${JOBS_PATH}?wait=${wait}`,
33960
+ {
33961
+ method: POST_METHOD,
33962
+ headers: {
33963
+ [AUTHORIZATION_HEADER]: authorization,
33964
+ [CONTENT_TYPE_HEADER]: JSON_CONTENT_TYPE
33965
+ },
33966
+ body: bodyBytes
33967
+ },
33968
+ "Job submission"
33969
+ );
33970
+ } catch (error) {
33971
+ if (error instanceof JobTransportError) {
33972
+ throw new JobTransportError(error.message, error.cause, {
33973
+ ...error.details,
33974
+ ...identifiers
33975
+ });
33976
+ }
33977
+ throw error;
33978
+ }
33979
+ }
33343
33980
  async function request(url, init, description) {
33344
33981
  try {
33345
33982
  return await fetchFn(url, init);
@@ -33395,7 +34032,8 @@ function createJobsClient(options) {
33395
34032
  "deadlineSeconds"
33396
34033
  );
33397
34034
  const wait = clampInteger(params.wait, 0, 0, MAX_WAIT_SECONDS, "wait");
33398
- const jobId = randomUUID();
34035
+ const jobId = params.jobId ?? randomUUID();
34036
+ const idempotencyKey = params.idempotencyKey ?? randomUUID();
33399
34037
  const nowMs = now().getTime();
33400
34038
  if (!Number.isFinite(nowMs)) {
33401
34039
  throw new JobRejectedError("now must return a valid Date");
@@ -33433,32 +34071,41 @@ function createJobsClient(options) {
33433
34071
  grantId: requestBody.grantId,
33434
34072
  scope: requestBody.scope,
33435
34073
  operation: requestBody.operation,
33436
- idempotencyKey: randomUUID(),
34074
+ idempotencyKey,
33437
34075
  jobId,
33438
34076
  deadline,
33439
- requestCiphertext
34077
+ requestCiphertext,
34078
+ ...params.maxPrice === void 0 ? {} : { maxPrice: params.maxPrice }
33440
34079
  };
33441
- const bodyBytes = new TextEncoder().encode(JSON.stringify(submission));
33442
- const authorization = await buildWeb3SignedHeader({
33443
- signMessage: builder.signMessage,
33444
- aud: audience,
33445
- method: POST_METHOD,
33446
- uri: JOBS_PATH,
33447
- body: bodyBytes,
33448
- nonce: randomUUID()
33449
- });
33450
- const response = await request(
33451
- `${baseUrl}${JOBS_PATH}?wait=${wait}`,
33452
- {
33453
- method: POST_METHOD,
33454
- headers: {
33455
- [AUTHORIZATION_HEADER]: authorization,
33456
- [CONTENT_TYPE_HEADER]: JSON_CONTENT_TYPE
33457
- },
33458
- body: bodyBytes
33459
- },
33460
- "Job submission"
33461
- );
34080
+ let response = await postSubmission(submission, wait);
34081
+ if (response.status === HTTP_PAYMENT_REQUIRED) {
34082
+ const quote = await paymentQuote(response);
34083
+ if (params.maxPrice !== void 0 && BigInt(quote.amount) > BigInt(params.maxPrice)) {
34084
+ throw new PaymentRequiredError(
34085
+ "The quoted price is above the maxPrice you set for this read",
34086
+ {
34087
+ jobId,
34088
+ scope: params.scope,
34089
+ grantId: params.grantId,
34090
+ asset: quote.asset,
34091
+ amount: quote.amount,
34092
+ maxPrice: params.maxPrice
34093
+ }
34094
+ );
34095
+ }
34096
+ submission.payment = await signQuote(jobId, quote);
34097
+ submission.priceAsset = quote.asset;
34098
+ response = await postSubmission(submission, wait);
34099
+ if (response.status === HTTP_PAYMENT_REQUIRED) {
34100
+ const refusal = await paymentRefusal(response);
34101
+ throw new PaymentRequiredError(refusal.message, {
34102
+ jobId,
34103
+ scope: params.scope,
34104
+ grantId: params.grantId,
34105
+ ...refusal.details
34106
+ });
34107
+ }
34108
+ }
33462
34109
  if (!response.ok) {
33463
34110
  throw await rejectedResponse(response, "Job submission rejected");
33464
34111
  }
@@ -33481,6 +34128,40 @@ function createJobsClient(options) {
33481
34128
  response.status
33482
34129
  );
33483
34130
  },
34131
+ async quoteJob() {
34132
+ const authorization = await buildWeb3SignedHeader({
34133
+ signMessage: builder.signMessage,
34134
+ aud: audience,
34135
+ method: GET_METHOD,
34136
+ uri: JOB_QUOTE_PATH,
34137
+ nonce: randomUUID()
34138
+ });
34139
+ const response = await request(
34140
+ `${baseUrl}${JOB_QUOTE_PATH}`,
34141
+ {
34142
+ method: GET_METHOD,
34143
+ headers: { [AUTHORIZATION_HEADER]: authorization }
34144
+ },
34145
+ "Job quote"
34146
+ );
34147
+ if (!response.ok) {
34148
+ throw await rejectedResponse(response, "Job quote rejected");
34149
+ }
34150
+ const quote = parseJobQuote(await responseBody(response));
34151
+ if (!quote) {
34152
+ throw new JobRejectedError(
34153
+ "Gateway returned an undocumented job quote",
34154
+ response.status
34155
+ );
34156
+ }
34157
+ if (quote.chainId !== options.chainId) {
34158
+ throw new JobRejectedError(
34159
+ `Gateway quoted chain ${quote.chainId}, not the configured ${options.chainId}`,
34160
+ response.status
34161
+ );
34162
+ }
34163
+ return quote;
34164
+ },
33484
34165
  async getJob(jobId) {
33485
34166
  const path = `${JOBS_PATH}/${encodeURIComponent(jobId)}`;
33486
34167
  const authorization = await buildWeb3SignedHeader({
@@ -34234,7 +34915,7 @@ async function getOpFee(client, config, opType, opts) {
34234
34915
 
34235
34916
  // src/protocol/escrow-deposit.ts
34236
34917
  import { encodeFunctionData } from "viem";
34237
- var ESCROW_DEPOSIT_ABI = [
34918
+ var ESCROW_DEPOSIT_ABI2 = [
34238
34919
  {
34239
34920
  type: "function",
34240
34921
  name: "depositNative",
@@ -34259,14 +34940,14 @@ function escrowContractAddress(config) {
34259
34940
  }
34260
34941
  function encodeDepositNativeData(input) {
34261
34942
  return encodeFunctionData({
34262
- abi: ESCROW_DEPOSIT_ABI,
34943
+ abi: ESCROW_DEPOSIT_ABI2,
34263
34944
  functionName: "depositNative",
34264
34945
  args: [input.account]
34265
34946
  });
34266
34947
  }
34267
34948
  function encodeDepositTokenData(input) {
34268
34949
  return encodeFunctionData({
34269
- abi: ESCROW_DEPOSIT_ABI,
34950
+ abi: ESCROW_DEPOSIT_ABI2,
34270
34951
  functionName: "depositToken",
34271
34952
  args: [input.account, input.token, input.amount]
34272
34953
  });
@@ -34332,7 +35013,7 @@ function buildMarkDataPointUnavailableRequest(config, input) {
34332
35013
  // src/protocol/data-point-deletion.ts
34333
35014
  import {
34334
35015
  isAddress as isAddress7,
34335
- keccak256 as keccak2563,
35016
+ keccak256 as keccak2564,
34336
35017
  maxUint256,
34337
35018
  stringToBytes as stringToBytes3
34338
35019
  } from "viem";
@@ -34342,7 +35023,7 @@ import { DataPointDeletedError, DataPointNotFoundError } from "./errors.js";
34342
35023
  import {
34343
35024
  encodeAbiParameters,
34344
35025
  isAddress as isAddress6,
34345
- keccak256 as keccak2562
35026
+ keccak256 as keccak2563
34346
35027
  } from "viem";
34347
35028
  import { z } from "zod";
34348
35029
  import { LineageReadError, WriteRequestError as WriteRequestError2 } from "./errors.js";
@@ -34387,7 +35068,7 @@ function deriveDataPointId(ownerAddress, scope) {
34387
35068
  `ownerAddress is not an EVM address: ${String(ownerAddress)}`
34388
35069
  );
34389
35070
  }
34390
- return keccak2562(
35071
+ return keccak2563(
34391
35072
  encodeAbiParameters(
34392
35073
  [
34393
35074
  { name: "ownerAddress", type: "address" },
@@ -34614,7 +35295,7 @@ var TOMBSTONE_METADATA_HASH_PREIMAGE = "vana.data-point.tombstone.metadata.v1";
34614
35295
  var TOMBSTONE_DATA_HASH = "0x30c45ee72fe56d1927701316925ab7ceacd3b6f9267061735d59396f075c6222";
34615
35296
  var TOMBSTONE_METADATA_HASH = "0xc5255a141acd6a2ae55971b62c0a85977c2511989dc114ad2abc2b7644f57d90";
34616
35297
  function computeTombstoneHash(preimage) {
34617
- return keccak2563(stringToBytes3(preimage));
35298
+ return keccak2564(stringToBytes3(preimage));
34618
35299
  }
34619
35300
  function isTombstoneHashes(dataHash, metadataHash) {
34620
35301
  return typeof dataHash === "string" && typeof metadataHash === "string" && dataHash.toLowerCase() === TOMBSTONE_DATA_HASH && metadataHash.toLowerCase() === TOMBSTONE_METADATA_HASH;
@@ -36706,259 +37387,99 @@ function createGatewayClient(baseUrl) {
36706
37387
  };
36707
37388
  }
36708
37389
 
36709
- // src/protocol/escrow.ts
36710
- import { isHex as isHex3 } from "viem";
36711
- var GENERIC_PAYMENT_TYPES = {
36712
- GenericPayment: [
36713
- { name: "payerAddress", type: "address" },
36714
- { name: "opType", type: "string" },
36715
- { name: "opId", type: "bytes32" },
36716
- { name: "asset", type: "address" },
36717
- { name: "amount", type: "uint256" },
36718
- { name: "paymentNonce", type: "uint256" }
36719
- ]
36720
- };
36721
- function genericPaymentDomain(chainId, escrowContract) {
36722
- return {
36723
- name: "Vana Data Portability",
36724
- version: "1",
36725
- chainId,
36726
- verifyingContract: escrowContract
36727
- };
37390
+ // src/direct/grant-union.ts
37391
+ import { DirectConfigError } from "./direct/errors.js";
37392
+ function dedupe(entries) {
37393
+ return [...new Set(entries)];
36728
37394
  }
36729
- var ESCROW_DEPOSIT_ABI2 = [
36730
- {
36731
- type: "function",
36732
- name: "depositNative",
36733
- stateMutability: "payable",
36734
- inputs: [{ name: "account", type: "address" }],
36735
- outputs: []
36736
- },
36737
- {
36738
- type: "function",
36739
- name: "depositToken",
36740
- stateMutability: "nonpayable",
36741
- inputs: [
36742
- { name: "account", type: "address" },
36743
- { name: "token", type: "address" },
36744
- { name: "amount", type: "uint256" }
36745
- ],
36746
- outputs: []
36747
- }
36748
- ];
36749
- var NATIVE_ASSET_ADDRESS = "0x0000000000000000000000000000000000000000";
36750
- var EscrowWithdrawalLifecycleError = class extends Error {
36751
- constructor(httpStatus, result) {
36752
- super(result.error);
36753
- this.httpStatus = httpStatus;
36754
- this.result = result;
36755
- }
36756
- httpStatus;
36757
- result;
36758
- name = "EscrowWithdrawalLifecycleError";
36759
- };
36760
- var EscrowWithdrawalRejectionError = class extends Error {
36761
- constructor(httpStatus, result) {
36762
- super(result.error);
36763
- this.httpStatus = httpStatus;
36764
- this.result = result;
36765
- }
36766
- httpStatus;
36767
- result;
36768
- name = "EscrowWithdrawalRejectionError";
36769
- };
36770
- function createEscrowGatewayClient(baseUrl) {
36771
- const base = baseUrl.replace(/\/+$/, "");
36772
- async function throwOnError(res, context) {
36773
- if (!res.ok) {
36774
- let detail = "";
36775
- try {
36776
- const body = await res.json();
36777
- if (body.error) detail = `: ${body.error}`;
36778
- } catch {
36779
- }
36780
- throw new Error(
36781
- `Escrow gateway error (${context}): ${res.status} ${res.statusText}${detail}`
36782
- );
36783
- }
37395
+ function isCarryable(entry) {
37396
+ try {
37397
+ parseScope(parseScopeEntry(entry).scope);
37398
+ return true;
37399
+ } catch {
37400
+ return false;
36784
37401
  }
36785
- async function throwOnWithdrawError(res) {
36786
- if (res.ok) return;
36787
- let body;
36788
- try {
36789
- body = await res.json();
36790
- } catch {
36791
- throw new Error(
36792
- `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}`
36793
- );
36794
- }
36795
- if (isEscrowWithdrawalFailureResult(body)) {
36796
- throw new EscrowWithdrawalLifecycleError(res.status, body);
36797
- }
36798
- if (isEscrowWithdrawalRejectedResult(body)) {
36799
- throw new EscrowWithdrawalRejectionError(res.status, body);
36800
- }
36801
- const error = getGatewayErrorMessage(body);
36802
- throw new Error(
36803
- `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}${error ? `: ${error}` : ""}`
37402
+ }
37403
+ function unionGrantScopes(liveScopes, scopes, removeScopes = []) {
37404
+ const remove = new Set(removeScopes);
37405
+ const conflicting = scopes.filter((entry) => remove.has(entry));
37406
+ if (conflicting.length > 0) {
37407
+ throw new DirectConfigError(
37408
+ `${conflicting.join(", ")} cannot be both requested and removed. Drop it from scopes or from removeScopes.`,
37409
+ { conflicting }
36804
37410
  );
36805
37411
  }
37412
+ const live = dedupe(liveScopes);
37413
+ const requested = dedupe(scopes);
37414
+ const liveSet = new Set(live);
37415
+ const removed = live.filter((entry) => remove.has(entry));
37416
+ const remaining = live.filter((entry) => !remove.has(entry));
37417
+ const notCarried = remaining.filter((entry) => !isCarryable(entry));
37418
+ const keptAll = remaining.filter(isCarryable);
37419
+ const added = requested.filter((entry) => !liveSet.has(entry));
36806
37420
  return {
36807
- async submitDeposit({ txHash }) {
36808
- const res = await fetch(`${base}/v1/escrow/deposit`, {
36809
- method: "POST",
36810
- headers: { "Content-Type": "application/json" },
36811
- body: JSON.stringify({ txHash })
36812
- });
36813
- if (res.status !== 200 && res.status !== 202) {
36814
- await throwOnError(res, "POST /v1/escrow/deposit");
36815
- }
36816
- return res.json();
36817
- },
36818
- async getEscrowBalance(account) {
36819
- const res = await fetch(
36820
- `${base}/v1/escrow/balance?account=${encodeURIComponent(account)}`
36821
- );
36822
- await throwOnError(res, "GET /v1/escrow/balance");
36823
- return res.json();
36824
- },
36825
- async syncEscrowBalance(account) {
36826
- const res = await fetch(
36827
- `${base}/v1/escrow/balance/sync?account=${encodeURIComponent(account)}`,
36828
- { method: "POST" }
36829
- );
36830
- await throwOnError(res, "POST /v1/escrow/balance/sync");
36831
- return res.json();
36832
- },
36833
- async payForOp({
36834
- payerAddress,
36835
- opType,
36836
- opId,
36837
- asset,
36838
- amount,
36839
- paymentNonce,
36840
- signature,
36841
- accessRecord
36842
- }) {
36843
- const res = await fetch(`${base}/v1/escrow/pay`, {
36844
- method: "POST",
36845
- headers: {
36846
- "Content-Type": "application/json",
36847
- Authorization: `Web3Signed ${signature}`
36848
- },
36849
- body: JSON.stringify({
36850
- payerAddress,
36851
- opType,
36852
- opId,
36853
- asset,
36854
- amount,
36855
- paymentNonce,
36856
- ...accessRecord ? { accessRecord } : {}
36857
- })
36858
- });
36859
- await throwOnError(res, "POST /v1/escrow/pay");
36860
- return res.json();
36861
- },
36862
- async withdraw({
36863
- account,
36864
- asset,
36865
- amount,
36866
- withdrawNonce,
36867
- deadline,
36868
- signature
36869
- }) {
36870
- const res = await fetch(`${base}/v1/escrow/withdraw`, {
36871
- method: "POST",
36872
- headers: {
36873
- "Content-Type": "application/json",
36874
- Authorization: `Web3Signed ${signature}`
36875
- },
36876
- body: JSON.stringify({
36877
- account,
36878
- asset,
36879
- amount,
36880
- withdrawNonce,
36881
- deadline
36882
- })
36883
- });
36884
- await throwOnWithdrawError(res);
36885
- return res.json();
36886
- },
36887
- async getWithdrawNonce(account) {
36888
- const res = await fetch(
36889
- `${base}/v1/escrow/withdraw/nonce?account=${encodeURIComponent(account)}`,
36890
- { cache: "no-store" }
36891
- );
36892
- await throwOnError(res, "GET /v1/escrow/withdraw/nonce");
36893
- const body = await res.json();
36894
- if (!isWithdrawNonceResponse(body, account)) {
36895
- throw new Error(
36896
- "GET /v1/escrow/withdraw/nonce: invalid response structure"
36897
- );
36898
- }
36899
- return body;
36900
- }
37421
+ scopes: dedupe([...keptAll, ...added]),
37422
+ kept: keptAll,
37423
+ added,
37424
+ removed,
37425
+ notCarried,
37426
+ liveScopes: live
36901
37427
  };
36902
37428
  }
36903
- function getGatewayErrorMessage(body) {
36904
- if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
36905
- return body.error;
36906
- }
36907
- return void 0;
36908
- }
36909
- function isEscrowWithdrawalFailureResult(body) {
36910
- if (typeof body !== "object" || body === null) return false;
36911
- const value = body;
36912
- 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));
36913
- }
36914
- function isEscrowWithdrawalRejectedResult(body) {
36915
- if (typeof body !== "object" || body === null) return false;
36916
- const value = body;
36917
- 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);
36918
- }
36919
- function isWithdrawalRejectionCode(value) {
36920
- return value === "below_minimum" || value === "deadline_too_far" || value === "expired" || value === "insufficient_available" || value === "stale_nonce";
37429
+ function isActiveGrant(grant) {
37430
+ return !grant.revokedAt && !grant.expired;
36921
37431
  }
36922
- function optionalUint256Decimal(value) {
36923
- return value === void 0 || isUint256Decimal(value);
37432
+ function sameHex(a, b) {
37433
+ return a.toLowerCase() === b.toLowerCase();
36924
37434
  }
36925
- function isAddressHex(value) {
36926
- return typeof value === "string" && isHex3(value, { strict: true }) && value.length === 42;
37435
+ async function findLiveGrant(gateway, owner, granteeId) {
37436
+ const grants = await gateway.listGrantsByUser(owner);
37437
+ const matching = grants.filter(
37438
+ (grant) => sameHex(grant.granteeId, granteeId) && isActiveGrant(grant)
37439
+ ).sort((a, b) => {
37440
+ const av = BigInt(a.grantVersion || "0");
37441
+ const bv = BigInt(b.grantVersion || "0");
37442
+ return av === bv ? 0 : av > bv ? -1 : 1;
37443
+ });
37444
+ return matching[0] ?? null;
36927
37445
  }
36928
- function isHash(value) {
36929
- return typeof value === "string" && isHex3(value, { strict: true }) && value.length === 66;
37446
+ async function liveGrantScopes(gateway, owner, granteeId) {
37447
+ const grant = await findLiveGrant(gateway, owner, granteeId);
37448
+ return grant ? [...grant.scopes] : [];
36930
37449
  }
36931
- function isUint256Decimal(value) {
36932
- if (typeof value !== "string" || value.length === 0 || value.length > 78) {
36933
- return false;
37450
+ async function resolveGranteeId(input) {
37451
+ if (input.granteeId) {
37452
+ return input.granteeId;
36934
37453
  }
36935
- if (!/^(0|[1-9]\d*)$/.test(value)) return false;
36936
- return BigInt(value) <= 2n ** 256n - 1n;
36937
- }
36938
- function isBlockNumber(value) {
36939
- return value === null || isUint256Decimal(value);
37454
+ if (!input.appAddress) {
37455
+ throw new DirectConfigError(
37456
+ "mergeWithLiveGrant needs granteeId or appAddress to find the app's grant."
37457
+ );
37458
+ }
37459
+ if (!input.gateway.getBuilder) {
37460
+ throw new DirectConfigError(
37461
+ "mergeWithLiveGrant needs gateway.getBuilder to resolve appAddress to a granteeId. Pass granteeId instead."
37462
+ );
37463
+ }
37464
+ const builder = await input.gateway.getBuilder(input.appAddress);
37465
+ return builder?.id ?? null;
36940
37466
  }
36941
- function isWithdrawNonceResponse(body, requestedAccount) {
36942
- if (typeof body !== "object" || body === null) return false;
36943
- const value = body;
36944
- if (value.success !== true) return false;
36945
- if (!isAddressHex(value.account)) return false;
36946
- if (value.account.toLowerCase() !== requestedAccount.toLowerCase())
36947
- return false;
36948
- if (typeof value.chainId !== "string") return false;
36949
- if (!/^(0|[1-9]\d*)$/.test(value.chainId)) return false;
36950
- const isLastNull = value.lastWithdrawNonce === null;
36951
- const lastNonceValid = isLastNull || isUint256Decimal(value.lastWithdrawNonce);
36952
- if (!lastNonceValid) return false;
36953
- if (!isUint256Decimal(value.nextWithdrawNonce)) return false;
36954
- if (isLastNull) {
36955
- return value.nextWithdrawNonce === "1";
37467
+ async function mergeWithLiveGrant(input) {
37468
+ const removeScopes = input.removeScopes ?? [];
37469
+ unionGrantScopes([], input.scopes, removeScopes);
37470
+ const granteeId = await resolveGranteeId(input);
37471
+ const grant = granteeId ? await findLiveGrant(input.gateway, input.owner, granteeId) : null;
37472
+ if (!grant) {
37473
+ return {
37474
+ status: "no_live_grant",
37475
+ ...unionGrantScopes([], input.scopes, removeScopes)
37476
+ };
36956
37477
  }
36957
- const lastNonce = BigInt(value.lastWithdrawNonce);
36958
- const nextNonce = BigInt(value.nextWithdrawNonce);
36959
- const expectedNextNonce = lastNonce + 1n;
36960
- if (expectedNextNonce > 2n ** 256n - 1n) return false;
36961
- return nextNonce === expectedNextNonce;
37478
+ return {
37479
+ status: "merged",
37480
+ grantId: grant.id,
37481
+ ...unionGrantScopes(grant.scopes, input.scopes, removeScopes)
37482
+ };
36962
37483
  }
36963
37484
 
36964
37485
  // src/direct/escrow-payment.ts
@@ -37197,7 +37718,7 @@ async function authorizeEscrowPayment(params) {
37197
37718
  }
37198
37719
 
37199
37720
  // src/direct/personal-server-read.ts
37200
- import { PaymentRequiredError, PersonalServerReadError } from "./direct/errors.js";
37721
+ import { PaymentRequiredError as PaymentRequiredError2, PersonalServerReadError } from "./direct/errors.js";
37201
37722
  import { DataPointDeletedError as DataPointDeletedError4 } from "./errors.js";
37202
37723
  function asRecord2(value) {
37203
37724
  return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
@@ -37514,7 +38035,7 @@ export {
37514
38035
  ENCLAVE_IDENTITY_EVIDENCE_VERSION,
37515
38036
  ENCLAVE_TRUST_ANCHORS,
37516
38037
  ENCLAVE_WALLET_PURPOSE,
37517
- ESCROW_DEPOSIT_ABI2 as ESCROW_DEPOSIT_ABI,
38038
+ ESCROW_DEPOSIT_ABI,
37518
38039
  EscrowWithdrawalLifecycleError,
37519
38040
  EscrowWithdrawalRejectionError,
37520
38041
  ExpiredTokenError2 as ExpiredTokenError,
@@ -37660,6 +38181,7 @@ export {
37660
38181
  encryptWithPassword,
37661
38182
  escrowContractAddress,
37662
38183
  escrowPaymentDomain,
38184
+ findLiveGrant,
37663
38185
  formatScopeEntry,
37664
38186
  gatewayLineagePath,
37665
38187
  generatePkceVerifier,
@@ -37693,7 +38215,9 @@ export {
37693
38215
  isTombstoneHashes,
37694
38216
  kmsIssuedPreimage,
37695
38217
  listQuestions,
38218
+ liveGrantScopes,
37696
38219
  mainnetServices,
38220
+ mergeWithLiveGrant,
37697
38221
  moksha,
37698
38222
  mokshaServices,
37699
38223
  mokshaTestnet2 as mokshaTestnet,
@@ -37737,6 +38261,7 @@ export {
37737
38261
  toDirectPaymentReceipt,
37738
38262
  tombstoneDeletedAt,
37739
38263
  tryGrantPermissions,
38264
+ unionGrantScopes,
37740
38265
  userPsId,
37741
38266
  vanaMainnet2 as vanaMainnet,
37742
38267
  verifyEnclaveIdentityEvidence,