@poa-box/core 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +2 -0
  2. package/dist/abis/AuthorityRouter.d.ts +448 -0
  3. package/dist/abis/AuthorityRouter.js +584 -0
  4. package/dist/abis/CutoverVerifier.d.ts +194 -0
  5. package/dist/abis/CutoverVerifier.js +259 -0
  6. package/dist/abis/DirectDemocracyVotingNew.d.ts +168 -30
  7. package/dist/abis/DirectDemocracyVotingNew.js +214 -35
  8. package/dist/abis/EducationHubNew.d.ts +32 -75
  9. package/dist/abis/EducationHubNew.js +38 -94
  10. package/dist/abis/Executor.d.ts +56 -86
  11. package/dist/abis/Executor.js +68 -104
  12. package/dist/abis/HybridVotingNew.d.ts +279 -35
  13. package/dist/abis/HybridVotingNew.js +357 -40
  14. package/dist/abis/{EligibilityModuleNew.d.ts → MembershipAuthority.d.ts} +1437 -718
  15. package/dist/abis/{EligibilityModuleNew.js → MembershipAuthority.js} +1821 -899
  16. package/dist/abis/OrgDeployerNew.d.ts +193 -127
  17. package/dist/abis/OrgDeployerNew.js +244 -160
  18. package/dist/abis/OrgRegistry.d.ts +40 -0
  19. package/dist/abis/OrgRegistry.js +51 -0
  20. package/dist/abis/ParticipationToken.d.ts +32 -75
  21. package/dist/abis/ParticipationToken.js +38 -94
  22. package/dist/abis/PasskeyAccount.d.ts +28 -0
  23. package/dist/abis/PasskeyAccount.js +35 -0
  24. package/dist/abis/PaymasterHub.d.ts +527 -47
  25. package/dist/abis/PaymasterHub.js +750 -135
  26. package/dist/abis/QuickJoinNew.d.ts +59 -170
  27. package/dist/abis/QuickJoinNew.js +71 -215
  28. package/dist/abis/TaskManagerNew.d.ts +27 -44
  29. package/dist/abis/TaskManagerNew.js +31 -52
  30. package/dist/abis/UniversalAccountRegistry.d.ts +24 -0
  31. package/dist/abis/UniversalAccountRegistry.js +30 -0
  32. package/dist/abis/ZkEmailInvites.d.ts +44 -0
  33. package/dist/abis/ZkEmailInvites.js +55 -0
  34. package/dist/abis/index.d.ts +6 -4
  35. package/dist/abis/index.js +10 -7
  36. package/dist/chains.js +3 -3
  37. package/dist/error-catalog.js +125 -7
  38. package/dist/graph/documents/activity.d.ts +3 -1
  39. package/dist/graph/documents/activity.js +19 -14
  40. package/dist/graph/documents/org.d.ts +4 -4
  41. package/dist/graph/documents/org.js +10 -4
  42. package/dist/graph/documents/task.d.ts +10 -1
  43. package/dist/graph/documents/task.js +157 -3
  44. package/dist/graph/documents/user.d.ts +5 -30
  45. package/dist/graph/documents/user.js +2 -42
  46. package/dist/graph/documents/voting-classes.d.ts +23 -2
  47. package/dist/graph/documents/voting-classes.js +119 -10
  48. package/dist/metadata/index.d.ts +0 -1
  49. package/dist/metadata/index.js +1 -2
  50. package/dist/perms.d.ts +0 -15
  51. package/dist/perms.js +1 -21
  52. package/dist/preflight.d.ts +2 -2
  53. package/dist/preflight.js +14 -22
  54. package/dist/reads/authority.d.ts +33 -0
  55. package/dist/reads/authority.js +196 -0
  56. package/dist/reads/index.d.ts +1 -1
  57. package/dist/reads/index.js +2 -2
  58. package/dist/reads/org.d.ts +20 -20
  59. package/dist/reads/org.js +94 -28
  60. package/dist/reads/project.js +3 -3
  61. package/dist/reads/resolve.d.ts +1 -1
  62. package/dist/reads/resolve.js +12 -3
  63. package/dist/reads/task.d.ts +44 -22
  64. package/dist/reads/task.js +126 -67
  65. package/dist/reads/user.d.ts +8 -43
  66. package/dist/reads/user.js +27 -44
  67. package/dist/reads/vote.d.ts +26 -2
  68. package/dist/reads/vote.js +104 -23
  69. package/dist/tx/authority.d.ts +33 -0
  70. package/dist/tx/authority.js +62 -0
  71. package/dist/tx/governance.d.ts +6 -0
  72. package/dist/tx/governance.js +20 -2
  73. package/dist/tx/index.d.ts +1 -1
  74. package/dist/tx/index.js +2 -2
  75. package/dist/tx/org.d.ts +23 -18
  76. package/dist/tx/org.js +203 -67
  77. package/dist/tx/project.d.ts +3 -2
  78. package/dist/tx/project.js +28 -10
  79. package/dist/tx/task.d.ts +13 -24
  80. package/dist/tx/task.js +45 -85
  81. package/dist/tx/user.d.ts +2 -40
  82. package/dist/tx/user.js +2 -76
  83. package/dist/tx/vote.d.ts +5 -0
  84. package/dist/tx/vote.js +54 -43
  85. package/dist/version.d.ts +0 -5
  86. package/dist/version.js +1 -13
  87. package/package.json +1 -1
  88. package/dist/abis/ToggleModule.d.ts +0 -193
  89. package/dist/abis/ToggleModule.js +0 -255
  90. package/dist/metadata/role.d.ts +0 -38
  91. package/dist/metadata/role.js +0 -35
  92. package/dist/reads/eligibility.d.ts +0 -377
  93. package/dist/reads/eligibility.js +0 -687
  94. package/dist/tx/eligibility.d.ts +0 -511
  95. package/dist/tx/eligibility.js +0 -818
@@ -3,7 +3,7 @@
3
3
  * Ported from frontend queries.js
4
4
  */
5
5
  import type { FieldFallbackTier } from '../client';
