@opendatalabs/vana-sdk 0.1.0-alpha.2e77fcc → 0.1.0-alpha.3041a59

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 (180) hide show
  1. package/dist/controllers/__tests__/data-consistency-integration.test.d.ts +7 -0
  2. package/dist/controllers/__tests__/operations.processQueue.test.d.ts +1 -0
  3. package/dist/controllers/data.cjs +255 -143
  4. package/dist/controllers/data.cjs.map +1 -1
  5. package/dist/controllers/data.d.ts +25 -10
  6. package/dist/controllers/data.js +268 -146
  7. package/dist/controllers/data.js.map +1 -1
  8. package/dist/controllers/operations.cjs +430 -0
  9. package/dist/controllers/operations.cjs.map +1 -0
  10. package/dist/controllers/operations.d.ts +229 -0
  11. package/dist/controllers/operations.js +406 -0
  12. package/dist/controllers/operations.js.map +1 -0
  13. package/dist/controllers/permissions.cjs +516 -183
  14. package/dist/controllers/permissions.cjs.map +1 -1
  15. package/dist/controllers/permissions.d.ts +126 -28
  16. package/dist/controllers/permissions.js +516 -183
  17. package/dist/controllers/permissions.js.map +1 -1
  18. package/dist/controllers/schemas.cjs +81 -4
  19. package/dist/controllers/schemas.cjs.map +1 -1
  20. package/dist/controllers/schemas.d.ts +41 -0
  21. package/dist/controllers/schemas.js +81 -4
  22. package/dist/controllers/schemas.js.map +1 -1
  23. package/dist/controllers/server.cjs +251 -42
  24. package/dist/controllers/server.cjs.map +1 -1
  25. package/dist/controllers/server.d.ts +111 -14
  26. package/dist/controllers/server.js +251 -42
  27. package/dist/controllers/server.js.map +1 -1
  28. package/dist/core/__tests__/health.test.d.ts +1 -0
  29. package/dist/core/__tests__/inMemoryNonceManager.test.d.ts +1 -0
  30. package/dist/core/__tests__/nonceManager.test.d.ts +1 -0
  31. package/dist/core/__tests__/pollingManager.test.d.ts +4 -0
  32. package/dist/core/health.cjs +289 -0
  33. package/dist/core/health.cjs.map +1 -0
  34. package/dist/core/health.d.ts +143 -0
  35. package/dist/core/health.js +265 -0
  36. package/dist/core/health.js.map +1 -0
  37. package/dist/core/inMemoryNonceManager.cjs +138 -0
  38. package/dist/core/inMemoryNonceManager.cjs.map +1 -0
  39. package/dist/core/inMemoryNonceManager.d.ts +69 -0
  40. package/dist/core/inMemoryNonceManager.js +114 -0
  41. package/dist/core/inMemoryNonceManager.js.map +1 -0
  42. package/dist/core/nonceManager.cjs +304 -0
  43. package/dist/core/nonceManager.cjs.map +1 -0
  44. package/dist/core/nonceManager.d.ts +116 -0
  45. package/dist/core/nonceManager.js +280 -0
  46. package/dist/core/nonceManager.js.map +1 -0
  47. package/dist/core/pollingManager.cjs +292 -0
  48. package/dist/core/pollingManager.cjs.map +1 -0
  49. package/dist/core/pollingManager.d.ts +120 -0
  50. package/dist/core/pollingManager.js +268 -0
  51. package/dist/core/pollingManager.js.map +1 -0
  52. package/dist/core.cjs +5 -0
  53. package/dist/core.cjs.map +1 -1
  54. package/dist/core.d.ts +11 -5
  55. package/dist/core.js +5 -0
  56. package/dist/core.js.map +1 -1
  57. package/dist/crypto/ecies/base.cjs +16 -3
  58. package/dist/crypto/ecies/base.cjs.map +1 -1
  59. package/dist/crypto/ecies/base.js +16 -3
  60. package/dist/crypto/ecies/base.js.map +1 -1
  61. package/dist/errors.cjs +29 -0
  62. package/dist/errors.cjs.map +1 -1
  63. package/dist/errors.d.ts +64 -0
  64. package/dist/errors.js +28 -0
  65. package/dist/errors.js.map +1 -1
  66. package/dist/generated/abi/DataPortabilityGranteesImplementation.cjs +162 -0
  67. package/dist/generated/abi/DataPortabilityGranteesImplementation.cjs.map +1 -1
  68. package/dist/generated/abi/DataPortabilityGranteesImplementation.d.ts +123 -0
  69. package/dist/generated/abi/DataPortabilityGranteesImplementation.js +162 -0
  70. package/dist/generated/abi/DataPortabilityGranteesImplementation.js.map +1 -1
  71. package/dist/generated/abi/index.d.ts +123 -0
  72. package/dist/generated/server/server-exports.cjs +22 -0
  73. package/dist/generated/server/server-exports.cjs.map +1 -1
  74. package/dist/generated/server/server-exports.d.ts +27 -10
  75. package/dist/generated/server/server-exports.js +17 -0
  76. package/dist/generated/server/server-exports.js.map +1 -1
  77. package/dist/generated/server/server.cjs.map +1 -1
  78. package/dist/generated/server/server.d.ts +771 -402
  79. package/dist/generated/subgraph.cjs +797 -32
  80. package/dist/generated/subgraph.cjs.map +1 -1
  81. package/dist/generated/subgraph.d.ts +135 -0
  82. package/dist/generated/subgraph.js +792 -32
  83. package/dist/generated/subgraph.js.map +1 -1
  84. package/dist/index.browser.d.ts +1 -0
  85. package/dist/index.browser.js +2 -0
  86. package/dist/index.browser.js.map +1 -1
  87. package/dist/index.node.cjs +17 -0
  88. package/dist/index.node.cjs.map +1 -1
  89. package/dist/index.node.d.ts +25 -5
  90. package/dist/index.node.js +15 -1
  91. package/dist/index.node.js.map +1 -1
  92. package/dist/lib/__tests__/redisAtomicStore.test.d.ts +1 -0
  93. package/dist/lib/redisAtomicStore.cjs +201 -0
  94. package/dist/lib/redisAtomicStore.cjs.map +1 -0
  95. package/dist/lib/redisAtomicStore.d.ts +120 -0
  96. package/dist/lib/redisAtomicStore.js +177 -0
  97. package/dist/lib/redisAtomicStore.js.map +1 -0
  98. package/dist/server/relayerHandler.cjs +187 -25
  99. package/dist/server/relayerHandler.cjs.map +1 -1
  100. package/dist/server/relayerHandler.d.ts +35 -4
  101. package/dist/server/relayerHandler.js +187 -25
  102. package/dist/server/relayerHandler.js.map +1 -1
  103. package/dist/storage/index.cjs +3 -0
  104. package/dist/storage/index.cjs.map +1 -1
  105. package/dist/storage/index.d.ts +1 -0
  106. package/dist/storage/index.js +2 -0
  107. package/dist/storage/index.js.map +1 -1
  108. package/dist/storage/providers/dropbox.cjs +237 -0
  109. package/dist/storage/providers/dropbox.cjs.map +1 -0
  110. package/dist/storage/providers/dropbox.d.ts +39 -0
  111. package/dist/storage/providers/dropbox.js +215 -0
  112. package/dist/storage/providers/dropbox.js.map +1 -0
  113. package/dist/storage/providers/dropbox.test.d.ts +1 -0
  114. package/dist/tests/data-upload-owner-validation.test.d.ts +1 -0
  115. package/dist/types/atomicStore.cjs +31 -0
  116. package/dist/types/atomicStore.cjs.map +1 -0
  117. package/dist/types/atomicStore.d.ts +236 -0
  118. package/dist/types/atomicStore.js +7 -0
  119. package/dist/types/atomicStore.js.map +1 -0
  120. package/dist/types/config.cjs.map +1 -1
  121. package/dist/types/config.d.ts +3 -3
  122. package/dist/types/config.js.map +1 -1
  123. package/dist/types/controller-context.cjs.map +1 -1
  124. package/dist/types/controller-context.d.ts +4 -3
  125. package/dist/types/data.cjs.map +1 -1
  126. package/dist/types/data.d.ts +7 -4
  127. package/dist/types/index.cjs.map +1 -1
  128. package/dist/types/index.d.ts +4 -2
  129. package/dist/types/index.js.map +1 -1
  130. package/dist/types/operationStore.cjs +17 -0
  131. package/dist/types/operationStore.cjs.map +1 -0
  132. package/dist/types/operationStore.d.ts +171 -0
  133. package/dist/types/operationStore.js +1 -0
  134. package/dist/types/operationStore.js.map +1 -0
  135. package/dist/types/operations.cjs +3 -15
  136. package/dist/types/operations.cjs.map +1 -1
  137. package/dist/types/operations.d.ts +17 -88
  138. package/dist/types/operations.js +2 -13
  139. package/dist/types/operations.js.map +1 -1
  140. package/dist/types/options.cjs +17 -0
  141. package/dist/types/options.cjs.map +1 -0
  142. package/dist/types/options.d.ts +308 -0
  143. package/dist/types/options.js +1 -0
  144. package/dist/types/options.js.map +1 -0
  145. package/dist/types/permissions.cjs.map +1 -1
  146. package/dist/types/permissions.d.ts +4 -0
  147. package/dist/types/personal.cjs.map +1 -1
  148. package/dist/types/personal.d.ts +19 -0
  149. package/dist/types/relayer.cjs.map +1 -1
  150. package/dist/types/relayer.d.ts +10 -10
  151. package/dist/types/utils.cjs.map +1 -1
  152. package/dist/types/utils.d.ts +0 -49
  153. package/dist/utils/__tests__/chainQuery.test.d.ts +1 -0
  154. package/dist/utils/__tests__/subgraphConsistency.test.d.ts +4 -0
  155. package/dist/utils/__tests__/subgraphPagination.test.d.ts +4 -0
  156. package/dist/utils/chainQuery.cjs +107 -0
  157. package/dist/utils/chainQuery.cjs.map +1 -0
  158. package/dist/utils/chainQuery.d.ts +31 -0
  159. package/dist/utils/chainQuery.js +82 -0
  160. package/dist/utils/chainQuery.js.map +1 -0
  161. package/dist/utils/grantFiles.cjs +4 -1
  162. package/dist/utils/grantFiles.cjs.map +1 -1
  163. package/dist/utils/grantFiles.js +4 -1
  164. package/dist/utils/grantFiles.js.map +1 -1
  165. package/dist/utils/subgraphConsistency.cjs +184 -0
  166. package/dist/utils/subgraphConsistency.cjs.map +1 -0
  167. package/dist/utils/subgraphConsistency.d.ts +65 -0
  168. package/dist/utils/subgraphConsistency.js +155 -0
  169. package/dist/utils/subgraphConsistency.js.map +1 -0
  170. package/dist/utils/subgraphMetaCache.cjs +101 -0
  171. package/dist/utils/subgraphMetaCache.cjs.map +1 -0
  172. package/dist/utils/subgraphMetaCache.d.ts +56 -0
  173. package/dist/utils/subgraphMetaCache.js +76 -0
  174. package/dist/utils/subgraphMetaCache.js.map +1 -0
  175. package/dist/utils/subgraphPagination.cjs +104 -0
  176. package/dist/utils/subgraphPagination.cjs.map +1 -0
  177. package/dist/utils/subgraphPagination.d.ts +78 -0
  178. package/dist/utils/subgraphPagination.js +78 -0
  179. package/dist/utils/subgraphPagination.js.map +1 -0
  180. package/package.json +1 -1
