@opendatalabs/vana-sdk 0.1.0-alpha.a6b60fc → 0.1.0-alpha.a78ce5c

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 (256) hide show
  1. package/dist/client/__tests__/enhancedResponse.test.d.ts +1 -0
  2. package/dist/client/enhancedResponse.cjs +164 -0
  3. package/dist/client/enhancedResponse.cjs.map +1 -0
  4. package/dist/client/enhancedResponse.d.ts +120 -0
  5. package/dist/client/enhancedResponse.js +138 -0
  6. package/dist/client/enhancedResponse.js.map +1 -0
  7. package/dist/controllers/__tests__/data-consistency-integration.test.d.ts +7 -0
  8. package/dist/controllers/__tests__/operations.processQueue.test.d.ts +1 -0
  9. package/dist/controllers/base.cjs +33 -0
  10. package/dist/controllers/base.cjs.map +1 -1
  11. package/dist/controllers/base.d.ts +10 -0
  12. package/dist/controllers/base.js +33 -0
  13. package/dist/controllers/base.js.map +1 -1
  14. package/dist/controllers/data.cjs +278 -159
  15. package/dist/controllers/data.cjs.map +1 -1
  16. package/dist/controllers/data.d.ts +34 -19
  17. package/dist/controllers/data.js +291 -162
  18. package/dist/controllers/data.js.map +1 -1
  19. package/dist/controllers/operations.cjs +430 -0
  20. package/dist/controllers/operations.cjs.map +1 -0
  21. package/dist/controllers/operations.d.ts +229 -0
  22. package/dist/controllers/operations.js +406 -0
  23. package/dist/controllers/operations.js.map +1 -0
  24. package/dist/controllers/permissions.cjs +605 -213
  25. package/dist/controllers/permissions.cjs.map +1 -1
  26. package/dist/controllers/permissions.d.ts +141 -34
  27. package/dist/controllers/permissions.js +605 -213
  28. package/dist/controllers/permissions.js.map +1 -1
  29. package/dist/controllers/schemas.cjs +81 -4
  30. package/dist/controllers/schemas.cjs.map +1 -1
  31. package/dist/controllers/schemas.d.ts +41 -0
  32. package/dist/controllers/schemas.js +81 -4
  33. package/dist/controllers/schemas.js.map +1 -1
  34. package/dist/controllers/server.cjs +251 -42
  35. package/dist/controllers/server.cjs.map +1 -1
  36. package/dist/controllers/server.d.ts +111 -14
  37. package/dist/controllers/server.js +251 -42
  38. package/dist/controllers/server.js.map +1 -1
  39. package/dist/core/__tests__/health.test.d.ts +1 -0
  40. package/dist/core/__tests__/inMemoryNonceManager.test.d.ts +1 -0
  41. package/dist/core/__tests__/nonceManager.test.d.ts +1 -0
  42. package/dist/core/__tests__/pollingManager.test.d.ts +4 -0
  43. package/dist/core/health.cjs +289 -0
  44. package/dist/core/health.cjs.map +1 -0
  45. package/dist/core/health.d.ts +143 -0
  46. package/dist/core/health.js +265 -0
  47. package/dist/core/health.js.map +1 -0
  48. package/dist/core/inMemoryNonceManager.cjs +138 -0
  49. package/dist/core/inMemoryNonceManager.cjs.map +1 -0
  50. package/dist/core/inMemoryNonceManager.d.ts +69 -0
  51. package/dist/core/inMemoryNonceManager.js +114 -0
  52. package/dist/core/inMemoryNonceManager.js.map +1 -0
  53. package/dist/core/nonceManager.cjs +304 -0
  54. package/dist/core/nonceManager.cjs.map +1 -0
  55. package/dist/core/nonceManager.d.ts +116 -0
  56. package/dist/core/nonceManager.js +280 -0
  57. package/dist/core/nonceManager.js.map +1 -0
  58. package/dist/core/pollingManager.cjs +292 -0
  59. package/dist/core/pollingManager.cjs.map +1 -0
  60. package/dist/core/pollingManager.d.ts +120 -0
  61. package/dist/core/pollingManager.js +268 -0
  62. package/dist/core/pollingManager.js.map +1 -0
  63. package/dist/core.cjs +55 -1
  64. package/dist/core.cjs.map +1 -1
  65. package/dist/core.d.ts +54 -3
  66. package/dist/core.js +55 -1
  67. package/dist/core.js.map +1 -1
  68. package/dist/crypto/ecies/base.cjs +16 -3
  69. package/dist/crypto/ecies/base.cjs.map +1 -1
  70. package/dist/crypto/ecies/base.js +16 -3
  71. package/dist/crypto/ecies/base.js.map +1 -1
  72. package/dist/errors.cjs +29 -0
  73. package/dist/errors.cjs.map +1 -1
  74. package/dist/errors.d.ts +64 -0
  75. package/dist/errors.js +28 -0
  76. package/dist/errors.js.map +1 -1
  77. package/dist/generated/abi/ComputeInstructionRegistryImplementation.cjs.map +1 -1
  78. package/dist/generated/abi/ComputeInstructionRegistryImplementation.js.map +1 -1
  79. package/dist/generated/abi/DLPPerformanceImplementation.cjs +42 -0
  80. package/dist/generated/abi/DLPPerformanceImplementation.cjs.map +1 -1
  81. package/dist/generated/abi/DLPPerformanceImplementation.d.ts +32 -0
  82. package/dist/generated/abi/DLPPerformanceImplementation.js +42 -0
  83. package/dist/generated/abi/DLPPerformanceImplementation.js.map +1 -1
  84. package/dist/generated/abi/DLPRegistryImplementation.cjs +5 -5
  85. package/dist/generated/abi/DLPRegistryImplementation.cjs.map +1 -1
  86. package/dist/generated/abi/DLPRegistryImplementation.d.ts +4 -4
  87. package/dist/generated/abi/DLPRegistryImplementation.js +5 -5
  88. package/dist/generated/abi/DLPRegistryImplementation.js.map +1 -1
  89. package/dist/generated/abi/DLPRewardDeployerImplementation.cjs +166 -2
  90. package/dist/generated/abi/DLPRewardDeployerImplementation.cjs.map +1 -1
  91. package/dist/generated/abi/DLPRewardDeployerImplementation.d.ts +129 -2
  92. package/dist/generated/abi/DLPRewardDeployerImplementation.js +166 -2
  93. package/dist/generated/abi/DLPRewardDeployerImplementation.js.map +1 -1
  94. package/dist/generated/abi/DataPortabilityGranteesImplementation.cjs +167 -19
  95. package/dist/generated/abi/DataPortabilityGranteesImplementation.cjs.map +1 -1
  96. package/dist/generated/abi/DataPortabilityGranteesImplementation.d.ts +127 -14
  97. package/dist/generated/abi/DataPortabilityGranteesImplementation.js +167 -19
  98. package/dist/generated/abi/DataPortabilityGranteesImplementation.js.map +1 -1
  99. package/dist/generated/abi/DataPortabilityPermissionsImplementation.cjs +0 -19
  100. package/dist/generated/abi/DataPortabilityPermissionsImplementation.cjs.map +1 -1
  101. package/dist/generated/abi/DataPortabilityPermissionsImplementation.d.ts +0 -14
  102. package/dist/generated/abi/DataPortabilityPermissionsImplementation.js +0 -19
  103. package/dist/generated/abi/DataPortabilityPermissionsImplementation.js.map +1 -1
  104. package/dist/generated/abi/DataPortabilityServersImplementation.cjs +0 -19
  105. package/dist/generated/abi/DataPortabilityServersImplementation.cjs.map +1 -1
  106. package/dist/generated/abi/DataPortabilityServersImplementation.d.ts +0 -14
  107. package/dist/generated/abi/DataPortabilityServersImplementation.js +0 -19
  108. package/dist/generated/abi/DataPortabilityServersImplementation.js.map +1 -1
  109. package/dist/generated/abi/DataRegistryImplementation.cjs +0 -13
  110. package/dist/generated/abi/DataRegistryImplementation.cjs.map +1 -1
  111. package/dist/generated/abi/DataRegistryImplementation.d.ts +0 -10
  112. package/dist/generated/abi/DataRegistryImplementation.js +0 -13
  113. package/dist/generated/abi/DataRegistryImplementation.js.map +1 -1
  114. package/dist/generated/abi/SwapHelperImplementation.cjs +0 -43
  115. package/dist/generated/abi/SwapHelperImplementation.cjs.map +1 -1
  116. package/dist/generated/abi/SwapHelperImplementation.d.ts +0 -35
  117. package/dist/generated/abi/SwapHelperImplementation.js +0 -43
  118. package/dist/generated/abi/SwapHelperImplementation.js.map +1 -1
  119. package/dist/generated/abi/VanaEpochImplementation.cjs +195 -0
  120. package/dist/generated/abi/VanaEpochImplementation.cjs.map +1 -1
  121. package/dist/generated/abi/VanaEpochImplementation.d.ts +151 -0
  122. package/dist/generated/abi/VanaEpochImplementation.js +195 -0
  123. package/dist/generated/abi/VanaEpochImplementation.js.map +1 -1
  124. package/dist/generated/abi/VanaPoolEntityImplementation.cjs +22 -65
  125. package/dist/generated/abi/VanaPoolEntityImplementation.cjs.map +1 -1
  126. package/dist/generated/abi/VanaPoolEntityImplementation.d.ts +17 -51
  127. package/dist/generated/abi/VanaPoolEntityImplementation.js +22 -65
  128. package/dist/generated/abi/VanaPoolEntityImplementation.js.map +1 -1
  129. package/dist/generated/abi/VanaPoolStakingImplementation.cjs +113 -1
  130. package/dist/generated/abi/VanaPoolStakingImplementation.cjs.map +1 -1
  131. package/dist/generated/abi/VanaPoolStakingImplementation.d.ts +85 -1
  132. package/dist/generated/abi/VanaPoolStakingImplementation.js +113 -1
  133. package/dist/generated/abi/VanaPoolStakingImplementation.js.map +1 -1
  134. package/dist/generated/abi/index.d.ts +546 -146
  135. package/dist/generated/event-types.cjs.map +1 -1
  136. package/dist/generated/event-types.d.ts +14 -8
  137. package/dist/generated/eventRegistry.cjs +42 -18
  138. package/dist/generated/eventRegistry.cjs.map +1 -1
  139. package/dist/generated/eventRegistry.js +42 -18
  140. package/dist/generated/eventRegistry.js.map +1 -1
  141. package/dist/generated/server/server-exports.cjs +22 -0
  142. package/dist/generated/server/server-exports.cjs.map +1 -1
  143. package/dist/generated/server/server-exports.d.ts +27 -10
  144. package/dist/generated/server/server-exports.js +17 -0
  145. package/dist/generated/server/server-exports.js.map +1 -1
  146. package/dist/generated/server/server.cjs.map +1 -1
  147. package/dist/generated/server/server.d.ts +771 -402
  148. package/dist/generated/subgraph.cjs +797 -32
  149. package/dist/generated/subgraph.cjs.map +1 -1
  150. package/dist/generated/subgraph.d.ts +135 -0
  151. package/dist/generated/subgraph.js +792 -32
  152. package/dist/generated/subgraph.js.map +1 -1
  153. package/dist/index.browser.d.ts +2 -0
  154. package/dist/index.browser.js +10 -0
  155. package/dist/index.browser.js.map +1 -1
  156. package/dist/index.node.cjs +26 -0
  157. package/dist/index.node.cjs.map +1 -1
  158. package/dist/index.node.d.ts +49 -5
  159. package/dist/index.node.js +25 -1
  160. package/dist/index.node.js.map +1 -1
  161. package/dist/lib/__tests__/redisAtomicStore.test.d.ts +1 -0
  162. package/dist/lib/redisAtomicStore.cjs +201 -0
  163. package/dist/lib/redisAtomicStore.cjs.map +1 -0
  164. package/dist/lib/redisAtomicStore.d.ts +120 -0
  165. package/dist/lib/redisAtomicStore.js +177 -0
  166. package/dist/lib/redisAtomicStore.js.map +1 -0
  167. package/dist/server/relayerHandler.cjs +313 -75
  168. package/dist/server/relayerHandler.cjs.map +1 -1
  169. package/dist/server/relayerHandler.d.ts +35 -2
  170. package/dist/server/relayerHandler.js +313 -75
  171. package/dist/server/relayerHandler.js.map +1 -1
  172. package/dist/storage/index.cjs +3 -0
  173. package/dist/storage/index.cjs.map +1 -1
  174. package/dist/storage/index.d.ts +1 -0
  175. package/dist/storage/index.js +2 -0
  176. package/dist/storage/index.js.map +1 -1
  177. package/dist/storage/providers/dropbox.cjs +237 -0
  178. package/dist/storage/providers/dropbox.cjs.map +1 -0
  179. package/dist/storage/providers/dropbox.d.ts +39 -0
  180. package/dist/storage/providers/dropbox.js +215 -0
  181. package/dist/storage/providers/dropbox.js.map +1 -0
  182. package/dist/storage/providers/dropbox.test.d.ts +1 -0
  183. package/dist/tests/data-upload-owner-validation.test.d.ts +1 -0
  184. package/dist/types/atomicStore.cjs +31 -0
  185. package/dist/types/atomicStore.cjs.map +1 -0
  186. package/dist/types/atomicStore.d.ts +236 -0
  187. package/dist/types/atomicStore.js +7 -0
  188. package/dist/types/atomicStore.js.map +1 -0
  189. package/dist/types/config.cjs.map +1 -1
  190. package/dist/types/config.d.ts +32 -0
  191. package/dist/types/config.js.map +1 -1
  192. package/dist/types/controller-context.cjs.map +1 -1
  193. package/dist/types/controller-context.d.ts +4 -1
  194. package/dist/types/data.cjs.map +1 -1
  195. package/dist/types/data.d.ts +7 -4
  196. package/dist/types/generics.cjs.map +1 -1
  197. package/dist/types/generics.d.ts +1 -1
  198. package/dist/types/index.cjs.map +1 -1
  199. package/dist/types/index.d.ts +6 -3
  200. package/dist/types/index.js.map +1 -1
  201. package/dist/types/operationStore.cjs +17 -0
  202. package/dist/types/operationStore.cjs.map +1 -0
  203. package/dist/types/operationStore.d.ts +171 -0
  204. package/dist/types/operationStore.js +1 -0
  205. package/dist/types/operationStore.js.map +1 -0
  206. package/dist/types/operations.cjs +3 -15
  207. package/dist/types/operations.cjs.map +1 -1
  208. package/dist/types/operations.d.ts +17 -42
  209. package/dist/types/operations.js +2 -13
  210. package/dist/types/operations.js.map +1 -1
  211. package/dist/types/options.cjs +17 -0
  212. package/dist/types/options.cjs.map +1 -0
  213. package/dist/types/options.d.ts +308 -0
  214. package/dist/types/options.js +1 -0
  215. package/dist/types/options.js.map +1 -0
  216. package/dist/types/permissions.cjs.map +1 -1
  217. package/dist/types/permissions.d.ts +4 -0
  218. package/dist/types/personal.cjs.map +1 -1
  219. package/dist/types/personal.d.ts +19 -0
  220. package/dist/types/relayer.cjs.map +1 -1
  221. package/dist/types/relayer.d.ts +53 -9
  222. package/dist/types/utils.cjs.map +1 -1
  223. package/dist/types/utils.d.ts +0 -49
  224. package/dist/utils/__tests__/chainQuery.test.d.ts +1 -0
  225. package/dist/utils/__tests__/subgraphConsistency.test.d.ts +4 -0
  226. package/dist/utils/__tests__/subgraphPagination.test.d.ts +4 -0
  227. package/dist/utils/chainQuery.cjs +107 -0
  228. package/dist/utils/chainQuery.cjs.map +1 -0
  229. package/dist/utils/chainQuery.d.ts +31 -0
  230. package/dist/utils/chainQuery.js +82 -0
  231. package/dist/utils/chainQuery.js.map +1 -0
  232. package/dist/utils/grantFiles.cjs +4 -1
  233. package/dist/utils/grantFiles.cjs.map +1 -1
  234. package/dist/utils/grantFiles.js +4 -1
  235. package/dist/utils/grantFiles.js.map +1 -1
  236. package/dist/utils/ipfs.cjs +2 -4
  237. package/dist/utils/ipfs.cjs.map +1 -1
  238. package/dist/utils/ipfs.d.ts +1 -1
  239. package/dist/utils/ipfs.js +2 -4
  240. package/dist/utils/ipfs.js.map +1 -1
  241. package/dist/utils/subgraphConsistency.cjs +184 -0
  242. package/dist/utils/subgraphConsistency.cjs.map +1 -0
  243. package/dist/utils/subgraphConsistency.d.ts +65 -0
  244. package/dist/utils/subgraphConsistency.js +155 -0
  245. package/dist/utils/subgraphConsistency.js.map +1 -0
  246. package/dist/utils/subgraphMetaCache.cjs +101 -0
  247. package/dist/utils/subgraphMetaCache.cjs.map +1 -0
  248. package/dist/utils/subgraphMetaCache.d.ts +56 -0
  249. package/dist/utils/subgraphMetaCache.js +76 -0
  250. package/dist/utils/subgraphMetaCache.js.map +1 -0
  251. package/dist/utils/subgraphPagination.cjs +104 -0
  252. package/dist/utils/subgraphPagination.cjs.map +1 -0
  253. package/dist/utils/subgraphPagination.d.ts +78 -0
  254. package/dist/utils/subgraphPagination.js +78 -0
  255. package/dist/utils/subgraphPagination.js.map +1 -0
  256. package/package.json +3 -1