6
- export declare const FETCH_PROJECTS_DATA = "\n query FetchProjectsDataNew($orgId: Bytes!) {\n organization(id: $orgId) {\n id\n taskManager {\n id\n creatorHatIds\n projects(where: { deleted: false }, first: 50) {\n id\n title\n metadataHash\n metadata {\n id\n description\n }\n cap\n bountyCaps {\n token\n cap\n }\n createdAt\n tasks(first: 1000, orderBy: taskId, orderDirection: desc) {\n id\n taskId\n title\n metadataHash\n submissionHash\n rejectionHash\n rejectionCount\n metadata {\n id\n name\n description\n location\n difficulty\n estimatedHours\n dueDate\n submission\n rejection\n }\n rejections(orderBy: rejectedAt, orderDirection: desc, first: 10) {\n rejectorUsername\n rejectedAt\n metadata {\n rejection\n }\n }\n payout\n bountyToken\n bountyPayout\n completionWindow\n absoluteDeadline\n claimDeadline\n reclaimCount\n status\n assignee\n assigneeUsername\n completer\n completerUsername\n requiresApplication\n createdAt\n assignedAt\n submittedAt\n completedAt\n applications {\n applicant\n applicantUsername\n applicationHash\n metadata {\n notes\n experience\n }\n approved\n approver\n approverUsername\n appliedAt\n }\n }\n }\n }\n }\n }\n";
6
+ export declare const FETCH_PROJECTS_DATA = "\n query FetchProjectsDataNew($orgId: Bytes!, $projectCursor: String = \"\") {\n organization(id: $orgId) {\n id\n taskManager {\n id\n creatorHatIds\n projects(where: { deleted: false, id_gt: $projectCursor }, first: 50, orderBy: id, orderDirection: asc) {\n id\n title\n metadataHash\n metadata {\n id\n description\n }\n cap\n bountyCaps {\n token\n cap\n }\n createdAt\n tasks(first: 1000, orderBy: taskId, orderDirection: desc) {\n id\n taskId\n title\n metadataHash\n submissionHash\n rejectionHash\n rejectionCount\n metadata {\n id\n name\n description\n location\n difficulty\n estimatedHours\n dueDate\n submission\n rejection\n }\n rejections(orderBy: rejectedAt, orderDirection: desc, first: 10) {\n rejectorUsername\n rejectedAt\n metadata {\n rejection\n }\n }\n payout\n bountyToken\n bountyPayout\n completionWindow\n absoluteDeadline\n claimDeadline\n reclaimCount\n status\n assignee\n assigneeUsername\n completer\n completerUsername\n requiresApplication\n createdAt\n assignedAt\n submittedAt\n completedAt\n applications {\n applicant\n applicantUsername\n applicationHash\n metadata {\n notes\n experience\n }\n approved\n approver\n approverUsername\n appliedAt\n }\n }\n }\n }\n }\n }\n";
7
7
  /**
8
8
  * FETCH_PROJECTS_DATA without the TaskManager v6 deadline fields (subgraph #192).
9
9
  *
@@ -82,3 +82,12 @@ export declare const FETCH_TASK_RELEASE_HISTORY_LEGACY = "\n query FetchTaskRel
82
82
  * checksummed address returns `[]` silently rather than erroring.
83
83
  */
84
84
  export declare const FETCH_ORG_TASK_RELEASES = "\n query FetchOrgTaskReleases($taskManager: Bytes!, $first: Int!, $skip: Int!) {\n taskReleases(\n where: { task_: { taskManager: $taskManager } }\n orderBy: releasedAt\n orderDirection: desc\n first: $first\n skip: $skip\n ) {\n id\n previousClaimer\n previousClaimerUsername\n caller\n callerUsername\n selfRelease\n releasedAt\n transactionHash\n task {\n id\n taskId\n title\n status\n releaseCount\n }\n }\n }\n";
85
+ /** A direct task lookup avoids the org tree's project/task page limits. */
86
+ export declare const FETCH_TASK_DATA = "\n query FetchTaskData($taskId: ID!) {\n task(id: $taskId) {\n id\n taskId\n title\n metadataHash\n submissionHash\n rejectionHash\n rejectionCount\n metadata {\n id\n name\n description\n location\n difficulty\n estimatedHours\n dueDate\n submission\n rejection\n }\n rejections(orderBy: rejectedAt, orderDirection: desc, first: 10) {\n rejectorUsername\n rejectedAt\n metadata {\n rejection\n }\n }\n payout\n bountyToken\n bountyPayout\n completionWindow\n absoluteDeadline\n claimDeadline\n reclaimCount\n status\n assignee\n assigneeUsername\n completer\n completerUsername\n requiresApplication\n createdAt\n assignedAt\n submittedAt\n completedAt\n applications {\n applicant\n applicantUsername\n applicationHash\n metadata {\n notes\n experience\n }\n approved\n approver\n approverUsername\n appliedAt\n }\n project { id title }\n }\n }\n";
87
+ export declare const FETCH_TASK_DATA_WITH_RELEASES: string;
88
+ export declare const FETCH_TASK_DATA_LEGACY: string;
89
+ /** Follow-up page for a single project's tasks. taskId is unique within its TaskManager. */
90
+ export declare const FETCH_PROJECT_TASK_PAGE = "\n query FetchProjectTaskPage($projectId: ID!, $taskCursor: BigInt!) {\n project(id: $projectId) {\n id\n tasks(first: 1000, orderBy: taskId, orderDirection: desc, where: { taskId_lt: $taskCursor }) {\n id\n taskId\n title\n metadataHash\n submissionHash\n rejectionHash\n rejectionCount\n metadata {\n id\n name\n description\n location\n difficulty\n estimatedHours\n dueDate\n submission\n rejection\n }\n rejections(orderBy: rejectedAt, orderDirection: desc, first: 10) {\n rejectorUsername\n rejectedAt\n metadata {\n rejection\n }\n }\n payout\n bountyToken\n bountyPayout\n completionWindow\n absoluteDeadline\n claimDeadline\n reclaimCount\n status\n assignee\n assigneeUsername\n completer\n completerUsername\n requiresApplication\n createdAt\n assignedAt\n submittedAt\n completedAt\n applications {\n applicant\n applicantUsername\n applicationHash\n metadata {\n notes\n experience\n }\n approved\n approver\n approverUsername\n appliedAt\n }\n }\n }\n }\n";
91
+ export declare const PROJECT_TASK_PAGE_TIERS: string[];
92
+ /** PR213 immutable work/review history. ID cursors retain same-timestamp events. */
93
+ export declare const FETCH_TASK_SUBMISSION_HISTORY = "\n query FetchTaskSubmissionHistory($taskId: ID!, $submissionCursor: Bytes!, $rejectionCursor: Bytes!) {\n task(id: $taskId) {\n id\n latestSubmission { id submissionHash submittedAt submittedAtBlock transactionHash metadata { submission } }\n latestRejection { id }\n submissions(first: 1000, orderBy: id, orderDirection: asc, where: { id_gt: $submissionCursor }) {\n id submissionHash submittedAt submittedAtBlock transactionHash metadata { submission }\n }\n rejections(first: 1000, orderBy: id, orderDirection: asc, where: { id_gt: $rejectionCursor }) {\n id rejector rejectorUsername rejectionHash rejectedAt rejectedAtBlock transactionHash\n metadata { rejection }\n submission { id submissionHash submittedAt submittedAtBlock transactionHash metadata { submission } }\n }\n }\n }\n";
@@ -4,17 +4,17 @@
4
4
  * Ported from frontend queries.js
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.FETCH_ORG_TASK_RELEASES = exports.FETCH_TASK_RELEASE_HISTORY_LEGACY = exports.FETCH_TASK_RELEASE_HISTORY = exports.TASK_RELEASE_INDEXING_CHAIN_IDS = exports.PROJECTS_DATA_TIERS = exports.FETCH_PROJECTS_DATA_WITH_RELEASES = exports.FETCH_PROJECTS_DATA_LEGACY = exports.FETCH_PROJECTS_DATA = void 0;
7
+ exports.FETCH_TASK_SUBMISSION_HISTORY = exports.PROJECT_TASK_PAGE_TIERS = exports.FETCH_PROJECT_TASK_PAGE = exports.FETCH_TASK_DATA_LEGACY = exports.FETCH_TASK_DATA_WITH_RELEASES = exports.FETCH_TASK_DATA = exports.FETCH_ORG_TASK_RELEASES = exports.FETCH_TASK_RELEASE_HISTORY_LEGACY = exports.FETCH_TASK_RELEASE_HISTORY = exports.TASK_RELEASE_INDEXING_CHAIN_IDS = exports.PROJECTS_DATA_TIERS = exports.FETCH_PROJECTS_DATA_WITH_RELEASES = exports.FETCH_PROJECTS_DATA_LEGACY = exports.FETCH_PROJECTS_DATA = void 0;
8
8
  exports.projectsDataTiers = projectsDataTiers;