@@ -33,6 +33,7 @@ __export(permissions_exports, {
33
33
  module.exports = __toCommonJS(permissions_exports);
34
34
  var import_viem = require("viem");
35
35
  var import_multicall = require("../utils/multicall");
36
+ var import_pollingManager = require("../core/pollingManager");
36
37
  var import_errors = require("../errors");
37
38
  var import_addresses = require("../config/addresses");
38
39
  var import_abi = require("../generated/abi");
@@ -214,7 +215,7 @@ class PermissionsController extends import_base.BaseController {
214
215
  if (response.type === "error") {
215
216
  throw new Error(response.error);
216
217
  }
217
- if (response.type === "direct" && typeof response.result === "object" && "url" in response.result) {
218
+ if (response.type === "direct" && typeof response.result === "object" && response.result !== null && "url" in response.result) {
218
219
  grantUrl = response.result.url;
219
220
  } else {
220
221
  throw new Error("Invalid response from relayer for grant storage");
@@ -322,7 +323,7 @@ class PermissionsController extends import_base.BaseController {
322
323
  if (response.type === "error") {
323
324
  throw new Error(response.error);
324
325
  }
325
- if (response.type === "direct" && typeof response.result === "object" && "url" in response.result) {
326
+ if (response.type === "direct" && typeof response.result === "object" && response.result !== null && "url" in response.result) {
326
327
  grantUrl = response.result.url;
327
328
  } else {
328
329
  throw new Error("Invalid response from relayer for grant storage");
@@ -421,7 +422,8 @@ class PermissionsController extends import_base.BaseController {
421
422
  finalHash = response.hash;
422
423
  } else if (response.type === "pending") {
423
424
  const pollResult = await this.pollRelayerForConfirmation(
424
- response.operationId
425
+ response.operationId,
426
+ options
425
427
  );
426
428
  finalHash = pollResult.hash;
427
429
  } else if (response.type === "confirmed") {
@@ -543,7 +545,7 @@ class PermissionsController extends import_base.BaseController {
543
545
  * const result = await txHandle.waitForEvents();
544
546
  * ```
545
547
  */
546
- async submitSignedAddAndTrustServer(typedData, signature, _options) {
548
+ async submitSignedAddAndTrustServer(typedData, signature, options) {
547
549
  try {
548
550
  const addAndTrustServerInput = {
549
551
  nonce: BigInt(typedData.message.nonce),
@@ -553,7 +555,8 @@ class PermissionsController extends import_base.BaseController {
553
555
  };
554
556
  const hash = await this.submitAddAndTrustServerTransaction(
555
557
  addAndTrustServerInput,
556
- signature
558
+ signature,
559
+ options
557
560
  );
558
561
  const account = this.context.walletClient?.account ?? this.context.userAddress;
559
562
  const { tx } = await import("../utils/transactionHelpers");
@@ -651,34 +654,22 @@ class PermissionsController extends import_base.BaseController {
651
654
  * Polls the relayer for confirmation of a pending operation.
652
655
  *
653
656
  * @param operationId - The operation ID to poll
654
- * @returns Promise resolving to the confirmed hash
655
- * @throws {Error} When the operation fails or times out
657
+ * @param options - Polling configuration including status updates and cancellation
658
+ * @returns Promise resolving to the confirmed hash and receipt
659
+ * @throws {TransactionPendingError} When the operation times out
660
+ * @throws {Error} When the operation fails or is cancelled
656
661
  * @internal
657
662
  */
658
- async pollRelayerForConfirmation(operationId, options = {}) {
659
- const timeout = options.timeout ?? 3e4;
660
- let interval = options.pollingInterval ?? 1e3;
661
- const startTime = Date.now();
662
- while (Date.now() - startTime < timeout) {
663
- if (!this.context.relayer) {
664
- throw new Error("Relayer not configured for polling");
665
- }
666
- const statusResponse = await this.context.relayer({
667
- type: "status_check",
668
- operationId
669
- });
670
- if (statusResponse.type === "confirmed") {
671
- return { hash: statusResponse.hash };
672
- }
673
- if (statusResponse.type === "error") {
674
- throw new Error(
675
- `Operation ${operationId} failed: ${statusResponse.error}`
676
- );
677
- }
678
- await new Promise((resolve) => setTimeout(resolve, interval));
679
- interval = Math.min(interval * 1.5, 5e3);
663
+ async pollRelayerForConfirmation(operationId, options) {
664
+ if (!this.context.relayer) {
665
+ throw new Error("Relayer not configured for polling");
680
666
  }
681
- throw new Error(`Operation ${operationId} timed out after ${timeout}ms`);
667
+ const pollingManager = new import_pollingManager.PollingManager(this.context.relayer);
668
+ return await pollingManager.startPolling(operationId, {
669
+ signal: options?.signal,
670
+ onStatusUpdate: options?.onStatusUpdate,
671
+ ...options?.pollingOptions
672
+ });
682
673
  }
683
674
  /**
684
675
  * Submits an already-signed permission revoke transaction to the blockchain.
@@ -701,7 +692,7 @@ class PermissionsController extends import_base.BaseController {
701
692
  * const result = await txHandle.waitForEvents();
702
693
  * ```
703
694
  */
704
- async submitSignedRevoke(typedData, signature, _options) {
695
+ async submitSignedRevoke(typedData, signature, options) {
705
696
  try {
706
697
  let hash;
707
698
  if (this.context.relayer) {
@@ -719,7 +710,8 @@ class PermissionsController extends import_base.BaseController {
719
710
  hash = response.hash;
720
711
  } else if (response.type === "pending") {
721
712
  const pollResult = await this.pollRelayerForConfirmation(
722
- response.operationId
713
+ response.operationId,
714
+ options
723
715
  );
724
716
  hash = pollResult.hash;
725
717
  } else if (response.type === "confirmed") {
@@ -734,7 +726,8 @@ class PermissionsController extends import_base.BaseController {
734
726
  } else {
735
727
  hash = await this.submitDirectRevokeTransaction(
736
728
  typedData,
737
- signature
729
+ signature,
730
+ options
738
731
  );
739
732
  }
740
733
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -776,7 +769,7 @@ class PermissionsController extends import_base.BaseController {
776
769
  * const result = await txHandle.waitForEvents();
777
770
  * ```
778
771
  */
779
- async submitSignedUntrustServer(typedData, signature, _options) {
772
+ async submitSignedUntrustServer(typedData, signature, options) {
780
773
  try {
781
774
  let hash;
782
775
  if (this.context.relayer) {
@@ -787,7 +780,9 @@ class PermissionsController extends import_base.BaseController {
787
780
  signature,
788
781
  expectedUserAddress: this.context.userAddress
789
782
  });
790
- if (response.type === "signed") {
783
+ if (response.type === "submitted") {
784
+ hash = response.hash;
785
+ } else if (response.type === "signed") {
791
786
  hash = response.hash;
792
787
  } else if (response.type === "error") {
793
788
  throw new Error(`Relayer error: ${response.error}`);
@@ -799,7 +794,8 @@ class PermissionsController extends import_base.BaseController {
799
794
  } else {
800
795
  hash = await this.submitSignedUntrustTransaction(
801
796
  typedData,
802
- signature
797
+ signature,
798
+ options
803
799
  );
804
800
  }
805
801
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -1021,7 +1017,7 @@ class PermissionsController extends import_base.BaseController {
1021
1017
  * console.log(`Permission ${result.permissionId} revoked`);
1022
1018
  * ```
1023
1019
  */
1024
- async submitRevokeWithSignature(params) {
1020
+ async submitRevokeWithSignature(params, options) {
1025
1021
  this.assertWallet();
1026
1022
  try {
1027
1023
  if (!this.context.walletClient?.chain?.id) {
@@ -1053,7 +1049,9 @@ class PermissionsController extends import_base.BaseController {
1053
1049
  signature,
1054
1050
  expectedUserAddress: this.context.userAddress
1055
1051
  });
1056
- if (response.type === "signed") {
1052
+ if (response.type === "submitted") {
1053
+ hash = response.hash;
1054
+ } else if (response.type === "signed") {
1057
1055
  hash = response.hash;
1058
1056
  } else if (response.type === "error") {
1059
1057
  throw new Error(`Relayer error: ${response.error}`);
@@ -1065,7 +1063,8 @@ class PermissionsController extends import_base.BaseController {
1065
1063
  } else {
1066
1064
  hash = await this.submitDirectRevokeTransaction(
1067
1065
  typedData,
1068
- signature
1066
+ signature,
1067
+ options
1069
1068
  );
1070
1069
  }
1071
1070
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -1391,7 +1390,9 @@ class PermissionsController extends import_base.BaseController {
1391
1390
  * ```
1392
1391
  */
1393
1392
  async getUserPermissionGrantsOnChain(options = {}) {
1394
- const { limit = 50, subgraphUrl } = options;
1393
+ const { limit = 50, fetchAll = false, subgraphUrl } = options;
1394
+ const pageSize = fetchAll ? 100 : limit;
1395
+ const maxResults = fetchAll ? 1e4 : limit;
1395
1396
  try {
1396
1397
  const userAddress = this.context.userAddress;
1397
1398
  const graphqlEndpoint = subgraphUrl ?? this.context.subgraphUrl;
@@ -1401,10 +1402,10 @@ class PermissionsController extends import_base.BaseController {
1401
1402
  );
1402
1403
  }
1403
1404
  const query = `
1404
- query GetUserPermissions($userId: ID!) {
1405
+ query GetUserPermissions($userId: ID!, $first: Int!, $skip: Int!) {
1405
1406
  user(id: $userId) {
1406
1407
  id
1407
- permissions {
1408
+ permissions(first: $first, skip: $skip, orderBy: addedAtBlock, orderDirection: desc) {
1408
1409
  id
1409
1410
  grant
1410
1411
  nonce
@@ -1422,34 +1423,82 @@ class PermissionsController extends import_base.BaseController {
1422
1423
  }
1423
1424
  }
1424
1425
  `;
1425
- const response = await fetch(graphqlEndpoint, {
1426
- method: "POST",
1427
- headers: {
1428
- "Content-Type": "application/json"
1429
- },
1430
- body: JSON.stringify({
1431
- query,
1432
- variables: {
1433
- userId: userAddress.toLowerCase()
1426
+ const allPermissions = [];
1427
+ let currentOffset = 0;
1428
+ if (!fetchAll) {
1429
+ const response = await fetch(graphqlEndpoint, {
1430
+ method: "POST",
1431
+ headers: {
1432
+ "Content-Type": "application/json"
1433
+ },
1434
+ body: JSON.stringify({
1435
+ query,
1436
+ variables: {
1437
+ userId: userAddress.toLowerCase(),
1438
+ first: limit,
1439
+ skip: 0
1440
+ }
1441
+ })
1442
+ });
1443
+ if (!response.ok) {
1444
+ throw new import_errors.BlockchainError(
1445
+ `Subgraph request failed: ${response.status} ${response.statusText}`
1446
+ );
1447
+ }
1448
+ const result = await response.json();
1449
+ if (result.errors) {
1450
+ throw new import_errors.BlockchainError(
1451
+ `Subgraph errors: ${result.errors.map((e) => e.message).join(", ")}`
1452
+ );
1453
+ }
1454
+ const userData = result.data?.user;
1455
+ if (!userData?.permissions?.length) {
1456
+ return [];
1457
+ }
1458
+ allPermissions.push(...userData.permissions);
1459
+ } else {
1460
+ while (allPermissions.length < maxResults) {
1461
+ const currentLimit = Math.min(
1462
+ pageSize,
1463
+ maxResults - allPermissions.length
1464
+ );
1465
+ const response = await fetch(graphqlEndpoint, {
1466
+ method: "POST",
1467
+ headers: {
1468
+ "Content-Type": "application/json"
1469
+ },
1470
+ body: JSON.stringify({
1471
+ query,
1472
+ variables: {
1473
+ userId: userAddress.toLowerCase(),
1474
+ first: currentLimit,
1475
+ skip: currentOffset
1476
+ }
1477
+ })
1478
+ });
1479
+ if (!response.ok) {
1480
+ throw new import_errors.BlockchainError(
1481
+ `Subgraph request failed: ${response.status} ${response.statusText}`
1482
+ );
1434
1483
  }
1435
- })
1436
- });
1437
- if (!response.ok) {
1438
- throw new import_errors.BlockchainError(
1439
- `Subgraph request failed: ${response.status} ${response.statusText}`
1440
- );
1441
- }
1442
- const result = await response.json();
1443
- if (result.errors) {
1444
- throw new import_errors.BlockchainError(
1445
- `Subgraph errors: ${result.errors.map((e) => e.message).join(", ")}`
1446
- );
1447
- }
1448
- const userData = result.data?.user;
1449
- if (!userData?.permissions?.length) {
1450
- return [];
1484
+ const result = await response.json();
1485
+ if (result.errors) {
1486
+ throw new import_errors.BlockchainError(
1487
+ `Subgraph errors: ${result.errors.map((e) => e.message).join(", ")}`
1488
+ );
1489
+ }
1490
+ const userData = result.data?.user;
1491
+ if (!userData?.permissions?.length) {
1492
+ break;
1493
+ }
1494
+ allPermissions.push(...userData.permissions);
1495
+ if (userData.permissions.length < currentLimit) {
1496
+ break;
1497
+ }
1498
+ currentOffset += userData.permissions.length;
1499
+ }
1451
1500
  }
1452
- const onChainGrants = userData.permissions.slice(0, limit).map(
1501
+ const onChainGrants = allPermissions.map(
1453
1502
  (permission) => ({
1454
1503
  id: BigInt(permission.id),
1455
1504
  grantUrl: permission.grant,
@@ -1630,7 +1679,7 @@ class PermissionsController extends import_base.BaseController {
1630
1679
  * @param params - Parameters for adding and trusting the server
1631
1680
  * @returns Promise resolving to TransactionResult with ServerTrustResult event data
1632
1681
  */
1633
- async submitAddAndTrustServerWithSignature(params) {
1682
+ async submitAddAndTrustServerWithSignature(params, options) {
1634
1683
  this.assertWallet();
1635
1684
  try {
1636
1685
  const nonce = await this.getServersUserNonce();
@@ -1666,7 +1715,9 @@ class PermissionsController extends import_base.BaseController {
1666
1715
  if (response.type === "error") {
1667
1716
  throw new import_errors.RelayerError(response.error);
1668
1717
  }
1669
- if (response.type === "signed") {
1718
+ if (response.type === "submitted") {
1719
+ hash = response.hash;
1720
+ } else if (response.type === "signed") {
1670
1721
  hash = response.hash;
1671
1722
  } else {
1672
1723
  throw new Error("Unexpected response type from relayer");
@@ -1674,7 +1725,8 @@ class PermissionsController extends import_base.BaseController {
1674
1725
  } else {
1675
1726
  hash = await this.submitAddAndTrustServerTransaction(
1676
1727
  addAndTrustServerInput,
1677
- signature
1728
+ signature,
1729
+ options
1678
1730
  );
1679
1731
  }
1680
1732
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -1713,7 +1765,7 @@ class PermissionsController extends import_base.BaseController {
1713
1765
  * @throws {ServerUrlMismatchError} When server URL doesn't match existing registration
1714
1766
  * @throws {BlockchainError} When trust operation fails for any other reason
1715
1767
  */
1716
- async submitTrustServerWithSignature(params) {
1768
+ async submitTrustServerWithSignature(params, options) {
1717
1769
  this.assertWallet();
1718
1770
  try {
1719
1771
  const nonce = await this.getServersUserNonce();
@@ -1735,7 +1787,9 @@ class PermissionsController extends import_base.BaseController {
1735
1787
  if (response.type === "error") {
1736
1788
  throw new import_errors.RelayerError(response.error);
1737
1789
  }
1738
- if (response.type === "signed") {
1790
+ if (response.type === "submitted") {
1791
+ hash = response.hash;
1792
+ } else if (response.type === "signed") {
1739
1793
  hash = response.hash;
1740
1794
  } else {
1741
1795
  throw new Error("Unexpected response type from relayer");
@@ -1743,7 +1797,8 @@ class PermissionsController extends import_base.BaseController {
1743
1797
  } else {
1744
1798
  hash = await this.submitTrustServerTransaction(
1745
1799
  trustServerInput,
1746
- signature
1800
+ signature,
1801
+ options
1747
1802
  );
1748
1803
  }
1749
1804
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -1905,7 +1960,9 @@ class PermissionsController extends import_base.BaseController {
1905
1960
  if (response.type === "error") {
1906
1961
  throw new import_errors.RelayerError(response.error);
1907
1962
  }
1908
- if (response.type === "signed") {
1963
+ if (response.type === "submitted") {
1964
+ hash = response.hash;
1965
+ } else if (response.type === "signed") {
1909
1966
  hash = response.hash;
1910
1967
  } else {
1911
1968
  throw new Error("Unexpected response type from relayer");
@@ -2351,7 +2408,7 @@ class PermissionsController extends import_base.BaseController {
2351
2408
  * @param signature - The cryptographic signature for the transaction
2352
2409
  * @returns Promise resolving to the transaction hash
2353
2410
  */
2354
- async submitAddAndTrustServerTransaction(addAndTrustServerInput, signature) {
2411
+ async submitAddAndTrustServerTransaction(addAndTrustServerInput, signature, options) {
2355
2412
  this.assertWallet();
2356
2413
  const chainId = await this.context.walletClient.getChainId();
2357
2414
  const DataPortabilityServersAddress = (0, import_addresses.getContractAddress)(
@@ -2385,7 +2442,16 @@ class PermissionsController extends import_base.BaseController {
2385
2442
  formattedSignature
2386
2443
  ],
2387
2444
  account: this.context.walletClient?.account ?? this.context.userAddress,
2388
- chain: this.context.walletClient?.chain ?? null
2445
+ chain: this.context.walletClient?.chain ?? null,
2446
+ ...options && {
2447
+ gas: options.gas,
2448
+ nonce: options.nonce,
2449
+ // Use EIP-1559 gas pricing if available, otherwise legacy
2450
+ ...options.maxFeePerGas || options.maxPriorityFeePerGas ? {
2451
+ maxFeePerGas: options.maxFeePerGas,
2452
+ maxPriorityFeePerGas: options.maxPriorityFeePerGas
2453
+ } : options.gasPrice ? { gasPrice: options.gasPrice } : {}
2454
+ }
2389
2455
  });
2390
2456
  return txHash;
2391
2457
  }
@@ -2429,7 +2495,7 @@ class PermissionsController extends import_base.BaseController {
2429
2495
  * @param signature - The cryptographic signature authorizing the revoke
2430
2496
  * @returns Promise resolving to the transaction hash
2431
2497
  */
2432
- async submitDirectRevokeTransaction(typedData, signature) {
2498
+ async submitDirectRevokeTransaction(typedData, signature, options) {
2433
2499
  this.assertWallet();
2434
2500
  const chainId = await this.context.walletClient.getChainId();
2435
2501
  const DataPortabilityPermissionsAddress = (0, import_addresses.getContractAddress)(
@@ -2444,7 +2510,16 @@ class PermissionsController extends import_base.BaseController {
2444
2510
  functionName: "revokePermissionWithSignature",
2445
2511
  args: [typedData.message, formattedSignature],
2446
2512
  account: this.context.walletClient?.account ?? this.context.userAddress,
2447
- chain: this.context.walletClient?.chain ?? null
2513
+ chain: this.context.walletClient?.chain ?? null,
2514
+ ...options && {
2515
+ gas: options.gas,
2516
+ nonce: options.nonce,
2517
+ // Use EIP-1559 gas pricing if available, otherwise legacy
2518
+ ...options.maxFeePerGas || options.maxPriorityFeePerGas ? {
2519
+ maxFeePerGas: options.maxFeePerGas,
2520
+ maxPriorityFeePerGas: options.maxPriorityFeePerGas
2521
+ } : options.gasPrice ? { gasPrice: options.gasPrice } : {}
2522
+ }
2448
2523
  });
2449
2524
  return txHash;
2450
2525
  }
@@ -2455,7 +2530,7 @@ class PermissionsController extends import_base.BaseController {
2455
2530
  * @param signature - The cryptographic signature authorizing the untrust
2456
2531
  * @returns Promise resolving to the transaction hash
2457
2532
  */
2458
- async submitSignedUntrustTransaction(typedData, signature, _options) {
2533
+ async submitSignedUntrustTransaction(typedData, signature, options) {
2459
2534
  this.assertWallet();
2460
2535
  const chainId = await this.context.walletClient.getChainId();
2461
2536
  const DataPortabilityServersAddress = (0, import_addresses.getContractAddress)(
@@ -2474,7 +2549,16 @@ class PermissionsController extends import_base.BaseController {
2474
2549
  functionName: "untrustServerWithSignature",
2475
2550
  args: [contractMessage, formattedSignature],
2476
2551
  account: this.context.walletClient?.account ?? this.context.userAddress,
2477
- chain: this.context.walletClient?.chain ?? null
2552
+ chain: this.context.walletClient?.chain ?? null,
2553
+ ...options && {
2554
+ gas: options.gas,
2555
+ nonce: options.nonce,
2556
+ // Use EIP-1559 gas pricing if available, otherwise legacy
2557
+ ...options.maxFeePerGas || options.maxPriorityFeePerGas ? {
2558
+ maxFeePerGas: options.maxFeePerGas,
2559
+ maxPriorityFeePerGas: options.maxPriorityFeePerGas
2560
+ } : options.gasPrice ? { gasPrice: options.gasPrice } : {}
2561
+ }
2478
2562
  });
2479
2563
  return txHash;
2480
2564
  }
@@ -2487,6 +2571,9 @@ class PermissionsController extends import_base.BaseController {
2487
2571
  * A grantee is an entity (like an application) that can receive data permissions
2488
2572
  * from users. Once registered, users can grant the grantee access to their data.
2489
2573
  *
2574
+ * This method supports gasless transactions via relayer when configured.
2575
+ * If no relayer is available, it falls back to direct wallet transactions.
2576
+ *
2490
2577
  * @param params - Parameters for registering the grantee
2491
2578
  * @param params.owner - The Ethereum address that will own this grantee registration
2492
2579
  * @param params.granteeAddress - The Ethereum address of the grantee (application)
@@ -2495,7 +2582,7 @@ class PermissionsController extends import_base.BaseController {
2495
2582
  * @returns Promise resolving to the transaction hash
2496
2583
  * @throws {BlockchainError} When the grantee registration transaction fails
2497
2584
  * @throws {UserRejectedRequestError} When user rejects the transaction
2498
- * @throws {ContractError} When grantee is already registered
2585
+ * @throws {RelayerError} When gasless transaction submission fails
2499
2586
  *
2500
2587
  * @example
2501
2588
  * ```typescript
@@ -2508,36 +2595,87 @@ class PermissionsController extends import_base.BaseController {
2508
2595
  * ```
2509
2596
  */
2510
2597
  async submitRegisterGrantee(params, options) {
2511
- this.assertWallet();
2512
- const chainId = await this.context.walletClient.getChainId();
2513
- const DataPortabilityGranteesAddress = (0, import_addresses.getContractAddress)(
2514
- chainId,
2515
- "DataPortabilityGrantees"
2516
- );
2517
- const DataPortabilityGranteesAbi = (0, import_abi.getAbi)("DataPortabilityGrantees");
2518
- const ownerAddress = (0, import_viem.getAddress)(params.owner);
2519
- const granteeAddress = (0, import_viem.getAddress)(params.granteeAddress);
2520
- const account = this.context.walletClient?.account ?? this.context.userAddress;
2521
- const txHash = await this.context.walletClient.writeContract({
2522
- address: DataPortabilityGranteesAddress,
2523
- abi: DataPortabilityGranteesAbi,
2524
- functionName: "registerGrantee",
2525
- args: [ownerAddress, granteeAddress, params.publicKey],
2526
- account,
2527
- chain: this.context.walletClient?.chain ?? null,
2528
- ...this.spreadTransactionOptions(options)
2529
- });
2530
- const { tx } = await import("../utils/transactionHelpers");
2531
- return tx({
2532
- hash: txHash,
2533
- from: typeof account === "string" ? account : account.address,
2534
- contract: "DataPortabilityGrantees",
2535
- fn: "registerGrantee"
2536
- });
2598
+ try {
2599
+ let hash;
2600
+ if (this.context.relayer) {
2601
+ const request = {
2602
+ type: "direct",
2603
+ operation: "submitRegisterGrantee",
2604
+ params: {
2605
+ owner: params.owner,
2606
+ granteeAddress: params.granteeAddress,
2607
+ publicKey: params.publicKey
2608
+ }
2609
+ };
2610
+ const response = await this.context.relayer(request);
2611
+ if (response.type === "error") {
2612
+ throw new import_errors.RelayerError(response.error);
2613
+ }
2614
+ if (response.type === "submitted") {
2615
+ hash = response.hash;
2616
+ } else if (response.type === "direct") {
2617
+ const result = response.result;
2618
+ hash = result.transactionHash;
2619
+ } else {
2620
+ throw new Error("Unexpected response type from relayer");
2621
+ }
2622
+ } else {
2623
+ this.assertWallet();
2624
+ const chainId = await this.context.walletClient.getChainId();
2625
+ const DataPortabilityGranteesAddress = (0, import_addresses.getContractAddress)(
2626
+ chainId,
2627
+ "DataPortabilityGrantees"
2628
+ );
2629
+ const DataPortabilityGranteesAbi = (0, import_abi.getAbi)("DataPortabilityGrantees");
2630
+ const ownerAddress = (0, import_viem.getAddress)(params.owner);
2631
+ const granteeAddress = (0, import_viem.getAddress)(params.granteeAddress);
2632
+ const account2 = this.context.walletClient?.account ?? this.context.userAddress;
2633
+ hash = await this.context.walletClient.writeContract({
2634
+ address: DataPortabilityGranteesAddress,
2635
+ abi: DataPortabilityGranteesAbi,
2636
+ functionName: "registerGrantee",
2637
+ args: [ownerAddress, granteeAddress, params.publicKey],
2638
+ account: account2,
2639
+ chain: this.context.walletClient?.chain ?? null,
2640
+ ...this.spreadTransactionOptions(options)
2641
+ });
2642
+ }
2643
+ const account = this.context.walletClient?.account ?? this.context.userAddress;
2644
+ const { tx } = await import("../utils/transactionHelpers");
2645
+ return tx({
2646
+ hash,
2647
+ from: typeof account === "string" ? account : account.address,
2648
+ contract: "DataPortabilityGrantees",
2649
+ fn: "registerGrantee"
2650
+ });
2651
+ } catch (error) {
2652
+ if (error instanceof Error) {
2653
+ if (error instanceof import_errors.RelayerError || error instanceof import_errors.UserRejectedRequestError || error instanceof import_errors.SerializationError || error instanceof import_errors.SignatureError || error instanceof import_errors.BlockchainError) {
2654
+ throw error;
2655
+ }
2656
+ if (error.name === "ContractFunctionExecutionError") {
2657
+ throw new import_errors.BlockchainError(
2658
+ `Grantee registration failed: ${error.message}`,
2659
+ error
2660
+ );
2661
+ }
2662
+ if (error.name === "UserRejectedRequestError") {
2663
+ throw new import_errors.UserRejectedRequestError(
2664
+ "User rejected the grantee registration transaction"
2665
+ );
2666
+ }
2667
+ throw new import_errors.BlockchainError(
2668
+ `Failed to register grantee: ${error.message}`,
2669
+ error
2670
+ );
2671
+ }
2672
+ throw new import_errors.BlockchainError(`Failed to register grantee: ${String(error)}`);
2673
+ }
2537
2674
  }
2538
2675
  // TODO: When DataPortabilityGrantees contract adds registerGranteeWithSignature function,
2539
2676
  // implement submitRegisterGranteeWithSignature and submitSignedRegisterGrantee methods
2540
- // to support gasless transactions via relayer
2677
+ // to support EIP-712 signed gasless transactions via relayer.
2678
+ // Current implementation above supports direct gasless transactions (relayer pays gas directly).
2541
2679
  /**
2542
2680
  * Retrieves all registered grantees from the DataPortabilityGrantees contract.
2543
2681
  *
@@ -2585,27 +2723,52 @@ class PermissionsController extends import_base.BaseController {
2585
2723
  const total = Number(totalCount);
2586
2724
  const limit = options.limit ?? 50;
2587
2725
  const offset = options.offset ?? 0;
2588
- const grantees = [];
2589
- const endIndex = Math.min(offset + limit, total);
2590
- for (let i = offset; i < endIndex; i++) {
2591
- try {
2592
- const granteeInfo = await this.context.publicClient.readContract({
2593
- address: DataPortabilityGranteesAddress,
2594
- abi: DataPortabilityGranteesAbi,
2595
- functionName: "grantees",
2596
- args: [BigInt(i + 1)]
2597
- // Grantee IDs are 1-indexed
2598
- });
2599
- grantees.push({
2600
- id: i + 1,
2601
- owner: granteeInfo.owner,
2602
- address: granteeInfo.granteeAddress,
2603
- publicKey: granteeInfo.publicKey,
2604
- permissionIds: granteeInfo.permissionIds.map((id) => Number(id))
2605
- });
2606
- } catch (error) {
2607
- console.warn(`Failed to fetch grantee ${i + 1}:`, error);
2608
- }
2726
+ const includePermissions = options.includePermissions ?? true;
2727
+ const startId = total - offset;
2728
+ const endId = Math.max(startId - limit + 1, 1);
2729
+ const granteeIds = Array.from(
2730
+ { length: startId - endId + 1 },
2731
+ (_, i) => startId - i
2732
+ // Generate IDs in descending order
2733
+ );
2734
+ let grantees;
2735
+ if (includePermissions) {
2736
+ const granteePromises = granteeIds.map(
2737
+ (granteeId) => this.getGranteeById(granteeId)
2738
+ );
2739
+ const granteeResults = await Promise.all(granteePromises);
2740
+ grantees = granteeResults.filter(
2741
+ (grantee) => grantee !== null
2742
+ );
2743
+ } else {
2744
+ const granteeInfoPromises = granteeIds.map(
2745
+ async (granteeId) => {
2746
+ try {
2747
+ const granteeInfo = await this.context.publicClient.readContract({
2748
+ address: DataPortabilityGranteesAddress,
2749
+ abi: DataPortabilityGranteesAbi,
2750
+ functionName: "granteesV2",
2751
+ args: [BigInt(granteeId)]
2752
+ });
2753
+ const grantee = {
2754
+ id: granteeId,
2755
+ owner: granteeInfo.owner,
2756
+ address: granteeInfo.granteeAddress,
2757
+ publicKey: granteeInfo.publicKey,
2758
+ permissionIds: []
2759
+ // TypeScript infers number[] from Grantee type
2760
+ };
2761
+ return grantee;
2762
+ } catch (error) {
2763
+ console.warn(`Failed to fetch grantee ${granteeId}:`, error);
2764
+ return null;
2765
+ }
2766
+ }
2767
+ );
2768
+ const granteeInfoResults = await Promise.all(granteeInfoPromises);
2769
+ grantees = granteeInfoResults.filter(
2770
+ (grantee) => grantee !== null
2771
+ );
2609
2772
  }
2610
2773
  return {
2611
2774
  grantees,
@@ -2616,15 +2779,16 @@ class PermissionsController extends import_base.BaseController {
2616
2779
  };
2617
2780
  }
2618
2781
  /**
2619
- * Retrieves a specific grantee by their Ethereum address from the DataPortabilityGrantees contract.
2782
+ * Retrieves a specific grantee by their Ethereum wallet address.
2620
2783
  *
2784
+ * @remarks
2621
2785
  * Looks up a registered grantee (application) using their Ethereum address
2622
- * and returns their complete registration information including permissions.
2786
+ * and returns their complete registration information including all associated permissions.
2623
2787
  *
2624
- * @param granteeAddress - The Ethereum address of the grantee to look up
2625
- * @returns Promise resolving to the grantee information, or null if not found
2626
- * @throws {BlockchainError} When contract read operation fails
2627
- * @throws {NetworkError} When unable to connect to the blockchain network
2788
+ * Returns `null` if the address is not registered as a grantee or if an error occurs.
2789
+ *
2790
+ * @param granteeAddress - Ethereum wallet address of the grantee to query
2791
+ * @returns Grantee information including ID, addresses, public key, and permission IDs, or `null` if not found
2628
2792
  *
2629
2793
  * @example
2630
2794
  * ```typescript
@@ -2649,40 +2813,32 @@ class PermissionsController extends import_base.BaseController {
2649
2813
  );
2650
2814
  const DataPortabilityGranteesAbi = (0, import_abi.getAbi)("DataPortabilityGrantees");
2651
2815
  try {
2652
- const granteeInfo = await this.context.publicClient.readContract({
2653
- address: DataPortabilityGranteesAddress,
2654
- abi: DataPortabilityGranteesAbi,
2655
- functionName: "granteeByAddress",
2656
- args: [granteeAddress]
2657
- });
2658
2816
  const granteeId = await this.context.publicClient.readContract({
2659
2817
  address: DataPortabilityGranteesAddress,
2660
2818
  abi: DataPortabilityGranteesAbi,
2661
2819
  functionName: "granteeAddressToId",
2662
2820
  args: [granteeAddress]
2663
2821
  });
2664
- return {
2665
- id: Number(granteeId),
2666
- owner: granteeInfo.owner,
2667
- address: granteeInfo.granteeAddress,
2668
- publicKey: granteeInfo.publicKey,
2669
- permissionIds: granteeInfo.permissionIds.map((id) => Number(id))
2670
- };
2822
+ if (granteeId === 0n) {
2823
+ return null;
2824
+ }
2825
+ return await this.getGranteeById(Number(granteeId));
2671
2826
  } catch (error) {
2672
2827
  console.warn(`Failed to fetch grantee ${granteeAddress}:`, error);
2673
2828
  return null;
2674
2829
  }
2675
2830
  }
2676
2831
  /**
2677
- * Retrieves a specific grantee by their unique ID from the DataPortabilityGrantees contract.
2832
+ * Retrieves a specific grantee by their unique ID.
2678
2833
  *
2834
+ * @remarks
2679
2835
  * Looks up a registered grantee (application) using their numeric ID assigned during
2680
- * registration and returns their complete information including permissions.
2836
+ * registration and returns their complete information including all associated permissions.
2681
2837
  *
2682
- * @param granteeId - The unique numeric ID of the grantee (1-indexed)
2683
- * @returns Promise resolving to the grantee information, or null if not found
2684
- * @throws {BlockchainError} When contract read operation fails
2685
- * @throws {NetworkError} When unable to connect to the blockchain network
2838
+ * Returns `null` if the grantee is not found or if an error occurs during fetching.
2839
+ *
2840
+ * @param granteeId - Unique numeric ID of the grantee (1-indexed)
2841
+ * @returns Grantee information including ID, addresses, public key, and permission IDs, or `null` if not found
2686
2842
  *
2687
2843
  * @example
2688
2844
  * ```typescript
@@ -2690,7 +2846,7 @@ class PermissionsController extends import_base.BaseController {
2690
2846
  *
2691
2847
  * if (grantee) {
2692
2848
  * console.log(`Grantee ID: ${grantee.id}`);
2693
- * console.log(`Address: ${grantee.granteeAddress}`);
2849
+ * console.log(`Address: ${grantee.address}`);
2694
2850
  * console.log(`Owner: ${grantee.owner}`);
2695
2851
  * console.log(`Total permissions: ${grantee.permissionIds.length}`);
2696
2852
  * } else {
@@ -2706,18 +2862,23 @@ class PermissionsController extends import_base.BaseController {
2706
2862
  );
2707
2863
  const DataPortabilityGranteesAbi = (0, import_abi.getAbi)("DataPortabilityGrantees");
2708
2864
  try {
2709
- const granteeInfo = await this.context.publicClient.readContract({
2865
+ const granteeInfoResult = await this.context.publicClient.readContract({
2710
2866
  address: DataPortabilityGranteesAddress,
2711
2867
  abi: DataPortabilityGranteesAbi,
2712
- functionName: "grantees",
2868
+ functionName: "granteesV2",
2713
2869
  args: [BigInt(granteeId)]
2714
2870
  });
2871
+ const granteeInfo = granteeInfoResult;
2872
+ const allPermissionIdsResult = await this.getGranteePermissionsPaginated(
2873
+ BigInt(granteeId)
2874
+ );
2875
+ const allPermissionIds = allPermissionIdsResult;
2715
2876
  return {
2716
2877
  id: granteeId,
2717
2878
  owner: granteeInfo.owner,
2718
2879
  address: granteeInfo.granteeAddress,
2719
2880
  publicKey: granteeInfo.publicKey,
2720
- permissionIds: granteeInfo.permissionIds.map((id) => Number(id))
2881
+ permissionIds: allPermissionIds.map((id) => Number(id))
2721
2882
  };
2722
2883
  } catch (error) {
2723
2884
  console.warn(`Failed to fetch grantee ${granteeId}:`, error);
@@ -3114,6 +3275,31 @@ class PermissionsController extends import_base.BaseController {
3114
3275
  );
3115
3276
  }
3116
3277
  }
3278
+ /**
3279
+ * Retrieves detailed grant file data from IPFS or HTTP storage.
3280
+ *
3281
+ * @remarks
3282
+ * This method automatically uses the SDK's configured downloadRelayer to bypass CORS restrictions.
3283
+ * Use this instead of importing the standalone `retrieveGrantFile` utility.
3284
+ *
3285
+ * @param grantUrl - The grant file URL (from OnChainPermissionGrant.grantUrl)
3286
+ * @returns Promise resolving to the complete grant file with operation details
3287
+ * @throws {NetworkError} When all retrieval attempts fail
3288
+ * @example
3289
+ * ```typescript
3290
+ * const grants = await vana.permissions.getUserPermissionGrantsOnChain();
3291
+ * const grantFile = await vana.permissions.retrieveGrantFile(grants[0].grantUrl);
3292
+ * console.log(`Operation: ${grantFile.operation}`);
3293
+ * ```
3294
+ */
3295
+ async retrieveGrantFile(grantUrl) {
3296
+ const { retrieveGrantFile: retrieveGrantFileUtil } = await import("../utils/grantFiles");
3297
+ return retrieveGrantFileUtil(
3298
+ grantUrl,
3299
+ void 0,
3300
+ this.context.downloadRelayer
3301
+ );
3302
+ }
3117
3303
  /**
3118
3304
  * Get all permissions for a specific file (alias for getFilePermissionIds)
3119
3305
  *
@@ -3139,26 +3325,34 @@ class PermissionsController extends import_base.BaseController {
3139
3325
  // DATA PORTABILITY GRANTEES HELPER METHODS
3140
3326
  // ===========================
3141
3327
  /**
3142
- * Get grantee information by grantee ID
3328
+ * Retrieves detailed grantee information including all associated permissions.
3329
+ *
3330
+ * @remarks
3331
+ * Returns grantee metadata and associated permission IDs. Uses the newer
3332
+ * paginated contract method internally for efficient permission fetching.
3333
+ *
3334
+ * @param granteeId - Unique grantee identifier as bigint
3335
+ * @returns Grantee information containing owner address, grantee address, public key, and permission IDs
3336
+ * @throws {BlockchainError} When grantee ID is not found or contract read fails
3143
3337
  *
3144
- * @param granteeId - Grantee ID to get info for
3145
- * @returns Promise resolving to grantee info
3338
+ * @example
3339
+ * ```typescript
3340
+ * const granteeInfo = await vana.permissions.getGranteeInfo(BigInt(1));
3341
+ * console.log(`Grantee ${granteeInfo.granteeAddress} has ${granteeInfo.permissionIds.length} permissions`);
3342
+ * ```
3146
3343
  */
3147
3344
  async getGranteeInfo(granteeId) {
3148
3345
  try {
3149
- const chainId = await this.context.publicClient.getChainId();
3150
- const DataPortabilityGranteesAddress = (0, import_addresses.getContractAddress)(
3151
- chainId,
3152
- "DataPortabilityGrantees"
3153
- );
3154
- const DataPortabilityGranteesAbi = (0, import_abi.getAbi)("DataPortabilityGrantees");
3155
- const granteeInfo = await this.context.publicClient.readContract({
3156
- address: DataPortabilityGranteesAddress,
3157
- abi: DataPortabilityGranteesAbi,
3158
- functionName: "granteeInfo",
3159
- args: [granteeId]
3160
- });
3161
- return granteeInfo;
3346
+ const grantee = await this.getGranteeById(Number(granteeId));
3347
+ if (!grantee) {
3348
+ throw new Error("Grantee not found");
3349
+ }
3350
+ return {
3351
+ owner: grantee.owner,
3352
+ granteeAddress: grantee.address,
3353
+ publicKey: grantee.publicKey,
3354
+ permissionIds: grantee.permissionIds.map((id) => BigInt(id))
3355
+ };
3162
3356
  } catch (error) {
3163
3357
  throw new import_errors.BlockchainError(
3164
3358
  `Failed to get grantee info: ${error instanceof Error ? error.message : "Unknown error"}`,
@@ -3167,10 +3361,21 @@ class PermissionsController extends import_base.BaseController {
3167
3361
  }
3168
3362
  }
3169
3363
  /**
3170
- * Get grantee information by grantee address
3364
+ * Retrieves detailed grantee information by wallet address.
3171
3365
  *
3172
- * @param granteeAddress - Grantee address to get info for
3173
- * @returns Promise resolving to grantee info
3366
+ * @remarks
3367
+ * Looks up the grantee ID from the provided address, then fetches complete
3368
+ * grantee information including all associated permissions.
3369
+ *
3370
+ * @param granteeAddress - Ethereum wallet address of the grantee to query
3371
+ * @returns Grantee information containing owner address, grantee address, public key, and permission IDs
3372
+ * @throws {BlockchainError} When grantee address is not registered or contract read fails
3373
+ *
3374
+ * @example
3375
+ * ```typescript
3376
+ * const granteeInfo = await vana.permissions.getGranteeInfoByAddress("0x742d35Cc6634c0532925a3b844Bc9e8e1ee3b2De");
3377
+ * console.log(`Found grantee with ${granteeInfo.permissionIds.length} permissions`);
3378
+ * ```
3174
3379
  */
3175
3380
  async getGranteeInfoByAddress(granteeAddress) {
3176
3381
  try {
@@ -3180,13 +3385,26 @@ class PermissionsController extends import_base.BaseController {
3180
3385
  "DataPortabilityGrantees"
3181
3386
  );
3182
3387
  const DataPortabilityGranteesAbi = (0, import_abi.getAbi)("DataPortabilityGrantees");
3183
- const granteeInfo = await this.context.publicClient.readContract({
3388
+ const granteeIdResult = await this.context.publicClient.readContract({
3184
3389
  address: DataPortabilityGranteesAddress,
3185
3390
  abi: DataPortabilityGranteesAbi,
3186
- functionName: "granteeByAddress",
3391
+ functionName: "granteeAddressToId",
3187
3392
  args: [granteeAddress]
3188
3393
  });
3189
- return granteeInfo;
3394
+ const granteeId = granteeIdResult;
3395
+ if (granteeId === 0n) {
3396
+ throw new Error("Grantee not found");
3397
+ }
3398
+ const grantee = await this.getGranteeById(Number(granteeId));
3399
+ if (!grantee) {
3400
+ throw new Error("Grantee not found");
3401
+ }
3402
+ return {
3403
+ owner: grantee.owner,
3404
+ granteeAddress: grantee.address,
3405
+ publicKey: grantee.publicKey,
3406
+ permissionIds: grantee.permissionIds.map((id) => BigInt(id))
3407
+ };
3190
3408
  } catch (error) {
3191
3409
  throw new import_errors.BlockchainError(
3192
3410
  `Failed to get grantee info by address: ${error instanceof Error ? error.message : "Unknown error"}`,
@@ -3250,6 +3468,117 @@ class PermissionsController extends import_base.BaseController {
3250
3468
  );
3251
3469
  }
3252
3470
  }
3471
+ /**
3472
+ * Retrieves permission IDs for a specific grantee with flexible pagination.
3473
+ *
3474
+ * @remarks
3475
+ * **Pagination Behavior:**
3476
+ * Returns different types based on parameters:
3477
+ * - Without offset/limit: Returns `bigint[]` of all permissions using batched multicall
3478
+ * - With offset/limit: Returns paginated object with `permissionIds`, `totalCount`, and `hasMore`
3479
+ *
3480
+ * Uses gas-aware multicall for efficient batch fetching when retrieving all permissions.
3481
+ *
3482
+ * @param granteeId - Grantee ID to get permissions for
3483
+ * @param options - Optional pagination parameters
3484
+ * @param options.offset - Zero-based starting index for pagination. Defaults to 0 when fetching all permissions. Required for single-page requests.
3485
+ * @param options.limit - Maximum number of permission IDs to return per page. Defaults to 100 when fetching all permissions. Required for single-page requests.
3486
+ * @returns When called without options: Array of all permission IDs as `bigint[]`.
3487
+ * When called with offset and limit: Paginated result object containing `permissionIds` array,
3488
+ * `totalCount`, and `hasMore` boolean.
3489
+ * @throws {BlockchainError} When contract read operation fails
3490
+ *
3491
+ * @example
3492
+ * ```typescript
3493
+ * // Fetch all permissions (no pagination params)
3494
+ * const allPermissions = await vana.permissions.getGranteePermissionsPaginated(BigInt(1));
3495
+ * console.log(`Total permissions: ${allPermissions.length}`);
3496
+ *
3497
+ * // Fetch a specific page (with pagination params)
3498
+ * const page = await vana.permissions.getGranteePermissionsPaginated(BigInt(1), {
3499
+ * offset: BigInt(0),
3500
+ * limit: BigInt(100)
3501
+ * });
3502
+ * console.log(`Fetched ${page.permissionIds.length} permissions`);
3503
+ * console.log(`Total: ${page.totalCount}, Has more: ${page.hasMore}`);
3504
+ *
3505
+ * // Fetch next page
3506
+ * if (page.hasMore) {
3507
+ * const nextPage = await vana.permissions.getGranteePermissionsPaginated(BigInt(1), {
3508
+ * offset: BigInt(100),
3509
+ * limit: BigInt(100)
3510
+ * });
3511
+ * }
3512
+ * ```
3513
+ */
3514
+ async getGranteePermissionsPaginated(granteeId, options) {
3515
+ try {
3516
+ const chainId = await this.context.publicClient.getChainId();
3517
+ const DataPortabilityGranteesAddress = (0, import_addresses.getContractAddress)(
3518
+ chainId,
3519
+ "DataPortabilityGrantees"
3520
+ );
3521
+ const DataPortabilityGranteesAbi = (0, import_abi.getAbi)("DataPortabilityGrantees");
3522
+ const fetchOnlyOnePage = options?.offset !== void 0 && options?.limit !== void 0;
3523
+ if (fetchOnlyOnePage) {
3524
+ const result = await this.context.publicClient.readContract({
3525
+ address: DataPortabilityGranteesAddress,
3526
+ abi: DataPortabilityGranteesAbi,
3527
+ functionName: "granteePermissionsPaginated",
3528
+ args: [granteeId, options.offset, options.limit]
3529
+ });
3530
+ const [permissionIds, totalCount2, hasMore] = result;
3531
+ return {
3532
+ permissionIds: [...permissionIds],
3533
+ totalCount: totalCount2,
3534
+ hasMore
3535
+ };
3536
+ }
3537
+ const countResult = await this.context.publicClient.readContract({
3538
+ address: DataPortabilityGranteesAddress,
3539
+ abi: DataPortabilityGranteesAbi,
3540
+ functionName: "granteePermissionsPaginated",
3541
+ args: [granteeId, BigInt(0), BigInt(1)]
3542
+ });
3543
+ const [, totalCount] = countResult;
3544
+ if (totalCount === BigInt(0)) {
3545
+ return [];
3546
+ }
3547
+ const batchSize = options?.limit ?? BigInt(100);
3548
+ const startOffset = options?.offset ?? BigInt(0);
3549
+ const endOffset = totalCount;
3550
+ const numBatches = Math.ceil(
3551
+ Number(endOffset - startOffset) / Number(batchSize)
3552
+ );
3553
+ const paginationCalls = Array.from({ length: numBatches }, (_, i) => ({
3554
+ address: DataPortabilityGranteesAddress,
3555
+ abi: DataPortabilityGranteesAbi,
3556
+ functionName: "granteePermissionsPaginated",
3557
+ args: [
3558
+ granteeId,
3559
+ startOffset + BigInt(i) * batchSize,
3560
+ batchSize
3561
+ ]
3562
+ }));
3563
+ const results = await (0, import_multicall.gasAwareMulticall)(
3564
+ this.context.publicClient,
3565
+ {
3566
+ contracts: paginationCalls
3567
+ }
3568
+ );
3569
+ const allPermissionIds = [];
3570
+ for (const result of results) {
3571
+ const [permissionIds] = result;
3572
+ allPermissionIds.push(...permissionIds);
3573
+ }
3574
+ return allPermissionIds;
3575
+ } catch (error) {
3576
+ throw new import_errors.BlockchainError(
3577
+ `Failed to get grantee permissions: ${error instanceof Error ? error.message : "Unknown error"}`,
3578
+ error
3579
+ );
3580
+ }
3581
+ }
3253
3582
  // ===== DataPortabilityServersImplementation Methods =====
3254
3583
  /**
3255
3584
  * Get all server IDs for a user
@@ -3684,7 +4013,9 @@ class PermissionsController extends import_base.BaseController {
3684
4013
  if (response.type === "error") {
3685
4014
  throw new import_errors.RelayerError(response.error);
3686
4015
  }
3687
- if (response.type === "signed") {
4016
+ if (response.type === "submitted") {
4017
+ hash = response.hash;
4018
+ } else if (response.type === "signed") {
3688
4019
  hash = response.hash;
3689
4020
  } else {
3690
4021
  throw new Error("Unexpected response type from relayer");
@@ -3862,7 +4193,9 @@ class PermissionsController extends import_base.BaseController {
3862
4193
  if (response.type === "error") {
3863
4194
  throw new import_errors.RelayerError(response.error);
3864
4195
  }
3865
- if (response.type === "signed") {
4196
+ if (response.type === "submitted") {
4197
+ hash = response.hash;
4198
+ } else if (response.type === "signed") {
3866
4199
  hash = response.hash;
3867
4200
  } else {
3868
4201
  throw new Error("Unexpected response type from relayer");