@@ -1,5 +1,6 @@
1
1
  import { getAddress } from "viem";
2
2
  import { gasAwareMulticall } from "../utils/multicall";
3
+ import { PollingManager } from "../core/pollingManager";
3
4
  import {
4
5
  RelayerError,
5
6
  UserRejectedRequestError,
@@ -57,10 +58,14 @@ class PermissionsController extends BaseController {
57
58
  * await vana.permissions.revoke({ permissionId: result.permissionId });
58
59
  * ```
59
60
  */
60
- async grant(params) {
61
+ async grant(params, options) {
61
62
  this.assertWallet();
62
63
  const { typedData, signature } = await this.createAndSign(params);
63
- const result = await this.submitSignedGrantWithEvents(typedData, signature);
64
+ const result = await this.submitSignedGrantWithEvents(
65
+ typedData,
66
+ signature,
67
+ options
68
+ );
64
69
  return result;
65
70
  }
66
71
  /**
@@ -88,10 +93,10 @@ class PermissionsController extends BaseController {
88
93
  * console.log(`Permission ID: ${eventData.permissionId}`);
89
94
  * ```
90
95
  */
91
- async submitPermissionGrant(params) {
96
+ async submitPermissionGrant(params, options) {
92
97
  this.assertWallet();
93
98
  const { typedData, signature } = await this.createAndSign(params);
94
- return await this.submitSignedGrant(typedData, signature);
99
+ return await this.submitSignedGrant(typedData, signature, options);
95
100
  }
96
101
  /**
97
102
  * Prepares a permission grant with preview before signing.
@@ -118,7 +123,7 @@ class PermissionsController extends BaseController {
118
123
  * const transactionHash = await confirm();
119
124
  * ```
120
125
  */
121
- async prepareGrant(params) {
126
+ async prepareGrant(params, options) {
122
127
  this.assertWallet();
123
128
  try {
124
129
  const grantFile = createGrantFile(params);
@@ -126,7 +131,11 @@ class PermissionsController extends BaseController {
126
131
  return {
127
132
  preview: grantFile,
128
133
  confirm: async () => {
129
- return await this.confirmGrantInternalWithEvents(params, grantFile);
134
+ return await this.confirmGrantInternalWithEvents(
135
+ params,
136
+ grantFile,
137
+ options
138
+ );
130
139
  }
131
140
  };
132
141
  } catch (error) {
@@ -158,7 +167,7 @@ class PermissionsController extends BaseController {
158
167
  * @throws {NetworkError} When IPFS upload fails
159
168
  * @throws {SignatureError} When user rejects the signature
160
169
  */
161
- async confirmGrantInternal(params, grantFile) {
170
+ async confirmGrantInternal(params, grantFile, options) {
162
171
  try {
163
172
  let { grantUrl } = params;
164
173
  console.debug("\u{1F50D} Debug - Grant URL from params:", grantUrl);
@@ -183,7 +192,7 @@ class PermissionsController extends BaseController {
183
192
  if (response.type === "error") {
184
193
  throw new Error(response.error);
185
194
  }
186
- if (response.type === "direct" && typeof response.result === "object" && "url" in response.result) {
195
+ if (response.type === "direct" && typeof response.result === "object" && response.result !== null && "url" in response.result) {
187
196
  grantUrl = response.result.url;
188
197
  } else {
189
198
  throw new Error("Invalid response from relayer for grant storage");
@@ -219,7 +228,7 @@ class PermissionsController extends BaseController {
219
228
  nonce
220
229
  });
221
230
  const signature = await this.signTypedData(typedData);
222
- return await this.submitSignedGrant(typedData, signature);
231
+ return await this.submitSignedGrant(typedData, signature, options);
223
232
  } catch (error) {
224
233
  if (error instanceof Error) {
225
234
  if (error instanceof RelayerError || error instanceof UserRejectedRequestError || error instanceof SerializationError || error instanceof SignatureError || error instanceof NetworkError || error instanceof NonceError) {
@@ -291,7 +300,7 @@ class PermissionsController extends BaseController {
291
300
  if (response.type === "error") {
292
301
  throw new Error(response.error);
293
302
  }
294
- if (response.type === "direct" && typeof response.result === "object" && "url" in response.result) {
303
+ if (response.type === "direct" && typeof response.result === "object" && response.result !== null && "url" in response.result) {
295
304
  grantUrl = response.result.url;
296
305
  } else {
297
306
  throw new Error("Invalid response from relayer for grant storage");
@@ -364,7 +373,7 @@ class PermissionsController extends BaseController {
364
373
  * );
365
374
  * ```
366
375
  */
367
- async submitSignedGrant(typedData, signature) {
376
+ async submitSignedGrant(typedData, signature, options) {
368
377
  try {
369
378
  console.debug(
370
379
  "\u{1F50D} Debug - submitSignedGrant called with typed data:",
@@ -382,26 +391,41 @@ class PermissionsController extends BaseController {
382
391
  signature,
383
392
  expectedUserAddress: this.context.userAddress
384
393
  });
385
- let hash;
386
- if (response.type === "signed") {
387
- hash = response.hash;
388
- } else if (response.type === "error") {
394
+ if (response.type === "error") {
389
395
  throw new Error(`Relayer error: ${response.error}`);
396
+ }
397
+ let finalHash;
398
+ if (response.type === "submitted") {
399
+ finalHash = response.hash;
400
+ } else if (response.type === "pending") {
401
+ const pollResult = await this.pollRelayerForConfirmation(
402
+ response.operationId,
403
+ options
404
+ );
405
+ finalHash = pollResult.hash;
406
+ } else if (response.type === "confirmed") {
407
+ finalHash = response.hash;
408
+ } else if (response.type === "signed") {
409
+ finalHash = response.hash;
390
410
  } else {
391
411
  throw new Error(
392
- "Invalid response from relayer: expected signed transaction"
412
+ "Invalid response from relayer: unexpected response type"
393
413
  );
394
414
  }
395
415
  const account = this.context.walletClient?.account ?? this.context.userAddress;
396
416
  const { tx } = await import("../utils/transactionHelpers");
397
417
  return tx({
398
- hash,
418
+ hash: finalHash,
399
419
  from: typeof account === "string" ? account : account.address,
400
420
  contract: "DataPortabilityPermissions",
401
421
  fn: "addPermission"
402
422
  });
403
423
  } else {
404
- return await this.submitDirectTransaction(typedData, signature);
424
+ return await this.submitDirectTransaction(
425
+ typedData,
426
+ signature,
427
+ options
428
+ );
405
429
  }
406
430
  } catch (error) {
407
431
  if (error instanceof RelayerError || error instanceof NetworkError || error instanceof UserRejectedRequestError || error instanceof SignatureError || error instanceof NonceError) {
@@ -434,7 +458,7 @@ class PermissionsController extends BaseController {
434
458
  * const result = await txHandle.waitForEvents();
435
459
  * ```
436
460
  */
437
- async submitSignedTrustServer(typedData, signature) {
461
+ async submitSignedTrustServer(typedData, signature, options) {
438
462
  try {
439
463
  const trustServerInput = {
440
464
  nonce: BigInt(typedData.message.nonce),
@@ -442,7 +466,8 @@ class PermissionsController extends BaseController {
442
466
  };
443
467
  const hash = await this.submitTrustServerTransaction(
444
468
  trustServerInput,
445
- signature
469
+ signature,
470
+ options
446
471
  );
447
472
  const account = this.context.userAddress;
448
473
  const { tx } = await import("../utils/transactionHelpers");
@@ -497,7 +522,7 @@ class PermissionsController extends BaseController {
497
522
  * const result = await txHandle.waitForEvents();
498
523
  * ```
499
524
  */
500
- async submitSignedAddAndTrustServer(typedData, signature) {
525
+ async submitSignedAddAndTrustServer(typedData, signature, options) {
501
526
  try {
502
527
  const addAndTrustServerInput = {
503
528
  nonce: BigInt(typedData.message.nonce),
@@ -507,7 +532,8 @@ class PermissionsController extends BaseController {
507
532
  };
508
533
  const hash = await this.submitAddAndTrustServerTransaction(
509
534
  addAndTrustServerInput,
510
- signature
535
+ signature,
536
+ options
511
537
  );
512
538
  const account = this.context.walletClient?.account ?? this.context.userAddress;
513
539
  const { tx } = await import("../utils/transactionHelpers");
@@ -535,8 +561,12 @@ class PermissionsController extends BaseController {
535
561
  * @param signature - The user's signature authorizing the transaction
536
562
  * @returns Promise resolving to PermissionGrantResult with parsed events
537
563
  */
538
- async submitSignedGrantWithEvents(typedData, signature) {
539
- const txResult = await this.submitSignedGrant(typedData, signature);
564
+ async submitSignedGrantWithEvents(typedData, signature, options) {
565
+ const txResult = await this.submitSignedGrant(
566
+ typedData,
567
+ signature,
568
+ options
569
+ );
540
570
  if (!this.context.waitForTransactionEvents) {
541
571
  throw new BlockchainError("waitForTransactionEvents not configured");
542
572
  }
@@ -568,8 +598,12 @@ class PermissionsController extends BaseController {
568
598
  * @param grantFile - The pre-created grant file object
569
599
  * @returns Promise resolving to PermissionGrantResult with parsed events
570
600
  */
571
- async confirmGrantInternalWithEvents(params, grantFile) {
572
- const txResult = await this.confirmGrantInternal(params, grantFile);
601
+ async confirmGrantInternalWithEvents(params, grantFile, options) {
602
+ const txResult = await this.confirmGrantInternal(
603
+ params,
604
+ grantFile,
605
+ options
606
+ );
573
607
  if (!this.context.waitForTransactionEvents) {
574
608
  throw new BlockchainError("waitForTransactionEvents not configured");
575
609
  }
@@ -593,6 +627,27 @@ class PermissionsController extends BaseController {
593
627
  fileIds: event.fileIds
594
628
  };
595
629
  }
630
+ /**
631
+ * Polls the relayer for confirmation of a pending operation.
632
+ *
633
+ * @param operationId - The operation ID to poll
634
+ * @param options - Polling configuration including status updates and cancellation
635
+ * @returns Promise resolving to the confirmed hash and receipt
636
+ * @throws {TransactionPendingError} When the operation times out
637
+ * @throws {Error} When the operation fails or is cancelled
638
+ * @internal
639
+ */
640
+ async pollRelayerForConfirmation(operationId, options) {
641
+ if (!this.context.relayer) {
642
+ throw new Error("Relayer not configured for polling");
643
+ }
644
+ const pollingManager = new PollingManager(this.context.relayer);
645
+ return await pollingManager.startPolling(operationId, {
646
+ signal: options?.signal,
647
+ onStatusUpdate: options?.onStatusUpdate,
648
+ ...options?.pollingOptions
649
+ });
650
+ }
596
651
  /**
597
652
  * Submits an already-signed permission revoke transaction to the blockchain.
598
653
  *
@@ -614,7 +669,7 @@ class PermissionsController extends BaseController {
614
669
  * const result = await txHandle.waitForEvents();
615
670
  * ```
616
671
  */
617
- async submitSignedRevoke(typedData, signature) {
672
+ async submitSignedRevoke(typedData, signature, options) {
618
673
  try {
619
674
  let hash;
620
675
  if (this.context.relayer) {
@@ -625,19 +680,31 @@ class PermissionsController extends BaseController {
625
680
  signature,
626
681
  expectedUserAddress: this.context.userAddress
627
682
  });
628
- if (response.type === "signed") {
629
- hash = response.hash;
630
- } else if (response.type === "error") {
683
+ if (response.type === "error") {
631
684
  throw new Error(`Relayer error: ${response.error}`);
685
+ }
686
+ if (response.type === "submitted") {
687
+ hash = response.hash;
688
+ } else if (response.type === "pending") {
689
+ const pollResult = await this.pollRelayerForConfirmation(
690
+ response.operationId,
691
+ options
692
+ );
693
+ hash = pollResult.hash;
694
+ } else if (response.type === "confirmed") {
695
+ hash = response.hash;
696
+ } else if (response.type === "signed") {
697
+ hash = response.hash;
632
698
  } else {
633
699
  throw new Error(
634
- "Invalid response from relayer: expected signed transaction"
700
+ "Invalid response from relayer: unexpected response type"
635
701
  );
636
702
  }
637
703
  } else {
638
704
  hash = await this.submitDirectRevokeTransaction(
639
705
  typedData,
640
- signature
706
+ signature,
707
+ options
641
708
  );
642
709
  }
643
710
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -679,7 +746,7 @@ class PermissionsController extends BaseController {
679
746
  * const result = await txHandle.waitForEvents();
680
747
  * ```
681
748
  */
682
- async submitSignedUntrustServer(typedData, signature) {
749
+ async submitSignedUntrustServer(typedData, signature, options) {
683
750
  try {
684
751
  let hash;
685
752
  if (this.context.relayer) {
@@ -690,7 +757,9 @@ class PermissionsController extends BaseController {
690
757
  signature,
691
758
  expectedUserAddress: this.context.userAddress
692
759
  });
693
- if (response.type === "signed") {
760
+ if (response.type === "submitted") {
761
+ hash = response.hash;
762
+ } else if (response.type === "signed") {
694
763
  hash = response.hash;
695
764
  } else if (response.type === "error") {
696
765
  throw new Error(`Relayer error: ${response.error}`);
@@ -702,7 +771,8 @@ class PermissionsController extends BaseController {
702
771
  } else {
703
772
  hash = await this.submitSignedUntrustTransaction(
704
773
  typedData,
705
- signature
774
+ signature,
775
+ options
706
776
  );
707
777
  }
708
778
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -735,7 +805,7 @@ class PermissionsController extends BaseController {
735
805
  * @returns Promise resolving to the transaction hash
736
806
  * @throws {BlockchainError} When contract submission fails
737
807
  */
738
- async submitDirectTransaction(typedData, signature) {
808
+ async submitDirectTransaction(typedData, signature, options) {
739
809
  this.assertWallet();
740
810
  const chainId = await this.context.publicClient.getChainId();
741
811
  const DataPortabilityPermissionsAddress = getContractAddress(
@@ -767,7 +837,8 @@ class PermissionsController extends BaseController {
767
837
  functionName: "addPermission",
768
838
  args: [permissionInput, formattedSignature],
769
839
  account,
770
- chain: this.context.walletClient?.chain ?? null
840
+ chain: this.context.walletClient?.chain ?? null,
841
+ ...this.spreadTransactionOptions(options)
771
842
  });
772
843
  const { tx } = await import("../utils/transactionHelpers");
773
844
  return tx({
@@ -866,7 +937,7 @@ class PermissionsController extends BaseController {
866
937
  args: [params.permissionId],
867
938
  account,
868
939
  chain: this.context.walletClient?.chain ?? null,
869
- ...options?.gasLimit && { gas: options.gasLimit },
940
+ ...options?.gas && { gas: options.gas },
870
941
  ...options?.nonce && { nonce: options.nonce },
871
942
  // Use EIP-1559 if available, otherwise fall back to legacy gasPrice
872
943
  ...options?.maxFeePerGas || options?.maxPriorityFeePerGas ? {
@@ -923,7 +994,7 @@ class PermissionsController extends BaseController {
923
994
  * console.log(`Permission ${result.permissionId} revoked`);
924
995
  * ```
925
996
  */
926
- async submitRevokeWithSignature(params) {
997
+ async submitRevokeWithSignature(params, options) {
927
998
  this.assertWallet();
928
999
  try {
929
1000
  if (!this.context.walletClient?.chain?.id) {
@@ -955,7 +1026,9 @@ class PermissionsController extends BaseController {
955
1026
  signature,
956
1027
  expectedUserAddress: this.context.userAddress
957
1028
  });
958
- if (response.type === "signed") {
1029
+ if (response.type === "submitted") {
1030
+ hash = response.hash;
1031
+ } else if (response.type === "signed") {
959
1032
  hash = response.hash;
960
1033
  } else if (response.type === "error") {
961
1034
  throw new Error(`Relayer error: ${response.error}`);
@@ -967,7 +1040,8 @@ class PermissionsController extends BaseController {
967
1040
  } else {
968
1041
  hash = await this.submitDirectRevokeTransaction(
969
1042
  typedData,
970
- signature
1043
+ signature,
1044
+ options
971
1045
  );
972
1046
  }
973
1047
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -1293,7 +1367,9 @@ class PermissionsController extends BaseController {
1293
1367
  * ```
1294
1368
  */
1295
1369
  async getUserPermissionGrantsOnChain(options = {}) {
1296
- const { limit = 50, subgraphUrl } = options;
1370
+ const { limit = 50, fetchAll = false, subgraphUrl } = options;
1371
+ const pageSize = fetchAll ? 100 : limit;
1372
+ const maxResults = fetchAll ? 1e4 : limit;
1297
1373
  try {
1298
1374
  const userAddress = this.context.userAddress;
1299
1375
  const graphqlEndpoint = subgraphUrl ?? this.context.subgraphUrl;
@@ -1303,10 +1379,10 @@ class PermissionsController extends BaseController {
1303
1379
  );
1304
1380
  }
1305
1381
  const query = `
1306
- query GetUserPermissions($userId: ID!) {
1382
+ query GetUserPermissions($userId: ID!, $first: Int!, $skip: Int!) {
1307
1383
  user(id: $userId) {
1308
1384
  id
1309
- permissions {
1385
+ permissions(first: $first, skip: $skip, orderBy: addedAtBlock, orderDirection: desc) {
1310
1386
  id
1311
1387
  grant
1312
1388
  nonce
@@ -1324,34 +1400,82 @@ class PermissionsController extends BaseController {
1324
1400
  }
1325
1401
  }
1326
1402
  `;
1327
- const response = await fetch(graphqlEndpoint, {
1328
- method: "POST",
1329
- headers: {
1330
- "Content-Type": "application/json"
1331
- },
1332
- body: JSON.stringify({
1333
- query,
1334
- variables: {
1335
- userId: userAddress.toLowerCase()
1403
+ const allPermissions = [];
1404
+ let currentOffset = 0;
1405
+ if (!fetchAll) {
1406
+ const response = await fetch(graphqlEndpoint, {
1407
+ method: "POST",
1408
+ headers: {
1409
+ "Content-Type": "application/json"
1410
+ },
1411
+ body: JSON.stringify({
1412
+ query,
1413
+ variables: {
1414
+ userId: userAddress.toLowerCase(),
1415
+ first: limit,
1416
+ skip: 0
1417
+ }
1418
+ })
1419
+ });
1420
+ if (!response.ok) {
1421
+ throw new BlockchainError(
1422
+ `Subgraph request failed: ${response.status} ${response.statusText}`
1423
+ );
1424
+ }
1425
+ const result = await response.json();
1426
+ if (result.errors) {
1427
+ throw new BlockchainError(
1428
+ `Subgraph errors: ${result.errors.map((e) => e.message).join(", ")}`
1429
+ );
1430
+ }
1431
+ const userData = result.data?.user;
1432
+ if (!userData?.permissions?.length) {
1433
+ return [];
1434
+ }
1435
+ allPermissions.push(...userData.permissions);
1436
+ } else {
1437
+ while (allPermissions.length < maxResults) {
1438
+ const currentLimit = Math.min(
1439
+ pageSize,
1440
+ maxResults - allPermissions.length
1441
+ );
1442
+ const response = await fetch(graphqlEndpoint, {
1443
+ method: "POST",
1444
+ headers: {
1445
+ "Content-Type": "application/json"
1446
+ },
1447
+ body: JSON.stringify({
1448
+ query,
1449
+ variables: {
1450
+ userId: userAddress.toLowerCase(),
1451
+ first: currentLimit,
1452
+ skip: currentOffset
1453
+ }
1454
+ })
1455
+ });
1456
+ if (!response.ok) {
1457
+ throw new BlockchainError(
1458
+ `Subgraph request failed: ${response.status} ${response.statusText}`
1459
+ );
1336
1460
  }
1337
- })
1338
- });
1339
- if (!response.ok) {
1340
- throw new BlockchainError(
1341
- `Subgraph request failed: ${response.status} ${response.statusText}`
1342
- );
1343
- }
1344
- const result = await response.json();
1345
- if (result.errors) {
1346
- throw new BlockchainError(
1347
- `Subgraph errors: ${result.errors.map((e) => e.message).join(", ")}`
1348
- );
1349
- }
1350
- const userData = result.data?.user;
1351
- if (!userData?.permissions?.length) {
1352
- return [];
1461
+ const result = await response.json();
1462
+ if (result.errors) {
1463
+ throw new BlockchainError(
1464
+ `Subgraph errors: ${result.errors.map((e) => e.message).join(", ")}`
1465
+ );
1466
+ }
1467
+ const userData = result.data?.user;
1468
+ if (!userData?.permissions?.length) {
1469
+ break;
1470
+ }
1471
+ allPermissions.push(...userData.permissions);
1472
+ if (userData.permissions.length < currentLimit) {
1473
+ break;
1474
+ }
1475
+ currentOffset += userData.permissions.length;
1476
+ }
1353
1477
  }
1354
- const onChainGrants = userData.permissions.slice(0, limit).map(
1478
+ const onChainGrants = allPermissions.map(
1355
1479
  (permission) => ({
1356
1480
  id: BigInt(permission.id),
1357
1481
  grantUrl: permission.grant,
@@ -1532,7 +1656,7 @@ class PermissionsController extends BaseController {
1532
1656
  * @param params - Parameters for adding and trusting the server
1533
1657
  * @returns Promise resolving to TransactionResult with ServerTrustResult event data
1534
1658
  */
1535
- async submitAddAndTrustServerWithSignature(params) {
1659
+ async submitAddAndTrustServerWithSignature(params, options) {
1536
1660
  this.assertWallet();
1537
1661
  try {
1538
1662
  const nonce = await this.getServersUserNonce();
@@ -1568,7 +1692,9 @@ class PermissionsController extends BaseController {
1568
1692
  if (response.type === "error") {
1569
1693
  throw new RelayerError(response.error);
1570
1694
  }
1571
- if (response.type === "signed") {
1695
+ if (response.type === "submitted") {
1696
+ hash = response.hash;
1697
+ } else if (response.type === "signed") {
1572
1698
  hash = response.hash;
1573
1699
  } else {
1574
1700
  throw new Error("Unexpected response type from relayer");
@@ -1576,7 +1702,8 @@ class PermissionsController extends BaseController {
1576
1702
  } else {
1577
1703
  hash = await this.submitAddAndTrustServerTransaction(
1578
1704
  addAndTrustServerInput,
1579
- signature
1705
+ signature,
1706
+ options
1580
1707
  );
1581
1708
  }
1582
1709
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -1615,7 +1742,7 @@ class PermissionsController extends BaseController {
1615
1742
  * @throws {ServerUrlMismatchError} When server URL doesn't match existing registration
1616
1743
  * @throws {BlockchainError} When trust operation fails for any other reason
1617
1744
  */
1618
- async submitTrustServerWithSignature(params) {
1745
+ async submitTrustServerWithSignature(params, options) {
1619
1746
  this.assertWallet();
1620
1747
  try {
1621
1748
  const nonce = await this.getServersUserNonce();
@@ -1637,7 +1764,9 @@ class PermissionsController extends BaseController {
1637
1764
  if (response.type === "error") {
1638
1765
  throw new RelayerError(response.error);
1639
1766
  }
1640
- if (response.type === "signed") {
1767
+ if (response.type === "submitted") {
1768
+ hash = response.hash;
1769
+ } else if (response.type === "signed") {
1641
1770
  hash = response.hash;
1642
1771
  } else {
1643
1772
  throw new Error("Unexpected response type from relayer");
@@ -1645,7 +1774,8 @@ class PermissionsController extends BaseController {
1645
1774
  } else {
1646
1775
  hash = await this.submitTrustServerTransaction(
1647
1776
  trustServerInput,
1648
- signature
1777
+ signature,
1778
+ options
1649
1779
  );
1650
1780
  }
1651
1781
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -1703,7 +1833,7 @@ class PermissionsController extends BaseController {
1703
1833
  args: [BigInt(params.serverId)],
1704
1834
  account,
1705
1835
  chain: this.context.walletClient?.chain ?? null,
1706
- ...options?.gasLimit && { gas: options.gasLimit },
1836
+ ...options?.gas && { gas: options.gas },
1707
1837
  ...options?.nonce && { nonce: options.nonce },
1708
1838
  // Use EIP-1559 if available, otherwise fall back to legacy gasPrice
1709
1839
  ...options?.maxFeePerGas || options?.maxPriorityFeePerGas ? {
@@ -1807,7 +1937,9 @@ class PermissionsController extends BaseController {
1807
1937
  if (response.type === "error") {
1808
1938
  throw new RelayerError(response.error);
1809
1939
  }
1810
- if (response.type === "signed") {
1940
+ if (response.type === "submitted") {
1941
+ hash = response.hash;
1942
+ } else if (response.type === "signed") {
1811
1943
  hash = response.hash;
1812
1944
  } else {
1813
1945
  throw new Error("Unexpected response type from relayer");
@@ -2253,7 +2385,7 @@ class PermissionsController extends BaseController {
2253
2385
  * @param signature - The cryptographic signature for the transaction
2254
2386
  * @returns Promise resolving to the transaction hash
2255
2387
  */
2256
- async submitAddAndTrustServerTransaction(addAndTrustServerInput, signature) {
2388
+ async submitAddAndTrustServerTransaction(addAndTrustServerInput, signature, options) {
2257
2389
  this.assertWallet();
2258
2390
  const chainId = await this.context.walletClient.getChainId();
2259
2391
  const DataPortabilityServersAddress = getContractAddress(
@@ -2287,7 +2419,16 @@ class PermissionsController extends BaseController {
2287
2419
  formattedSignature
2288
2420
  ],
2289
2421
  account: this.context.walletClient?.account ?? this.context.userAddress,
2290
- chain: this.context.walletClient?.chain ?? null
2422
+ chain: this.context.walletClient?.chain ?? null,
2423
+ ...options && {
2424
+ gas: options.gas,
2425
+ nonce: options.nonce,
2426
+ // Use EIP-1559 gas pricing if available, otherwise legacy
2427
+ ...options.maxFeePerGas || options.maxPriorityFeePerGas ? {
2428
+ maxFeePerGas: options.maxFeePerGas,
2429
+ maxPriorityFeePerGas: options.maxPriorityFeePerGas
2430
+ } : options.gasPrice ? { gasPrice: options.gasPrice } : {}
2431
+ }
2291
2432
  });
2292
2433
  return txHash;
2293
2434
  }
@@ -2298,7 +2439,7 @@ class PermissionsController extends BaseController {
2298
2439
  * @param signature - The cryptographic signature for the transaction
2299
2440
  * @returns Promise resolving to the transaction hash
2300
2441
  */
2301
- async submitTrustServerTransaction(trustServerInput, signature) {
2442
+ async submitTrustServerTransaction(trustServerInput, signature, options) {
2302
2443
  this.assertWallet();
2303
2444
  const chainId = await this.context.walletClient.getChainId();
2304
2445
  const DataPortabilityServersAddress = getContractAddress(
@@ -2319,7 +2460,8 @@ class PermissionsController extends BaseController {
2319
2460
  formattedSignature
2320
2461
  ],
2321
2462
  account: this.context.walletClient?.account ?? this.context.userAddress,
2322
- chain: this.context.walletClient?.chain ?? null
2463
+ chain: this.context.walletClient?.chain ?? null,
2464
+ ...this.spreadTransactionOptions(options)
2323
2465
  });
2324
2466
  return txHash;
2325
2467
  }
@@ -2330,7 +2472,7 @@ class PermissionsController extends BaseController {
2330
2472
  * @param signature - The cryptographic signature authorizing the revoke
2331
2473
  * @returns Promise resolving to the transaction hash
2332
2474
  */
2333
- async submitDirectRevokeTransaction(typedData, signature) {
2475
+ async submitDirectRevokeTransaction(typedData, signature, options) {
2334
2476
  this.assertWallet();
2335
2477
  const chainId = await this.context.walletClient.getChainId();
2336
2478
  const DataPortabilityPermissionsAddress = getContractAddress(
@@ -2345,7 +2487,16 @@ class PermissionsController extends BaseController {
2345
2487
  functionName: "revokePermissionWithSignature",
2346
2488
  args: [typedData.message, formattedSignature],
2347
2489
  account: this.context.walletClient?.account ?? this.context.userAddress,
2348
- chain: this.context.walletClient?.chain ?? null
2490
+ chain: this.context.walletClient?.chain ?? null,
2491
+ ...options && {
2492
+ gas: options.gas,
2493
+ nonce: options.nonce,
2494
+ // Use EIP-1559 gas pricing if available, otherwise legacy
2495
+ ...options.maxFeePerGas || options.maxPriorityFeePerGas ? {
2496
+ maxFeePerGas: options.maxFeePerGas,
2497
+ maxPriorityFeePerGas: options.maxPriorityFeePerGas
2498
+ } : options.gasPrice ? { gasPrice: options.gasPrice } : {}
2499
+ }
2349
2500
  });
2350
2501
  return txHash;
2351
2502
  }
@@ -2356,7 +2507,7 @@ class PermissionsController extends BaseController {
2356
2507
  * @param signature - The cryptographic signature authorizing the untrust
2357
2508
  * @returns Promise resolving to the transaction hash
2358
2509
  */
2359
- async submitSignedUntrustTransaction(typedData, signature) {
2510
+ async submitSignedUntrustTransaction(typedData, signature, options) {
2360
2511
  this.assertWallet();
2361
2512
  const chainId = await this.context.walletClient.getChainId();
2362
2513
  const DataPortabilityServersAddress = getContractAddress(
@@ -2375,7 +2526,16 @@ class PermissionsController extends BaseController {
2375
2526
  functionName: "untrustServerWithSignature",
2376
2527
  args: [contractMessage, formattedSignature],
2377
2528
  account: this.context.walletClient?.account ?? this.context.userAddress,
2378
- chain: this.context.walletClient?.chain ?? null
2529
+ chain: this.context.walletClient?.chain ?? null,
2530
+ ...options && {
2531
+ gas: options.gas,
2532
+ nonce: options.nonce,
2533
+ // Use EIP-1559 gas pricing if available, otherwise legacy
2534
+ ...options.maxFeePerGas || options.maxPriorityFeePerGas ? {
2535
+ maxFeePerGas: options.maxFeePerGas,
2536
+ maxPriorityFeePerGas: options.maxPriorityFeePerGas
2537
+ } : options.gasPrice ? { gasPrice: options.gasPrice } : {}
2538
+ }
2379
2539
  });
2380
2540
  return txHash;
2381
2541
  }
@@ -2388,6 +2548,9 @@ class PermissionsController extends BaseController {
2388
2548
  * A grantee is an entity (like an application) that can receive data permissions
2389
2549
  * from users. Once registered, users can grant the grantee access to their data.
2390
2550
  *
2551
+ * This method supports gasless transactions via relayer when configured.
2552
+ * If no relayer is available, it falls back to direct wallet transactions.
2553
+ *
2391
2554
  * @param params - Parameters for registering the grantee
2392
2555
  * @param params.owner - The Ethereum address that will own this grantee registration
2393
2556
  * @param params.granteeAddress - The Ethereum address of the grantee (application)
@@ -2396,7 +2559,7 @@ class PermissionsController extends BaseController {
2396
2559
  * @returns Promise resolving to the transaction hash
2397
2560
  * @throws {BlockchainError} When the grantee registration transaction fails
2398
2561
  * @throws {UserRejectedRequestError} When user rejects the transaction
2399
- * @throws {ContractError} When grantee is already registered
2562
+ * @throws {RelayerError} When gasless transaction submission fails
2400
2563
  *
2401
2564
  * @example
2402
2565
  * ```typescript
@@ -2409,44 +2572,87 @@ class PermissionsController extends BaseController {
2409
2572
  * ```
2410
2573
  */
2411
2574
  async submitRegisterGrantee(params, options) {
2412
- this.assertWallet();
2413
- const chainId = await this.context.walletClient.getChainId();
2414
- const DataPortabilityGranteesAddress = getContractAddress(
2415
- chainId,
2416
- "DataPortabilityGrantees"
2417
- );
2418
- const DataPortabilityGranteesAbi = getAbi("DataPortabilityGrantees");
2419
- const ownerAddress = getAddress(params.owner);
2420
- const granteeAddress = getAddress(params.granteeAddress);
2421
- const account = this.context.walletClient?.account ?? this.context.userAddress;
2422
- const txHash = await this.context.walletClient.writeContract({
2423
- address: DataPortabilityGranteesAddress,
2424
- abi: DataPortabilityGranteesAbi,
2425
- functionName: "registerGrantee",
2426
- args: [ownerAddress, granteeAddress, params.publicKey],
2427
- account,
2428
- chain: this.context.walletClient?.chain ?? null,
2429
- ...options?.gasLimit && { gas: options.gasLimit },
2430
- ...options?.nonce && { nonce: options.nonce },
2431
- // Use EIP-1559 if available, otherwise fall back to legacy gasPrice
2432
- ...options?.maxFeePerGas || options?.maxPriorityFeePerGas ? {
2433
- ...options.maxFeePerGas && { maxFeePerGas: options.maxFeePerGas },
2434
- ...options.maxPriorityFeePerGas && {
2435
- maxPriorityFeePerGas: options.maxPriorityFeePerGas
2575
+ try {
2576
+ let hash;
2577
+ if (this.context.relayer) {
2578
+ const request = {
2579
+ type: "direct",
2580
+ operation: "submitRegisterGrantee",
2581
+ params: {
2582
+ owner: params.owner,
2583
+ granteeAddress: params.granteeAddress,
2584
+ publicKey: params.publicKey
2585
+ }
2586
+ };
2587
+ const response = await this.context.relayer(request);
2588
+ if (response.type === "error") {
2589
+ throw new RelayerError(response.error);
2436
2590
  }
2437
- } : options?.gasPrice && { gasPrice: options.gasPrice }
2438
- });
2439
- const { tx } = await import("../utils/transactionHelpers");
2440
- return tx({
2441
- hash: txHash,
2442
- from: typeof account === "string" ? account : account.address,
2443
- contract: "DataPortabilityGrantees",
2444
- fn: "registerGrantee"
2445
- });
2591
+ if (response.type === "submitted") {
2592
+ hash = response.hash;
2593
+ } else if (response.type === "direct") {
2594
+ const result = response.result;
2595
+ hash = result.transactionHash;
2596
+ } else {
2597
+ throw new Error("Unexpected response type from relayer");
2598
+ }
2599
+ } else {
2600
+ this.assertWallet();
2601
+ const chainId = await this.context.walletClient.getChainId();
2602
+ const DataPortabilityGranteesAddress = getContractAddress(
2603
+ chainId,
2604
+ "DataPortabilityGrantees"
2605
+ );
2606
+ const DataPortabilityGranteesAbi = getAbi("DataPortabilityGrantees");
2607
+ const ownerAddress = getAddress(params.owner);
2608
+ const granteeAddress = getAddress(params.granteeAddress);
2609
+ const account2 = this.context.walletClient?.account ?? this.context.userAddress;
2610
+ hash = await this.context.walletClient.writeContract({
2611
+ address: DataPortabilityGranteesAddress,
2612
+ abi: DataPortabilityGranteesAbi,
2613
+ functionName: "registerGrantee",
2614
+ args: [ownerAddress, granteeAddress, params.publicKey],
2615
+ account: account2,
2616
+ chain: this.context.walletClient?.chain ?? null,
2617
+ ...this.spreadTransactionOptions(options)
2618
+ });
2619
+ }
2620
+ const account = this.context.walletClient?.account ?? this.context.userAddress;
2621
+ const { tx } = await import("../utils/transactionHelpers");
2622
+ return tx({
2623
+ hash,
2624
+ from: typeof account === "string" ? account : account.address,
2625
+ contract: "DataPortabilityGrantees",
2626
+ fn: "registerGrantee"
2627
+ });
2628
+ } catch (error) {
2629
+ if (error instanceof Error) {
2630
+ if (error instanceof RelayerError || error instanceof UserRejectedRequestError || error instanceof SerializationError || error instanceof SignatureError || error instanceof BlockchainError) {
2631
+ throw error;
2632
+ }
2633
+ if (error.name === "ContractFunctionExecutionError") {
2634
+ throw new BlockchainError(
2635
+ `Grantee registration failed: ${error.message}`,
2636
+ error
2637
+ );
2638
+ }
2639
+ if (error.name === "UserRejectedRequestError") {
2640
+ throw new UserRejectedRequestError(
2641
+ "User rejected the grantee registration transaction"
2642
+ );
2643
+ }
2644
+ throw new BlockchainError(
2645
+ `Failed to register grantee: ${error.message}`,
2646
+ error
2647
+ );
2648
+ }
2649
+ throw new BlockchainError(`Failed to register grantee: ${String(error)}`);
2650
+ }
2446
2651
  }
2447
2652
  // TODO: When DataPortabilityGrantees contract adds registerGranteeWithSignature function,
2448
2653
  // implement submitRegisterGranteeWithSignature and submitSignedRegisterGrantee methods
2449
- // to support gasless transactions via relayer
2654
+ // to support EIP-712 signed gasless transactions via relayer.
2655
+ // Current implementation above supports direct gasless transactions (relayer pays gas directly).
2450
2656
  /**
2451
2657
  * Retrieves all registered grantees from the DataPortabilityGrantees contract.
2452
2658
  *
@@ -2494,27 +2700,52 @@ class PermissionsController extends BaseController {
2494
2700
  const total = Number(totalCount);
2495
2701
  const limit = options.limit ?? 50;
2496
2702
  const offset = options.offset ?? 0;
2497
- const grantees = [];
2498
- const endIndex = Math.min(offset + limit, total);
2499
- for (let i = offset; i < endIndex; i++) {
2500
- try {
2501
- const granteeInfo = await this.context.publicClient.readContract({
2502
- address: DataPortabilityGranteesAddress,
2503
- abi: DataPortabilityGranteesAbi,
2504
- functionName: "grantees",
2505
- args: [BigInt(i + 1)]
2506
- // Grantee IDs are 1-indexed
2507
- });
2508
- grantees.push({
2509
- id: i + 1,
2510
- owner: granteeInfo.owner,
2511
- address: granteeInfo.granteeAddress,
2512
- publicKey: granteeInfo.publicKey,
2513
- permissionIds: granteeInfo.permissionIds.map((id) => Number(id))
2514
- });
2515
- } catch (error) {
2516
- console.warn(`Failed to fetch grantee ${i + 1}:`, error);
2517
- }
2703
+ const includePermissions = options.includePermissions ?? true;
2704
+ const startId = total - offset;
2705
+ const endId = Math.max(startId - limit + 1, 1);
2706
+ const granteeIds = Array.from(
2707
+ { length: startId - endId + 1 },
2708
+ (_, i) => startId - i
2709
+ // Generate IDs in descending order
2710
+ );
2711
+ let grantees;
2712
+ if (includePermissions) {
2713
+ const granteePromises = granteeIds.map(
2714
+ (granteeId) => this.getGranteeById(granteeId)
2715
+ );
2716
+ const granteeResults = await Promise.all(granteePromises);
2717
+ grantees = granteeResults.filter(
2718
+ (grantee) => grantee !== null
2719
+ );
2720
+ } else {
2721
+ const granteeInfoPromises = granteeIds.map(
2722
+ async (granteeId) => {
2723
+ try {
2724
+ const granteeInfo = await this.context.publicClient.readContract({
2725
+ address: DataPortabilityGranteesAddress,
2726
+ abi: DataPortabilityGranteesAbi,
2727
+ functionName: "granteesV2",
2728
+ args: [BigInt(granteeId)]
2729
+ });
2730
+ const grantee = {
2731
+ id: granteeId,
2732
+ owner: granteeInfo.owner,
2733
+ address: granteeInfo.granteeAddress,
2734
+ publicKey: granteeInfo.publicKey,
2735
+ permissionIds: []
2736
+ // TypeScript infers number[] from Grantee type
2737
+ };
2738
+ return grantee;
2739
+ } catch (error) {
2740
+ console.warn(`Failed to fetch grantee ${granteeId}:`, error);
2741
+ return null;
2742
+ }
2743
+ }
2744
+ );
2745
+ const granteeInfoResults = await Promise.all(granteeInfoPromises);
2746
+ grantees = granteeInfoResults.filter(
2747
+ (grantee) => grantee !== null
2748
+ );
2518
2749
  }
2519
2750
  return {
2520
2751
  grantees,
@@ -2525,15 +2756,16 @@ class PermissionsController extends BaseController {
2525
2756
  };
2526
2757
  }
2527
2758
  /**
2528
- * Retrieves a specific grantee by their Ethereum address from the DataPortabilityGrantees contract.
2759
+ * Retrieves a specific grantee by their Ethereum wallet address.
2529
2760
  *
2761
+ * @remarks
2530
2762
  * Looks up a registered grantee (application) using their Ethereum address
2531
- * and returns their complete registration information including permissions.
2763
+ * and returns their complete registration information including all associated permissions.
2532
2764
  *
2533
- * @param granteeAddress - The Ethereum address of the grantee to look up
2534
- * @returns Promise resolving to the grantee information, or null if not found
2535
- * @throws {BlockchainError} When contract read operation fails
2536
- * @throws {NetworkError} When unable to connect to the blockchain network
2765
+ * Returns `null` if the address is not registered as a grantee or if an error occurs.
2766
+ *
2767
+ * @param granteeAddress - Ethereum wallet address of the grantee to query
2768
+ * @returns Grantee information including ID, addresses, public key, and permission IDs, or `null` if not found
2537
2769
  *
2538
2770
  * @example
2539
2771
  * ```typescript
@@ -2558,40 +2790,32 @@ class PermissionsController extends BaseController {
2558
2790
  );
2559
2791
  const DataPortabilityGranteesAbi = getAbi("DataPortabilityGrantees");
2560
2792
  try {
2561
- const granteeInfo = await this.context.publicClient.readContract({
2562
- address: DataPortabilityGranteesAddress,
2563
- abi: DataPortabilityGranteesAbi,
2564
- functionName: "granteeByAddress",
2565
- args: [granteeAddress]
2566
- });
2567
2793
  const granteeId = await this.context.publicClient.readContract({
2568
2794
  address: DataPortabilityGranteesAddress,
2569
2795
  abi: DataPortabilityGranteesAbi,
2570
2796
  functionName: "granteeAddressToId",
2571
2797
  args: [granteeAddress]
2572
2798
  });
2573
- return {
2574
- id: Number(granteeId),
2575
- owner: granteeInfo.owner,
2576
- address: granteeInfo.granteeAddress,
2577
- publicKey: granteeInfo.publicKey,
2578
- permissionIds: granteeInfo.permissionIds.map((id) => Number(id))
2579
- };
2799
+ if (granteeId === 0n) {
2800
+ return null;
2801
+ }
2802
+ return await this.getGranteeById(Number(granteeId));
2580
2803
  } catch (error) {
2581
2804
  console.warn(`Failed to fetch grantee ${granteeAddress}:`, error);
2582
2805
  return null;
2583
2806
  }
2584
2807
  }
2585
2808
  /**
2586
- * Retrieves a specific grantee by their unique ID from the DataPortabilityGrantees contract.
2809
+ * Retrieves a specific grantee by their unique ID.
2587
2810
  *
2811
+ * @remarks
2588
2812
  * Looks up a registered grantee (application) using their numeric ID assigned during
2589
- * registration and returns their complete information including permissions.
2813
+ * registration and returns their complete information including all associated permissions.
2590
2814
  *
2591
- * @param granteeId - The unique numeric ID of the grantee (1-indexed)
2592
- * @returns Promise resolving to the grantee information, or null if not found
2593
- * @throws {BlockchainError} When contract read operation fails
2594
- * @throws {NetworkError} When unable to connect to the blockchain network
2815
+ * Returns `null` if the grantee is not found or if an error occurs during fetching.
2816
+ *
2817
+ * @param granteeId - Unique numeric ID of the grantee (1-indexed)
2818
+ * @returns Grantee information including ID, addresses, public key, and permission IDs, or `null` if not found
2595
2819
  *
2596
2820
  * @example
2597
2821
  * ```typescript
@@ -2599,7 +2823,7 @@ class PermissionsController extends BaseController {
2599
2823
  *
2600
2824
  * if (grantee) {
2601
2825
  * console.log(`Grantee ID: ${grantee.id}`);
2602
- * console.log(`Address: ${grantee.granteeAddress}`);
2826
+ * console.log(`Address: ${grantee.address}`);
2603
2827
  * console.log(`Owner: ${grantee.owner}`);
2604
2828
  * console.log(`Total permissions: ${grantee.permissionIds.length}`);
2605
2829
  * } else {
@@ -2615,18 +2839,23 @@ class PermissionsController extends BaseController {
2615
2839
  );
2616
2840
  const DataPortabilityGranteesAbi = getAbi("DataPortabilityGrantees");
2617
2841
  try {
2618
- const granteeInfo = await this.context.publicClient.readContract({
2842
+ const granteeInfoResult = await this.context.publicClient.readContract({
2619
2843
  address: DataPortabilityGranteesAddress,
2620
2844
  abi: DataPortabilityGranteesAbi,
2621
- functionName: "grantees",
2845
+ functionName: "granteesV2",
2622
2846
  args: [BigInt(granteeId)]
2623
2847
  });
2848
+ const granteeInfo = granteeInfoResult;
2849
+ const allPermissionIdsResult = await this.getGranteePermissionsPaginated(
2850
+ BigInt(granteeId)
2851
+ );
2852
+ const allPermissionIds = allPermissionIdsResult;
2624
2853
  return {
2625
2854
  id: granteeId,
2626
2855
  owner: granteeInfo.owner,
2627
2856
  address: granteeInfo.granteeAddress,
2628
2857
  publicKey: granteeInfo.publicKey,
2629
- permissionIds: granteeInfo.permissionIds.map((id) => Number(id))
2858
+ permissionIds: allPermissionIds.map((id) => Number(id))
2630
2859
  };
2631
2860
  } catch (error) {
2632
2861
  console.warn(`Failed to fetch grantee ${granteeId}:`, error);
@@ -3023,6 +3252,31 @@ class PermissionsController extends BaseController {
3023
3252
  );
3024
3253
  }
3025
3254
  }
3255
+ /**
3256
+ * Retrieves detailed grant file data from IPFS or HTTP storage.
3257
+ *
3258
+ * @remarks
3259
+ * This method automatically uses the SDK's configured downloadRelayer to bypass CORS restrictions.
3260
+ * Use this instead of importing the standalone `retrieveGrantFile` utility.
3261
+ *
3262
+ * @param grantUrl - The grant file URL (from OnChainPermissionGrant.grantUrl)
3263
+ * @returns Promise resolving to the complete grant file with operation details
3264
+ * @throws {NetworkError} When all retrieval attempts fail
3265
+ * @example
3266
+ * ```typescript
3267
+ * const grants = await vana.permissions.getUserPermissionGrantsOnChain();
3268
+ * const grantFile = await vana.permissions.retrieveGrantFile(grants[0].grantUrl);
3269
+ * console.log(`Operation: ${grantFile.operation}`);
3270
+ * ```
3271
+ */
3272
+ async retrieveGrantFile(grantUrl) {
3273
+ const { retrieveGrantFile: retrieveGrantFileUtil } = await import("../utils/grantFiles");
3274
+ return retrieveGrantFileUtil(
3275
+ grantUrl,
3276
+ void 0,
3277
+ this.context.downloadRelayer
3278
+ );
3279
+ }
3026
3280
  /**
3027
3281
  * Get all permissions for a specific file (alias for getFilePermissionIds)
3028
3282
  *
@@ -3048,26 +3302,34 @@ class PermissionsController extends BaseController {
3048
3302
  // DATA PORTABILITY GRANTEES HELPER METHODS
3049
3303
  // ===========================
3050
3304
  /**
3051
- * Get grantee information by grantee ID
3305
+ * Retrieves detailed grantee information including all associated permissions.
3306
+ *
3307
+ * @remarks
3308
+ * Returns grantee metadata and associated permission IDs. Uses the newer
3309
+ * paginated contract method internally for efficient permission fetching.
3052
3310
  *
3053
- * @param granteeId - Grantee ID to get info for
3054
- * @returns Promise resolving to grantee info
3311
+ * @param granteeId - Unique grantee identifier as bigint
3312
+ * @returns Grantee information containing owner address, grantee address, public key, and permission IDs
3313
+ * @throws {BlockchainError} When grantee ID is not found or contract read fails
3314
+ *
3315
+ * @example
3316
+ * ```typescript
3317
+ * const granteeInfo = await vana.permissions.getGranteeInfo(BigInt(1));
3318
+ * console.log(`Grantee ${granteeInfo.granteeAddress} has ${granteeInfo.permissionIds.length} permissions`);
3319
+ * ```
3055
3320
  */
3056
3321
  async getGranteeInfo(granteeId) {
3057
3322
  try {
3058
- const chainId = await this.context.publicClient.getChainId();
3059
- const DataPortabilityGranteesAddress = getContractAddress(
3060
- chainId,
3061
- "DataPortabilityGrantees"
3062
- );
3063
- const DataPortabilityGranteesAbi = getAbi("DataPortabilityGrantees");
3064
- const granteeInfo = await this.context.publicClient.readContract({
3065
- address: DataPortabilityGranteesAddress,
3066
- abi: DataPortabilityGranteesAbi,
3067
- functionName: "granteeInfo",
3068
- args: [granteeId]
3069
- });
3070
- return granteeInfo;
3323
+ const grantee = await this.getGranteeById(Number(granteeId));
3324
+ if (!grantee) {
3325
+ throw new Error("Grantee not found");
3326
+ }
3327
+ return {
3328
+ owner: grantee.owner,
3329
+ granteeAddress: grantee.address,
3330
+ publicKey: grantee.publicKey,
3331
+ permissionIds: grantee.permissionIds.map((id) => BigInt(id))
3332
+ };
3071
3333
  } catch (error) {
3072
3334
  throw new BlockchainError(
3073
3335
  `Failed to get grantee info: ${error instanceof Error ? error.message : "Unknown error"}`,
@@ -3076,10 +3338,21 @@ class PermissionsController extends BaseController {
3076
3338
  }
3077
3339
  }
3078
3340
  /**
3079
- * Get grantee information by grantee address
3341
+ * Retrieves detailed grantee information by wallet address.
3342
+ *
3343
+ * @remarks
3344
+ * Looks up the grantee ID from the provided address, then fetches complete
3345
+ * grantee information including all associated permissions.
3346
+ *
3347
+ * @param granteeAddress - Ethereum wallet address of the grantee to query
3348
+ * @returns Grantee information containing owner address, grantee address, public key, and permission IDs
3349
+ * @throws {BlockchainError} When grantee address is not registered or contract read fails
3080
3350
  *
3081
- * @param granteeAddress - Grantee address to get info for
3082
- * @returns Promise resolving to grantee info
3351
+ * @example
3352
+ * ```typescript
3353
+ * const granteeInfo = await vana.permissions.getGranteeInfoByAddress("0x742d35Cc6634c0532925a3b844Bc9e8e1ee3b2De");
3354
+ * console.log(`Found grantee with ${granteeInfo.permissionIds.length} permissions`);
3355
+ * ```
3083
3356
  */
3084
3357
  async getGranteeInfoByAddress(granteeAddress) {
3085
3358
  try {
@@ -3089,13 +3362,26 @@ class PermissionsController extends BaseController {
3089
3362
  "DataPortabilityGrantees"
3090
3363
  );
3091
3364
  const DataPortabilityGranteesAbi = getAbi("DataPortabilityGrantees");
3092
- const granteeInfo = await this.context.publicClient.readContract({
3365
+ const granteeIdResult = await this.context.publicClient.readContract({
3093
3366
  address: DataPortabilityGranteesAddress,
3094
3367
  abi: DataPortabilityGranteesAbi,
3095
- functionName: "granteeByAddress",
3368
+ functionName: "granteeAddressToId",
3096
3369
  args: [granteeAddress]
3097
3370
  });
3098
- return granteeInfo;
3371
+ const granteeId = granteeIdResult;
3372
+ if (granteeId === 0n) {
3373
+ throw new Error("Grantee not found");
3374
+ }
3375
+ const grantee = await this.getGranteeById(Number(granteeId));
3376
+ if (!grantee) {
3377
+ throw new Error("Grantee not found");
3378
+ }
3379
+ return {
3380
+ owner: grantee.owner,
3381
+ granteeAddress: grantee.address,
3382
+ publicKey: grantee.publicKey,
3383
+ permissionIds: grantee.permissionIds.map((id) => BigInt(id))
3384
+ };
3099
3385
  } catch (error) {
3100
3386
  throw new BlockchainError(
3101
3387
  `Failed to get grantee info by address: ${error instanceof Error ? error.message : "Unknown error"}`,
@@ -3159,6 +3445,117 @@ class PermissionsController extends BaseController {
3159
3445
  );
3160
3446
  }
3161
3447
  }
3448
+ /**
3449
+ * Retrieves permission IDs for a specific grantee with flexible pagination.
3450
+ *
3451
+ * @remarks
3452
+ * **Pagination Behavior:**
3453
+ * Returns different types based on parameters:
3454
+ * - Without offset/limit: Returns `bigint[]` of all permissions using batched multicall
3455
+ * - With offset/limit: Returns paginated object with `permissionIds`, `totalCount`, and `hasMore`
3456
+ *
3457
+ * Uses gas-aware multicall for efficient batch fetching when retrieving all permissions.
3458
+ *
3459
+ * @param granteeId - Grantee ID to get permissions for
3460
+ * @param options - Optional pagination parameters
3461
+ * @param options.offset - Zero-based starting index for pagination. Defaults to 0 when fetching all permissions. Required for single-page requests.
3462
+ * @param options.limit - Maximum number of permission IDs to return per page. Defaults to 100 when fetching all permissions. Required for single-page requests.
3463
+ * @returns When called without options: Array of all permission IDs as `bigint[]`.
3464
+ * When called with offset and limit: Paginated result object containing `permissionIds` array,
3465
+ * `totalCount`, and `hasMore` boolean.
3466
+ * @throws {BlockchainError} When contract read operation fails
3467
+ *
3468
+ * @example
3469
+ * ```typescript
3470
+ * // Fetch all permissions (no pagination params)
3471
+ * const allPermissions = await vana.permissions.getGranteePermissionsPaginated(BigInt(1));
3472
+ * console.log(`Total permissions: ${allPermissions.length}`);
3473
+ *
3474
+ * // Fetch a specific page (with pagination params)
3475
+ * const page = await vana.permissions.getGranteePermissionsPaginated(BigInt(1), {
3476
+ * offset: BigInt(0),
3477
+ * limit: BigInt(100)
3478
+ * });
3479
+ * console.log(`Fetched ${page.permissionIds.length} permissions`);
3480
+ * console.log(`Total: ${page.totalCount}, Has more: ${page.hasMore}`);
3481
+ *
3482
+ * // Fetch next page
3483
+ * if (page.hasMore) {
3484
+ * const nextPage = await vana.permissions.getGranteePermissionsPaginated(BigInt(1), {
3485
+ * offset: BigInt(100),
3486
+ * limit: BigInt(100)
3487
+ * });
3488
+ * }
3489
+ * ```
3490
+ */
3491
+ async getGranteePermissionsPaginated(granteeId, options) {
3492
+ try {
3493
+ const chainId = await this.context.publicClient.getChainId();
3494
+ const DataPortabilityGranteesAddress = getContractAddress(
3495
+ chainId,
3496
+ "DataPortabilityGrantees"
3497
+ );
3498
+ const DataPortabilityGranteesAbi = getAbi("DataPortabilityGrantees");
3499
+ const fetchOnlyOnePage = options?.offset !== void 0 && options?.limit !== void 0;
3500
+ if (fetchOnlyOnePage) {
3501
+ const result = await this.context.publicClient.readContract({
3502
+ address: DataPortabilityGranteesAddress,
3503
+ abi: DataPortabilityGranteesAbi,
3504
+ functionName: "granteePermissionsPaginated",
3505
+ args: [granteeId, options.offset, options.limit]
3506
+ });
3507
+ const [permissionIds, totalCount2, hasMore] = result;
3508
+ return {
3509
+ permissionIds: [...permissionIds],
3510
+ totalCount: totalCount2,
3511
+ hasMore
3512
+ };
3513
+ }
3514
+ const countResult = await this.context.publicClient.readContract({
3515
+ address: DataPortabilityGranteesAddress,
3516
+ abi: DataPortabilityGranteesAbi,
3517
+ functionName: "granteePermissionsPaginated",
3518
+ args: [granteeId, BigInt(0), BigInt(1)]
3519
+ });
3520
+ const [, totalCount] = countResult;
3521
+ if (totalCount === BigInt(0)) {
3522
+ return [];
3523
+ }
3524
+ const batchSize = options?.limit ?? BigInt(100);
3525
+ const startOffset = options?.offset ?? BigInt(0);
3526
+ const endOffset = totalCount;
3527
+ const numBatches = Math.ceil(
3528
+ Number(endOffset - startOffset) / Number(batchSize)
3529
+ );
3530
+ const paginationCalls = Array.from({ length: numBatches }, (_, i) => ({
3531
+ address: DataPortabilityGranteesAddress,
3532
+ abi: DataPortabilityGranteesAbi,
3533
+ functionName: "granteePermissionsPaginated",
3534
+ args: [
3535
+ granteeId,
3536
+ startOffset + BigInt(i) * batchSize,
3537
+ batchSize
3538
+ ]
3539
+ }));
3540
+ const results = await gasAwareMulticall(
3541
+ this.context.publicClient,
3542
+ {
3543
+ contracts: paginationCalls
3544
+ }
3545
+ );
3546
+ const allPermissionIds = [];
3547
+ for (const result of results) {
3548
+ const [permissionIds] = result;
3549
+ allPermissionIds.push(...permissionIds);
3550
+ }
3551
+ return allPermissionIds;
3552
+ } catch (error) {
3553
+ throw new BlockchainError(
3554
+ `Failed to get grantee permissions: ${error instanceof Error ? error.message : "Unknown error"}`,
3555
+ error
3556
+ );
3557
+ }
3558
+ }
3162
3559
  // ===== DataPortabilityServersImplementation Methods =====
3163
3560
  /**
3164
3561
  * Get all server IDs for a user
@@ -3372,7 +3769,7 @@ class PermissionsController extends BaseController {
3372
3769
  args: [serverId, url],
3373
3770
  chain: this.context.walletClient?.chain,
3374
3771
  account,
3375
- ...options?.gasLimit && { gas: options.gasLimit },
3772
+ ...options?.gas && { gas: options.gas },
3376
3773
  ...options?.nonce && { nonce: options.nonce },
3377
3774
  // Use EIP-1559 if available, otherwise fall back to legacy gasPrice
3378
3775
  ...options?.maxFeePerGas || options?.maxPriorityFeePerGas ? {
@@ -3578,7 +3975,7 @@ class PermissionsController extends BaseController {
3578
3975
  * @throws {BlockchainError} When permission addition fails
3579
3976
  * @throws {NetworkError} When network communication fails
3580
3977
  */
3581
- async submitSignedAddPermission(typedData, signature) {
3978
+ async submitSignedAddPermission(typedData, signature, options) {
3582
3979
  this.assertWallet();
3583
3980
  try {
3584
3981
  let hash;
@@ -3593,7 +3990,9 @@ class PermissionsController extends BaseController {
3593
3990
  if (response.type === "error") {
3594
3991
  throw new RelayerError(response.error);
3595
3992
  }
3596
- if (response.type === "signed") {
3993
+ if (response.type === "submitted") {
3994
+ hash = response.hash;
3995
+ } else if (response.type === "signed") {
3597
3996
  hash = response.hash;
3598
3997
  } else {
3599
3998
  throw new Error("Unexpected response type from relayer");
@@ -3601,7 +4000,8 @@ class PermissionsController extends BaseController {
3601
4000
  } else {
3602
4001
  hash = await this.submitDirectAddPermissionTransaction(
3603
4002
  typedData,
3604
- signature
4003
+ signature,
4004
+ options
3605
4005
  );
3606
4006
  }
3607
4007
  const account = this.context.walletClient?.account ?? this.context.userAddress;
@@ -3770,7 +4170,9 @@ class PermissionsController extends BaseController {
3770
4170
  if (response.type === "error") {
3771
4171
  throw new RelayerError(response.error);
3772
4172
  }
3773
- if (response.type === "signed") {
4173
+ if (response.type === "submitted") {
4174
+ hash = response.hash;
4175
+ } else if (response.type === "signed") {
3774
4176
  hash = response.hash;
3775
4177
  } else {
3776
4178
  throw new Error("Unexpected response type from relayer");
@@ -3832,7 +4234,7 @@ class PermissionsController extends BaseController {
3832
4234
  args: [permissionId],
3833
4235
  chain: this.context.walletClient?.chain,
3834
4236
  account,
3835
- ...options?.gasLimit && { gas: options.gasLimit },
4237
+ ...options?.gas && { gas: options.gas },
3836
4238
  ...options?.nonce && { nonce: options.nonce },
3837
4239
  // Use EIP-1559 if available, otherwise fall back to legacy gasPrice
3838
4240
  ...options?.maxFeePerGas || options?.maxPriorityFeePerGas ? {
@@ -3865,7 +4267,7 @@ class PermissionsController extends BaseController {
3865
4267
  * @param signature - The cryptographic signature authorizing the transaction
3866
4268
  * @returns Promise resolving to the transaction hash
3867
4269
  */
3868
- async submitDirectAddPermissionTransaction(typedData, signature) {
4270
+ async submitDirectAddPermissionTransaction(typedData, signature, options) {
3869
4271
  this.assertWallet();
3870
4272
  const chainId = await this.context.walletClient.getChainId();
3871
4273
  const DataPortabilityPermissionsAddress = getContractAddress(
@@ -3886,7 +4288,8 @@ class PermissionsController extends BaseController {
3886
4288
  functionName: "addPermission",
3887
4289
  args: [permissionInput, formattedSignature],
3888
4290
  account: this.context.walletClient?.account ?? this.context.userAddress,
3889
- chain: this.context.walletClient?.chain ?? null
4291
+ chain: this.context.walletClient?.chain ?? null,
4292
+ ...this.spreadTransactionOptions(options)
3890
4293
  });
3891
4294
  return hash;
3892
4295
  }
@@ -3921,22 +4324,11 @@ class PermissionsController extends BaseController {
3921
4324
  address: DataPortabilityPermissionsAddress,
3922
4325
  abi: DataPortabilityPermissionsAbi,
3923
4326
  functionName: "addServerFilesAndPermissions",
3924
- // @ts-expect-error - Viem's type inference for nested Permission[][] arrays is incompatible with our Permission type
3925
4327
  args: [serverFilesAndPermissionInput, formattedSignature],
3926
4328
  account: this.context.walletClient?.account ?? this.context.userAddress,
3927
4329
  chain: this.context.walletClient?.chain ?? null,
3928
- ...options?.gasLimit && { gas: options.gasLimit },
3929
- ...options?.nonce && { nonce: options.nonce },
3930
4330
  ...options?.value && { value: options.value },
3931
- // Use EIP-1559 if available, otherwise fall back to legacy gasPrice
3932
- ...options?.maxFeePerGas || options?.maxPriorityFeePerGas ? {
3933
- ...options.maxFeePerGas && {
3934
- maxFeePerGas: options.maxFeePerGas
3935
- },
3936
- ...options.maxPriorityFeePerGas && {
3937
- maxPriorityFeePerGas: options.maxPriorityFeePerGas
3938
- }
3939
- } : options?.gasPrice && { gasPrice: options.gasPrice }
4331
+ ...this.spreadTransactionOptions(options)
3940
4332
  });
3941
4333
  return hash;
3942
4334
  }