9
9
  exports.chainIndexesTaskReleases = chainIndexesTaskReleases;
10
10
  exports.FETCH_PROJECTS_DATA = `
11
- query FetchProjectsDataNew($orgId: Bytes!) {
11
+ query FetchProjectsDataNew($orgId: Bytes!, $projectCursor: String = "") {
12
12
  organization(id: $orgId) {
13
13
  id
14
14
  taskManager {
15
15
  id
16
16
  creatorHatIds
17
- projects(where: { deleted: false }, first: 50) {
17
+ projects(where: { deleted: false, id_gt: $projectCursor }, first: 50, orderBy: id, orderDirection: asc) {
18
18
  id
19
19
  title
20
20
  metadataHash
@@ -234,3 +234,157 @@ exports.FETCH_ORG_TASK_RELEASES = `
234
234
  }
235
235
  }
236
236
  `;
237
+ /** A direct task lookup avoids the org tree's project/task page limits. */
238
+ exports.FETCH_TASK_DATA = `
239
+ query FetchTaskData($taskId: ID!) {
240
+ task(id: $taskId) {
241
+ id
242
+ taskId
243
+ title
244
+ metadataHash
245
+ submissionHash
246
+ rejectionHash
247
+ rejectionCount
248
+ metadata {
249
+ id
250
+ name
251
+ description
252
+ location
253
+ difficulty
254
+ estimatedHours
255
+ dueDate
256
+ submission
257
+ rejection
258
+ }
259
+ rejections(orderBy: rejectedAt, orderDirection: desc, first: 10) {
260
+ rejectorUsername
261
+ rejectedAt
262
+ metadata {
263
+ rejection
264
+ }
265
+ }
266
+ payout
267
+ bountyToken
268
+ bountyPayout
269
+ completionWindow
270
+ absoluteDeadline
271
+ claimDeadline
272
+ reclaimCount
273
+ status
274
+ assignee
275
+ assigneeUsername
276
+ completer
277
+ completerUsername
278
+ requiresApplication
279
+ createdAt
280
+ assignedAt
281
+ submittedAt
282
+ completedAt
283
+ applications {
284
+ applicant
285
+ applicantUsername
286
+ applicationHash
287
+ metadata {
288
+ notes
289
+ experience
290
+ }
291
+ approved
292
+ approver
293
+ approverUsername
294
+ appliedAt
295
+ }
296
+ project { id title }
297
+ }
298
+ }
299
+ `;
300
+ exports.FETCH_TASK_DATA_WITH_RELEASES = exports.FETCH_TASK_DATA.replace(/^(\s*)reclaimCount$/m, '$1reclaimCount\n$1releaseCount\n$1lastReleasedAt');
301
+ exports.FETCH_TASK_DATA_LEGACY = exports.FETCH_TASK_DATA.split('\n')
302
+ .filter(line => !/^\s*(completionWindow|absoluteDeadline|claimDeadline|reclaimCount)\s*$/.test(line)).join('\n');
303
+ /** Follow-up page for a single project's tasks. taskId is unique within its TaskManager. */
304
+ exports.FETCH_PROJECT_TASK_PAGE = `
305
+ query FetchProjectTaskPage($projectId: ID!, $taskCursor: BigInt!) {
306
+ project(id: $projectId) {
307
+ id
308
+ tasks(first: 1000, orderBy: taskId, orderDirection: desc, where: { taskId_lt: $taskCursor }) {
309
+ id
310
+ taskId
311
+ title
312
+ metadataHash
313
+ submissionHash
314
+ rejectionHash
315
+ rejectionCount
316
+ metadata {
317
+ id
318
+ name
319
+ description
320
+ location
321
+ difficulty
322
+ estimatedHours
323
+ dueDate
324
+ submission
325
+ rejection
326
+ }
327
+ rejections(orderBy: rejectedAt, orderDirection: desc, first: 10) {
328
+ rejectorUsername
329
+ rejectedAt
330
+ metadata {
331
+ rejection
332
+ }
333
+ }
334
+ payout
335
+ bountyToken
336
+ bountyPayout
337
+ completionWindow
338
+ absoluteDeadline
339
+ claimDeadline
340
+ reclaimCount
341
+ status
342
+ assignee
343
+ assigneeUsername
344
+ completer
345
+ completerUsername
346
+ requiresApplication
347
+ createdAt
348
+ assignedAt
349
+ submittedAt
350
+ completedAt
351
+ applications {
352
+ applicant
353
+ applicantUsername
354
+ applicationHash
355
+ metadata {
356
+ notes
357
+ experience
358
+ }
359
+ approved
360
+ approver
361
+ approverUsername
362
+ appliedAt
363
+ }
364
+ }
365
+ }
366
+ }
367
+ `;
368
+ exports.PROJECT_TASK_PAGE_TIERS = [
369
+ exports.FETCH_PROJECT_TASK_PAGE.replace(/^(\s*)reclaimCount$/m, '$1reclaimCount\n$1releaseCount\n$1lastReleasedAt'),
370
+ exports.FETCH_PROJECT_TASK_PAGE,
371
+ exports.FETCH_PROJECT_TASK_PAGE.split('\n').filter(line => !/^\s*(completionWindow|absoluteDeadline|claimDeadline|reclaimCount)\s*$/.test(line)).join('\n'),
372
+ ];
373
+ /** PR213 immutable work/review history. ID cursors retain same-timestamp events. */
374
+ exports.FETCH_TASK_SUBMISSION_HISTORY = `
375
+ query FetchTaskSubmissionHistory($taskId: ID!, $submissionCursor: Bytes!, $rejectionCursor: Bytes!) {
376
+ task(id: $taskId) {
377
+ id
378
+ latestSubmission { id submissionHash submittedAt submittedAtBlock transactionHash metadata { submission } }
379
+ latestRejection { id }
380
+ submissions(first: 1000, orderBy: id, orderDirection: asc, where: { id_gt: $submissionCursor }) {
381
+ id submissionHash submittedAt submittedAtBlock transactionHash metadata { submission }
382
+ }
383
+ rejections(first: 1000, orderBy: id, orderDirection: asc, where: { id_gt: $rejectionCursor }) {
384
+ id rejector rejectorUsername rejectionHash rejectedAt rejectedAtBlock transactionHash
385
+ metadata { rejection }
386
+ submission { id submissionHash submittedAt submittedAtBlock transactionHash metadata { submission } }
387
+ }
388
+ }
389
+ }
390
+ `;
@@ -5,28 +5,8 @@
5
5
  import type { FieldFallbackTier } from '../client';
6
6
  export declare const FETCH_USERNAME = "\n query FetchUsernameNew($id: Bytes!) {\n account(id: $id) {\n id\n username\n profileMetadataHash\n metadata {\n id\n bio\n avatar\n github\n twitter\n website\n }\n }\n }\n";
7
7
  export declare const GET_ACCOUNT_BY_USERNAME = "\n query GetAccountByUsername($username: String!) {\n accounts(where: { username: $username }, first: 1) {\n id\n user\n username\n }\n }\n";
8
- /**
9
- * One-round-trip org snapshot for `pop user whoami`: org name + role-hat
10
- * names, the org's QuickJoin module pointers, the caller's account
11
- * (username + which registry it lives on), their ERC-20 participation-token
12
- * balance, their org-user entity (membership, PT balance, hats worn), and
13
- * their pending participation-token requests. The `status: Pending`
14
- * filter is inlined (enum literal) to match FETCH_PENDING_TOKEN_REQUESTS
15
- * in queries/token.ts.
16
- *
17
- * Every field here was verified NON-NULL against the live Gnosis
18
- * (poa-gnosis-v-1) AND Arbitrum (poa-arb-v-1) deployments, and
19
- * quickJoinContract.{accountRegistry,hatsContract,memberHatIds} were
20
- * byte-compared against the matching eth_calls on both chains — including
21
- * the empty-array memberHatIds case, which is genuinely empty on-chain and
22
- * not an indexing gap.
23
- *
24
- * `account.registry` is carried so callers can prove the indexed account
25
- * belongs to the SAME registry the org's QuickJoin consults before trusting
26
- * the indexed username (a legacy org can point at a registry this subgraph
27
- * does not index).
28
- */
29
- export declare const FETCH_WHOAMI_ORG_DATA = "\n query WhoamiOrgData(\n $orgId: Bytes!\n $orgUserID: String!\n $tokenAddress: String!\n $userAddress: Bytes!\n $quickJoinAddress: ID!\n $accountID: ID!\n $tokenBalanceID: ID!\n ) {\n organization(id: $orgId) {\n id\n name\n roles(where: { isUserRole: true }) {\n hatId\n name\n # Hats Protocol's toggle flag. When it is false, Hats.isWearerOfHat returns\n # false for EVERY wearer regardless of token balance, and the tokens are NOT\n # burned \u2014 so User.currentHatIds still lists the hat. A membership answer\n # derived from currentHatIds alone must AND it with this flag.\n hat {\n active\n }\n }\n }\n quickJoinContract(id: $quickJoinAddress) {\n id\n accountRegistry\n hatsContract\n memberHatIds\n }\n account(id: $accountID) {\n id\n username\n isDeleted\n registry {\n id\n }\n }\n tokenBalance(id: $tokenBalanceID) {\n id\n balance\n }\n user(id: $orgUserID) {\n id\n membershipStatus\n participationTokenBalance\n currentHatIds\n }\n tokenRequests(\n where: { participationToken: $tokenAddress, requester: $userAddress, status: Pending }\n first: 100\n ) {\n id\n }\n }\n";
8
+ /** Historical account and token snapshot; current membership is projected from the authority index. */
9
+ export declare const FETCH_WHOAMI_ORG_DATA = "\n query WhoamiOrgData(\n $orgId: Bytes!\n $orgUserID: String!\n $tokenAddress: String!\n $userAddress: Bytes!\n $quickJoinAddress: ID!\n $accountID: ID!\n $tokenBalanceID: ID!\n ) {\n organization(id: $orgId) {\n id\n name\n }\n quickJoinContract(id: $quickJoinAddress) {\n id\n accountRegistry\n }\n account(id: $accountID) {\n id\n username\n isDeleted\n registry {\n id\n }\n }\n tokenBalance(id: $tokenBalanceID) {\n id\n balance\n }\n user(id: $orgUserID) {\n id\n membershipStatus\n participationTokenBalance\n currentHatIds\n }\n tokenRequests(\n where: { participationToken: $tokenAddress, requester: $userAddress, status: Pending }\n first: 100\n ) {\n id\n }\n }\n";
30
10
  /**
31
11
  * Standalone account lookup (no org): the username + registry for one
32
12
  * address. Account.id is the LOWERCASED address. Used by `pop user whoami`
@@ -45,12 +25,9 @@ export declare const FETCH_ACCOUNT_USERNAME = "\n query AccountUsername($accoun
45
25
  * `account.registry.id === quickJoinContract.accountRegistry` — see the
46
26
  * guard in commands/user/join.ts.
47
27
  */
48
- export declare const FETCH_QUICKJOIN_ACCOUNT = "\n query QuickJoinAccount($quickJoinAddress: ID!, $accountID: ID!) {\n quickJoinContract(id: $quickJoinAddress) {\n id\n accountRegistry\n hatsContract\n memberHatIds\n }\n account(id: $accountID) {\n id\n username\n isDeleted\n registry {\n id\n }\n }\n }\n";
49
- /**
50
- * Just the QuickJoin module pointers — the addresses `pop user claim-hats`
51
- * needs before running its (deliberately on-chain) pre-flight probes.
52
- */
53
- export declare const FETCH_QUICKJOIN_MODULES = "\n query QuickJoinModules($quickJoinAddress: ID!) {\n quickJoinContract(id: $quickJoinAddress) {\n id\n accountRegistry\n hatsContract\n memberHatIds\n }\n }\n";
28
+ export declare const FETCH_QUICKJOIN_ACCOUNT = "\n query QuickJoinAccount($quickJoinAddress: ID!, $accountID: ID!) {\n quickJoinContract(id: $quickJoinAddress) {\n id\n accountRegistry\n }\n account(id: $accountID) {\n id\n username\n isDeleted\n registry {\n id\n }\n }\n }\n";
29
+ /** Indexed QuickJoin account registry pointer. */
30
+ export declare const FETCH_QUICKJOIN_MODULES = "\n query QuickJoinModules($quickJoinAddress: ID!) {\n quickJoinContract(id: $quickJoinAddress) {\n id\n accountRegistry\n }\n }\n";
54
31
  /**
55
32
  * The indexed account registry plus one account's username and profile
56
33
  * metadata, in one round-trip — everything `pop user update-profile` needs
@@ -71,8 +48,6 @@ export interface IndexedAccount {
71
48
  export interface IndexedQuickJoin {
72
49
  id: string;
73
50
  accountRegistry: string;
74
- hatsContract: string;
75
- memberHatIds: string[];
76
51
  }
77
52
  /**
78
53
  * True when an indexed account can stand in for a live
@@ -33,27 +33,7 @@ exports.GET_ACCOUNT_BY_USERNAME = `
33
33
  }
34
34
  }
35
35
  `;
36
- /**
37
- * One-round-trip org snapshot for `pop user whoami`: org name + role-hat
38
- * names, the org's QuickJoin module pointers, the caller's account
39
- * (username + which registry it lives on), their ERC-20 participation-token
40
- * balance, their org-user entity (membership, PT balance, hats worn), and
41
- * their pending participation-token requests. The `status: Pending`
42
- * filter is inlined (enum literal) to match FETCH_PENDING_TOKEN_REQUESTS
43
- * in queries/token.ts.
44
- *
45
- * Every field here was verified NON-NULL against the live Gnosis
46
- * (poa-gnosis-v-1) AND Arbitrum (poa-arb-v-1) deployments, and
47
- * quickJoinContract.{accountRegistry,hatsContract,memberHatIds} were
48
- * byte-compared against the matching eth_calls on both chains — including
49
- * the empty-array memberHatIds case, which is genuinely empty on-chain and
50
- * not an indexing gap.
51
- *
52
- * `account.registry` is carried so callers can prove the indexed account
53
- * belongs to the SAME registry the org's QuickJoin consults before trusting
54
- * the indexed username (a legacy org can point at a registry this subgraph
55
- * does not index).
56
- */
36
+ /** Historical account and token snapshot; current membership is projected from the authority index. */
57
37
  exports.FETCH_WHOAMI_ORG_DATA = `
58
38
  query WhoamiOrgData(
59
39
  $orgId: Bytes!
@@ -67,23 +47,10 @@ exports.FETCH_WHOAMI_ORG_DATA = `
67
47
  organization(id: $orgId) {
68
48
  id
69
49
  name
70
- roles(where: { isUserRole: true }) {
71
- hatId
72
- name
73
- # Hats Protocol's toggle flag. When it is false, Hats.isWearerOfHat returns
74
- # false for EVERY wearer regardless of token balance, and the tokens are NOT
75
- # burned — so User.currentHatIds still lists the hat. A membership answer
76
- # derived from currentHatIds alone must AND it with this flag.
77
- hat {
78
- active
79
- }
80
- }
81
50
  }
82
51
  quickJoinContract(id: $quickJoinAddress) {
83
52
  id
84
53
  accountRegistry
85
- hatsContract
86
- memberHatIds
87
54
  }
88
55
  account(id: $accountID) {
89
56
  id
@@ -145,8 +112,6 @@ exports.FETCH_QUICKJOIN_ACCOUNT = `
145
112
  quickJoinContract(id: $quickJoinAddress) {
146
113
  id
147
114
  accountRegistry
148
- hatsContract
149
- memberHatIds
150
115
  }
151
116
  account(id: $accountID) {
152
117
  id
@@ -158,17 +123,12 @@ exports.FETCH_QUICKJOIN_ACCOUNT = `
158
123
  }
159
124
  }
160
125
  `;
161
- /**
162
- * Just the QuickJoin module pointers — the addresses `pop user claim-hats`
163
- * needs before running its (deliberately on-chain) pre-flight probes.
164
- */
126
+ /** Indexed QuickJoin account registry pointer. */
165
127
  exports.FETCH_QUICKJOIN_MODULES = `
166
128
  query QuickJoinModules($quickJoinAddress: ID!) {
167
129
  quickJoinContract(id: $quickJoinAddress) {
168
130
  id
169
131
  accountRegistry
170
- hatsContract
171
- memberHatIds
172
132
  }
173
133
  }
174
134
  `;
@@ -34,14 +34,22 @@ export declare const FETCH_VOTING_CLASS_CONFIG = "\n query FetchVotingClassConf
34
34
  */
35
35
  export declare const FETCH_VOTING_CLASS_CONFIG_LEGACY = "\n query FetchVotingClassConfigLegacy($hybridVoting: ID!) {\n hybridVotingContract(id: $hybridVoting) {\n id\n thresholdPct\n quorum\n votingClasses(first: 1000) {\n version\n classIndex\n strategy\n slicePct\n quadratic\n minBalance\n asset\n hatIds\n isActive\n }\n }\n }\n";
36
36
  /** Class snapshot frozen for one proposal + threshold/quorum. Single tier. */
37
- export declare const FETCH_PROPOSAL_VOTING_CLASSES = "\n query FetchProposalVotingClasses($hybridVoting: ID!, $proposalId: BigInt!) {\n hybridVotingContract(id: $hybridVoting) {\n id\n thresholdPct\n quorum\n proposals(where: { proposalId: $proposalId }) {\n proposalId\n classesVersion\n }\n votingClasses(first: 1000) {\n version\n classIndex\n strategy\n slicePct\n quadratic\n minBalance\n asset\n hatIds\n isActive\n }\n }\n }\n";
37
+ export declare const FETCH_PROPOSAL_VOTING_CLASSES = "\n query FetchProposalVotingClasses($hybridVoting: ID!, $proposalId: BigInt!) {\n hybridVotingContract(id: $hybridVoting) {\n id\n thresholdPct\n quorum\n proposals(where: { proposalId: $proposalId }) {\n proposalId\n classesVersion\n isHatRestricted\n }\n votingClasses(first: 1000) {\n version\n classIndex\n strategy\n slicePct\n quadratic\n minBalance\n asset\n hatIds\n isActive\n }\n }\n }\n";
38
38
  /**
39
39
  * Everything `pop vote analyze` needs in ONE round-trip: the frozen class
40
40
  * snapshot, every ballot with its per-class raw power (Vote.classRawPowers is
41
41
  * the exact quantity the command used to reconstruct from VoteCast logs), and
42
42
  * the org's username map for display names.
43
43
  */
44
- export declare const FETCH_PROPOSAL_VOTE_ANALYSIS = "\n query FetchProposalVoteAnalysis($hybridVoting: ID!, $proposalId: BigInt!) {\n hybridVotingContract(id: $hybridVoting) {\n id\n organization {\n id\n users(first: 100) {\n address\n account { username }\n }\n }\n proposals(where: { proposalId: $proposalId }) {\n proposalId\n classesVersion\n votes(first: 1000, orderBy: votedAt, orderDirection: asc) {\n voter\n voterUsername\n optionIndexes\n optionWeights\n classRawPowers\n }\n }\n votingClasses(first: 1000) {\n version\n classIndex\n strategy\n slicePct\n quadratic\n minBalance\n asset\n hatIds\n isActive\n }\n }\n }\n";
44
+ export declare const FETCH_PROPOSAL_VOTE_ANALYSIS = "\n query FetchProposalVoteAnalysis($hybridVoting: ID!, $proposalId: BigInt!, $after: String = \"\") {\n hybridVotingContract(id: $hybridVoting) {\n id\n organization {\n id\n users(first: 100) {\n address\n account { username }\n }\n }\n proposals(where: { proposalId: $proposalId }) {\n proposalId\n numOptions\n classesVersion\n isHatRestricted\n votes(first: 1000, orderBy: id, orderDirection: asc, where: { id_gt: $after }) {\n id\n voter\n voterUsername\n optionIndexes\n optionWeights\n classRawPowers\n }\n }\n votingClasses(first: 1000) {\n version\n classIndex\n strategy\n slicePct\n quadratic\n minBalance\n asset\n hatIds\n isActive\n }\n }\n }\n";
45
+ export declare const FETCH_VOTING_CLASS_CONFIG_EXACT = "\n query FetchVotingClassConfigExact($hybridVoting: ID!) {\n hybridVotingContract(id: $hybridVoting) {\n id thresholdPct quorum classVersion classesChange {\n id numClasses\n votingClasses(first: 8, orderBy: classIndex, orderDirection: asc) {\n version\n classIndex\n strategy\n slicePct\n quadratic\n minBalance\n asset\n hatIds\n isActive\n }\n}\n }\n }\n";
46
+ export declare const FETCH_PROPOSAL_VOTING_CLASSES_EXACT = "\n query FetchProposalVotingClassesExact($hybridVoting: ID!, $proposalId: BigInt!) {\n hybridVotingContract(id: $hybridVoting) {\n id thresholdPct quorum\n proposals(where: { proposalId: $proposalId }, first: 1) {\n proposalId classesVersion isHatRestricted classesChange {\n id numClasses\n votingClasses(first: 8, orderBy: classIndex, orderDirection: asc) {\n version\n classIndex\n strategy\n slicePct\n quadratic\n minBalance\n asset\n hatIds\n isActive\n }\n}\n }\n }\n }\n";
47
+ export declare const FETCH_PROPOSAL_VOTE_ANALYSIS_EXACT: string;
48
+ /**
49
+ * Select one complete, unambiguous class emission. Restricted polls can use a
50
+ * synthetic V2 class which is still absent from the index; refuse that guess.
51
+ */
52
+ export declare function selectIndexedClassSnapshot(contract: any, proposalId?: number): SubgraphVotingClass[];
45
53
  /** One VotingClass row as returned by the subgraph (all scalars are strings/numbers). */
46
54
  export interface SubgraphVotingClass {
47
55
  version: string;
@@ -63,6 +71,19 @@ export interface SubgraphVotingClass {
63
71
  * version wins, which reproduces getClasses() but must NEVER be used to
64
72
  * reconstruct an old proposal's frozen snapshot.
65
73
  *
74
+ * `isActive` deliberately does NOT filter the version-pinned path. It means
75
+ * "belongs to the config that is live right now", so a proposal created under
76
+ * a since-replaced config has an entirely inactive snapshot — filtering on it
77
+ * first would drop every row and report "no answer" for exactly the proposals
78
+ * the snapshot machinery exists to serve. It is only used to pick a version
79
+ * when the caller has none, and to break the ambiguity below.
80
+ *
81
+ * `version` is the contract's `block.number`, not a per-setClasses id, so it is
82
+ * not unique: two setClasses share it in one block on Gnosis, and on Arbitrum
83
+ * `block.number` is the L1 block, which spans ~48 indexed L2 blocks. When two
84
+ * emissions share a version their classIndex values repeat; summing them would
85
+ * yield slice percentages over 100.
86
+ *
66
87
  * Returns [] when nothing matches, which callers treat as "subgraph can't
67
88
  * answer this" and fall back to the contract.
68
89
  */
@@ -26,7 +26,8 @@
26
26
  * falling back to the on-chain getProposalClasses call.
27
27
  */
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.FETCH_PROPOSAL_VOTE_ANALYSIS = exports.FETCH_PROPOSAL_VOTING_CLASSES = exports.FETCH_VOTING_CLASS_CONFIG_LEGACY = exports.FETCH_VOTING_CLASS_CONFIG = void 0;
29
+ exports.FETCH_PROPOSAL_VOTE_ANALYSIS_EXACT = exports.FETCH_PROPOSAL_VOTING_CLASSES_EXACT = exports.FETCH_VOTING_CLASS_CONFIG_EXACT = exports.FETCH_PROPOSAL_VOTE_ANALYSIS = exports.FETCH_PROPOSAL_VOTING_CLASSES = exports.FETCH_VOTING_CLASS_CONFIG_LEGACY = exports.FETCH_VOTING_CLASS_CONFIG = void 0;
30
+ exports.selectIndexedClassSnapshot = selectIndexedClassSnapshot;
30
31
  exports.selectClassSnapshot = selectClassSnapshot;
31
32
  /** Field set shared by every VotingClass selection. */
32
33
  const VOTING_CLASS_FIELDS = `
@@ -79,6 +80,7 @@ exports.FETCH_PROPOSAL_VOTING_CLASSES = `
79
80
  proposals(where: { proposalId: $proposalId }) {
80
81
  proposalId
81
82
  classesVersion
83
+ isHatRestricted
82
84
  }
83
85
  votingClasses(first: 1000) {${VOTING_CLASS_FIELDS}
84
86
  }
@@ -92,7 +94,7 @@ exports.FETCH_PROPOSAL_VOTING_CLASSES = `
92
94
  * the org's username map for display names.
93
95
  */
94
96
  exports.FETCH_PROPOSAL_VOTE_ANALYSIS = `
95
- query FetchProposalVoteAnalysis($hybridVoting: ID!, $proposalId: BigInt!) {
97
+ query FetchProposalVoteAnalysis($hybridVoting: ID!, $proposalId: BigInt!, $after: String = "") {
96
98
  hybridVotingContract(id: $hybridVoting) {
97
99
  id
98
100
  organization {
@@ -104,8 +106,11 @@ exports.FETCH_PROPOSAL_VOTE_ANALYSIS = `
104
106
  }
105
107
  proposals(where: { proposalId: $proposalId }) {
106
108
  proposalId
109
+ numOptions
107
110
  classesVersion
108
- votes(first: 1000, orderBy: votedAt, orderDirection: asc) {
111
+ isHatRestricted
112
+ votes(first: 1000, orderBy: id, orderDirection: asc, where: { id_gt: $after }) {
113
+ id
109
114
  voter
110
115
  voterUsername
111
116
  optionIndexes
@@ -118,6 +123,75 @@ exports.FETCH_PROPOSAL_VOTE_ANALYSIS = `
118
123
  }
119
124
  }
120
125
  `;
126
+ /** Exact per-emission joins are populated by current subgraphs on both supported chains. */
127
+ const CLASS_CHANGE_FIELDS = `classesChange {
128
+ id numClasses
129
+ votingClasses(first: 8, orderBy: classIndex, orderDirection: asc) {${VOTING_CLASS_FIELDS}
130
+ }
131
+ }`;
132
+ exports.FETCH_VOTING_CLASS_CONFIG_EXACT = `
133
+ query FetchVotingClassConfigExact($hybridVoting: ID!) {
134
+ hybridVotingContract(id: $hybridVoting) {
135
+ id thresholdPct quorum classVersion ${CLASS_CHANGE_FIELDS}
136
+ }
137
+ }
138
+ `;
139
+ exports.FETCH_PROPOSAL_VOTING_CLASSES_EXACT = `
140
+ query FetchProposalVotingClassesExact($hybridVoting: ID!, $proposalId: BigInt!) {
141
+ hybridVotingContract(id: $hybridVoting) {
142
+ id thresholdPct quorum
143
+ proposals(where: { proposalId: $proposalId }, first: 1) {
144
+ proposalId classesVersion isHatRestricted ${CLASS_CHANGE_FIELDS}
145
+ }
146
+ }
147
+ }
148
+ `;
149
+ exports.FETCH_PROPOSAL_VOTE_ANALYSIS_EXACT = exports.FETCH_PROPOSAL_VOTE_ANALYSIS
150
+ .replace('classesVersion', `classesVersion ${CLASS_CHANGE_FIELDS}`)
151
+ .replace(`votingClasses(first: 1000) {${VOTING_CLASS_FIELDS}
152
+ }`, '');
153
+ /**
154
+ * Select one complete, unambiguous class emission. Restricted polls can use a
155
+ * synthetic V2 class which is still absent from the index; refuse that guess.
156
+ */
157
+ function selectIndexedClassSnapshot(contract, proposalId) {
158
+ const holder = proposalId === undefined ? contract : contract?.proposals?.[0];
159
+ if (!holder)
160
+ return [];
161
+ if (proposalId !== undefined && holder.isHatRestricted !== false)
162
+ return [];
163
+ if (holder.classesChange !== undefined) {
164
+ const change = holder.classesChange;
165
+ const rows = change?.votingClasses ?? [];
166
+ if (!change || rows.length !== Number(change.numClasses) || rows.length === 0 || rows.length > 8)
167
+ return [];
168
+ const sorted = [...rows].sort((a, b) => Number(a.classIndex) - Number(b.classIndex));
169
+ if (sorted.some((r, i) => Number(r.classIndex) !== i))
170
+ return [];
171
+ return sorted;
172
+ }
173
+ const version = proposalId === undefined ? contract.classVersion : holder.classesVersion;
174
+ if (proposalId !== undefined && version == null)
175
+ return [];
176
+ // A full legacy history page could omit any requested emission or some of
177
+ // its classes. Never infer a complete snapshot from a truncated history.
178
+ if ((contract.votingClasses?.length ?? 0) >= 1000)
179
+ return [];
180
+ const rows = selectClassSnapshot(contract.votingClasses, version);
181
+ return rows.length > 0 && rows.length <= 8 && rows.every((r, i) => Number(r.classIndex) === i)
182
+ && rows.reduce((total, r) => total + Number(r.slicePct), 0) === 100 ? rows : [];
183
+ }
184
+ /** True when two rows claim the same classIndex, i.e. two configs are mixed together. */
185
+ function hasRepeatedClassIndex(rows) {
186
+ const seen = new Set();
187
+ for (const r of rows) {
188
+ const i = Number(r.classIndex);
189
+ if (seen.has(i))
190
+ return true;
191
+ seen.add(i);
192
+ }
193
+ return false;
194
+ }
121
195
  /**
122
196
  * Pick the class rows belonging to one config version and order them by
123
197
  * classIndex (the on-chain array order the whole slice/quorum math assumes).
@@ -127,23 +201,58 @@ exports.FETCH_PROPOSAL_VOTE_ANALYSIS = `
127
201
  * version wins, which reproduces getClasses() but must NEVER be used to
128
202
  * reconstruct an old proposal's frozen snapshot.
129
203
  *
204
+ * `isActive` deliberately does NOT filter the version-pinned path. It means
205
+ * "belongs to the config that is live right now", so a proposal created under
206
+ * a since-replaced config has an entirely inactive snapshot — filtering on it
207
+ * first would drop every row and report "no answer" for exactly the proposals
208
+ * the snapshot machinery exists to serve. It is only used to pick a version
209
+ * when the caller has none, and to break the ambiguity below.
210
+ *
211
+ * `version` is the contract's `block.number`, not a per-setClasses id, so it is
212
+ * not unique: two setClasses share it in one block on Gnosis, and on Arbitrum
213
+ * `block.number` is the L1 block, which spans ~48 indexed L2 blocks. When two
214
+ * emissions share a version their classIndex values repeat; summing them would
215
+ * yield slice percentages over 100.
216
+ *
130
217
  * Returns [] when nothing matches, which callers treat as "subgraph can't
131
218
  * answer this" and fall back to the contract.
132
219
  */
133
220
  function selectClassSnapshot(rows, version) {
134
- const active = (rows ?? []).filter(r => r && r.isActive !== false);
135
- if (active.length === 0)
136
- return [];
221
+ const all = (rows ?? []).filter(r => !!r);
137
222
  let target = version === null || version === undefined ? null : String(version);
138
223
  if (target === null) {
139
- target = active.reduce((max, r) => {
224
+ // Nothing pins the version, so the live rows are the only ones that identify
225
+ // the current config. Versions are block numbers and exceed 2^53 on some
226
+ // chains, so this comparison must not go through Number.
227
+ target = all
228
+ .filter(r => r.isActive !== false)
229
+ .reduce((max, r) => {
140
230
  const v = String(r.version);
141
231
  if (max === null)
142
232
  return v;
143
233
  return BigInt(v) > BigInt(max) ? v : max;
144
234
  }, null);
235
+ if (target === null)
236
+ return [];
237
+ }
238
+ let matched = all.filter(r => String(r.version) === target);
239
+ if (hasRepeatedClassIndex(matched)) {
240
+ // Two emissions share this version. The live one is still identifiable; a
241
+ // superseded one is not, without the per-emission pointer newer subgraphs
242
+ // expose. Blending them would report slices summing past 100, so say
243
+ // nothing and leave it to the caller's contract fallback. That fallback is
244
+ // not always free — `vote analyze` re-derives voters from a ~200k-block
245
+ // VoteCast window and throws for older proposals — but a wrong tally is
246
+ // worse than a loud one, and this path is unreachable until two setClasses
247
+ // land on one version.
248
+ // With a pinned version the live emission may be newer than the proposal.
249
+ // Only the exact classesChange pointer can disambiguate it.
250
+ if (version !== null && version !== undefined)
251
+ return [];
252
+ const live = matched.filter(r => r.isActive !== false);
253
+ if (live.length === 0 || hasRepeatedClassIndex(live))
254
+ return [];
255
+ matched = live;
145
256
  }
146
- return active
147
- .filter(r => String(r.version) === target)
148
- .sort((a, b) => Number(a.classIndex) - Number(b.classIndex));
257
+ return matched.sort((a, b) => Number(a.classIndex) - Number(b.classIndex));
149
258
  }
@@ -6,7 +6,6 @@
6
6
  export * as education from './education';
7
7
  export * as org from './org';
8
8
  export * as proposal from './proposal';
9
- export * as role from './role';
10
9
  export * as task from './task';
11
10
  export * as token from './token';
12
11
  export * as user from './user';
@@ -38,11 +38,10 @@ var __importStar = (this && this.__importStar) || (function () {
38
38
  };
39
39
  })();
40
40
  Object.defineProperty(exports, "__esModule", { value: true });
41
- exports.user = exports.token = exports.task = exports.role = exports.proposal = exports.org = exports.education = void 0;
41
+ exports.user = exports.token = exports.task = exports.proposal = exports.org = exports.education = void 0;
42
42
  exports.education = __importStar(require("./education"));
43
43
  exports.org = __importStar(require("./org"));
44
44
  exports.proposal = __importStar(require("./proposal"));
45
- exports.role = __importStar(require("./role"));
46
45
  exports.task = __importStar(require("./task"));
47
46
  exports.token = __importStar(require("./token"));
48
47
  exports.user = __importStar(require("./user"));
package/dist/perms.d.ts CHANGED
@@ -30,18 +30,3 @@ export declare function formatMask(mask: number): string;
30
30
  * Unknown bits render as 'unknown permission (bitN)'.
31
31
  */
32
32
  export declare function describeMask(mask: number): string[];
33
- /**
34
- * EligibilityModule vouch-config flag bits (EligibilityModule.sol:156-157).
35
- * Packed into the `flags` byte of the VouchConfig tuple returned by getVouchConfig.
36
- */
37
- export declare const VOUCH_FLAG_ENABLED = 1;
38
- export declare const VOUCH_FLAG_COMBINE_HIERARCHY = 2;
39
- /**
40
- * Would enabling vouching and default-eligibility on the same hat conflict?
41
- *
42
- * Audit M-03 made these mutually exclusive in BOTH directions: a hat that everyone is eligible
43
- * for by default makes a vouch quorum a no-op, so the contract reverts
44
- * DefaultEligibilityConflictsWithVouch. The guard only fires when vouching is enabled AND
45
- * combineWithHierarchy is set — vouching alone, or without combine, is fine.
46
- */
47
- export declare function vouchConflictsWithDefaultEligibility(vouchFlags: number, vouchQuorum: number, defaultEligible: boolean): boolean;