@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
package/dist/tx/task.d.ts CHANGED
@@ -5,8 +5,7 @@
5
5
  * resolved addresses + prepared values and return a TxIntent. ALL argument
6
6
  * encoding lives here, byte-for-byte as the CLI encodes it: stringToBytes
7
7
  * titles, ipfsCidToBytes32 hashes, parseUnits amounts (18d PT payouts, token
8
- * registry decimals for bounties), and the v6/legacy createTask arity switch
9
- * via TaskManagerFeatures + LEGACY_TM_FRAGMENTS.
8
+ * registry decimals for bounties), using the authority-only nine-argument createTask signature.
10
9
  *
11
10
  * Level 2 — resolved builders (async, `<action>Intent(ctx, params)`). They
12
11
  * resolve the org's TaskManager via reads/resolve, replicate the CLI's
@@ -67,7 +66,7 @@ export interface CreateTaskArgs {
67
66
  completionWindow?: number;
68
67
  /**
69
68
  * Feature probe result: `deadlines` picks the 9-arg v6 createTask; without
70
- * it the pre-v6 7-arg signature is encoded via LEGACY_TM_FRAGMENTS (the
69
+ * it older unsupported implementations are rejected (the
71
70
  * synced ABI no longer contains it).
72
71
  */
73
72
  features: Pick<TaskManagerFeatures, 'deadlines'>;
@@ -77,7 +76,7 @@ export interface CreateTaskArgs {
77
76
  * Port of `pop task create` — src/commands/task/create.ts (createTask send).
78
77
  * v6 9-arg: [payoutWei, titleBytes, metadataHash, pid, bountyToken,
79
78
  * bountyPayoutWei, requiresApplication, absoluteDeadline, completionWindow];
80
- * legacy 7-arg drops the two deadline words and uses LEGACY_TM_FRAGMENTS.
79
+ * The removed seven-argument form is never encoded.
81
80
  */
82
81
  export declare function buildCreateTask(a: CreateTaskArgs): TxIntent;
83
82
  /** One row of a v6 createTasksBatch call (prepared values; NO pid inside). */
@@ -204,30 +203,29 @@ export interface UpdateTaskMetadataArgs extends TaskIdArgs {
204
203
  */
205
204
  export declare function buildUpdateTaskMetadata(a: UpdateTaskMetadataArgs): TxIntent;
206
205
  export interface SetProjectRolePermArgs {
207
- taskManagerAddress: string;
206
+ authorityAddress: string;
208
207
  /** Resolved bytes32 project id. */
209
208
  projectId: string;
210
209
  hatId: ethers.BigNumberish;
211
210
  /** TaskPerm bitmask (uint8). */
212
211
  mask: number;
213
212
  orgId?: string;
213
+ inheritGlobal?: boolean;
214
214
  }
215
215
  /**
216
- * Port of `pop task perms set` — src/commands/task/perms.ts:309
217
- * (setProjectRolePerm send; creator-hat/executor gate stays on-chain).
216
+ * Low-level executor-only authority write. Normal users use setProjectRolePermIntent to propose it through governance.
218
217
  */
219
218
  export declare function buildSetProjectRolePerm(a: SetProjectRolePermArgs): TxIntent;
220
219
  /**
221
- * The executor-gated setConfig(ROLE_PERM, abi.encode(uint256 hatId, uint8
222
- * mask)) call `pop task perms propose-global` wraps in a proposal —
220
+ * The executor-gated MembershipAuthority.setPerm call `pop task perms propose-global` wraps in a proposal —
223
221
  * src/commands/task/perms.ts:418. The CLI encodes via an inline
224
222
  * `setConfig(uint8,bytes)` interface; the synced TaskManagerNew ABI carries
225
223
  * the same signature, so the calldata is byte-identical.
226
224
  */
227
- export declare function buildSetGlobalRolePermCall(taskManagerAddress: string, hatId: ethers.BigNumberish, mask: number): ExecutionCall;
225
+ export declare function buildSetGlobalRolePermCall(authorityAddress: string, hatId: ethers.BigNumberish, mask: number): ExecutionCall;
228
226
  export interface ProposeGlobalRolePermArgs {
229
227
  hybridVotingAddress: string;
230
- taskManagerAddress: string;
228
+ authorityAddress: string;
231
229
  hatId: ethers.BigNumberish;
232
230
  mask: number;
233
231
  durationMinutes: ethers.BigNumberish;
@@ -429,19 +427,13 @@ export interface EditTaskMetadataParams extends TaskActionParams {
429
427
  export declare function editTaskMetadataIntent(ctx: PopContext, p: EditTaskMetadataParams): Promise<TxIntent | null>;
430
428
  export interface SetProjectRolePermParams {
431
429
  org: string;
432
- /** Project bytes32 id or title (resolved via the perms tiers, like the CLI). */
433
430
  project: string;
434
- /** Hat id (decimal or 0x hex). */
435
431
  hat: string | number | ethers.BigNumber;
436
- /** Comma-separated permission list ('create,claim' / 'none') or a raw mask. */
437
432
  perms: string | number;
433
+ duration?: number;
434
+ inheritGlobal?: boolean;
438
435
  }
439
- /**
440
- * Port of `pop task perms set` — src/commands/task/perms.ts:309. Resolves the
441
- * project by hex or title (PERMS_QUERY_FULL/LEGACY tiers), parses the perm
442
- * list into a mask, and builds setProjectRolePerm. The creator-hat/executor
443
- * gate stays on-chain (masks are not readable per-wearer).
444
- */
436
+ /** Resolve project and authority, then propose the executor-only permission write through governance. */
445
437
  export declare function setProjectRolePermIntent(ctx: PopContext, p: SetProjectRolePermParams): Promise<TxIntent>;
446
438
  export interface ProposeGlobalRolePermParams {
447
439
  org: string;
@@ -452,10 +444,7 @@ export interface ProposeGlobalRolePermParams {
452
444
  }
453
445
  /**
454
446
  * Port of `pop task perms propose-global` — src/commands/task/perms.ts:400.
455
- * setConfig(ROLE_PERM) is executor-only, so the change ships as a HybridVoting
456
- * proposal whose option-0 batch targets the TaskManager. Pins the proposal
457
- * metadata {description, optionNames, createdAt} (exact key order), then
458
- * delegates to buildProposeGlobalRolePerm.
447
+ * MembershipAuthority.setPerm is executor-only; option 0 applies the change through the org executor.
459
448
  */
460
449
  export declare function proposeGlobalRolePermIntent(ctx: PopContext, p: ProposeGlobalRolePermParams): Promise<TxIntent>;
461
450
  export interface SetFoldersParams {
package/dist/tx/task.js CHANGED
@@ -6,8 +6,7 @@
6
6
  * resolved addresses + prepared values and return a TxIntent. ALL argument
7
7
  * encoding lives here, byte-for-byte as the CLI encodes it: stringToBytes
8
8
  * titles, ipfsCidToBytes32 hashes, parseUnits amounts (18d PT payouts, token
9
- * registry decimals for bounties), and the v6/legacy createTask arity switch
10
- * via TaskManagerFeatures + LEGACY_TM_FRAGMENTS.
9
+ * registry decimals for bounties), using the authority-only nine-argument createTask signature.
11
10
  *
12
11
  * Level 2 — resolved builders (async, `<action>Intent(ctx, params)`). They
13
12
  * resolve the org's TaskManager via reads/resolve, replicate the CLI's
@@ -55,6 +54,7 @@ exports.setProjectRolePermIntent = setProjectRolePermIntent;
55
54
  exports.proposeGlobalRolePermIntent = proposeGlobalRolePermIntent;
56
55
  exports.setFoldersIntent = setFoldersIntent;
57
56
  const ethers_1 = require("ethers");
57
+ const authority_1 = require("./authority");
58
58
  const governance_1 = require("./governance");
59
59
  const contracts_1 = require("../contracts");
60
60
  const encoding_1 = require("../encoding");
@@ -71,7 +71,6 @@ const org_1 = require("../graph/documents/org");
71
71
  const task_1 = require("../graph/documents/task");
72
72
  const task_2 = require("../reads/task");
73
73
  const task_3 = require("../metadata/task");
74
- const proposal_1 = require("../metadata/proposal");
75
74
  const task_lens_1 = require("../task-lens");
76
75
  // ─────────────────────────── shared encoding helpers ───────────────────────────
77
76
  /** TaskManager.ConfigKey.ROLE_PERM — verified enum index (src/commands/task/perms.ts:49). */
@@ -154,28 +153,27 @@ function parseHatId(input) {
154
153
  * Port of `pop task create` — src/commands/task/create.ts (createTask send).
155
154
  * v6 9-arg: [payoutWei, titleBytes, metadataHash, pid, bountyToken,
156
155
  * bountyPayoutWei, requiresApplication, absoluteDeadline, completionWindow];
157
- * legacy 7-arg drops the two deadline words and uses LEGACY_TM_FRAGMENTS.
156
+ * The removed seven-argument form is never encoded.
158
157
  */
159
158
  function buildCreateTask(a) {
159
+ if (!a.features.deadlines)
160
+ throw new Error('Unsupported TaskManager: the authority CLI requires the current task creation signature.');
160
161
  const payoutWei = ethers_1.ethers.utils.parseUnits(a.payout.toString(), 18);
161
162
  const titleBytes = (0, encoding_1.stringToBytes)(a.title);
162
163
  const metadataHash = (0, encoding_1.ipfsCidToBytes32)(a.metadataHash);
163
164
  const bountyToken = a.bountyToken || ethers_1.ethers.constants.AddressZero;
164
165
  const bountyPayoutWei = computeBountyPayoutWei(bountyToken, a.bountyAmount);
165
166
  const requiresApp = a.requiresApplication || false;
166
- const v6 = a.features.deadlines;
167
167
  return {
168
168
  to: a.taskManagerAddress,
169
- abi: v6 ? (0, contracts_1.getAbi)('TaskManagerNew') : version_1.LEGACY_TM_FRAGMENTS,
169
+ abi: (0, contracts_1.getAbi)('TaskManagerNew'),
170
170
  method: 'createTask',
171
- args: v6
172
- ? [payoutWei, titleBytes, metadataHash, a.projectId, bountyToken, bountyPayoutWei, requiresApp, a.absoluteDeadline ?? 0, a.completionWindow ?? 0]
173
- : [payoutWei, titleBytes, metadataHash, a.projectId, bountyToken, bountyPayoutWei, requiresApp],
171
+ args: [payoutWei, titleBytes, metadataHash, a.projectId, bountyToken, bountyPayoutWei, requiresApp, a.absoluteDeadline ?? 0, a.completionWindow ?? 0],
174
172
  meta: {
175
173
  domain: 'task',
176
174
  action: 'create',
177
175
  orgId: a.orgId,
178
- summary: { name: a.title, projectId: a.projectId, payout: String(a.payout), signature: v6 ? 'v6' : 'legacy7' },
176
+ summary: { name: a.title, projectId: a.projectId, payout: String(a.payout), signature: 'authority' },
179
177
  },
180
178
  };
181
179
  }
@@ -368,16 +366,15 @@ function buildUpdateTaskMetadata(a) {
368
366
  };
369
367
  }
370
368
  /**
371
- * Port of `pop task perms set` — src/commands/task/perms.ts:309
372
- * (setProjectRolePerm send; creator-hat/executor gate stays on-chain).
369
+ * Low-level executor-only authority write. Normal users use setProjectRolePermIntent to propose it through governance.
373
370
  */
374
371
  function buildSetProjectRolePerm(a) {
375
372
  const hatId = ethers_1.ethers.BigNumber.from(a.hatId);
376
373
  return {
377
- to: a.taskManagerAddress,
378
- abi: (0, contracts_1.getAbi)('TaskManagerNew'),
379
- method: 'setProjectRolePerm',
380
- args: [a.projectId, hatId, a.mask],
374
+ to: a.authorityAddress,
375
+ abi: (0, contracts_1.getAbi)('MembershipAuthority'),
376
+ method: 'setPerm',
377
+ args: [hatId, authority_1.AUTHORITY_KEYS.TM_PERMS, (0, authority_1.projectContext)(a.projectId), (0, authority_1.permissionWord)(a.mask, a.inheritGlobal)],
381
378
  meta: {
382
379
  domain: 'task',
383
380
  action: 'perms-set',
@@ -387,15 +384,13 @@ function buildSetProjectRolePerm(a) {
387
384
  };
388
385
  }
389
386
  /**
390
- * The executor-gated setConfig(ROLE_PERM, abi.encode(uint256 hatId, uint8
391
- * mask)) call `pop task perms propose-global` wraps in a proposal —
387
+ * The executor-gated MembershipAuthority.setPerm call `pop task perms propose-global` wraps in a proposal —
392
388
  * src/commands/task/perms.ts:418. The CLI encodes via an inline
393
389
  * `setConfig(uint8,bytes)` interface; the synced TaskManagerNew ABI carries
394
390
  * the same signature, so the calldata is byte-identical.
395
391
  */
396
- function buildSetGlobalRolePermCall(taskManagerAddress, hatId, mask) {
397
- const encodedValue = ethers_1.ethers.utils.defaultAbiCoder.encode(['uint256', 'uint8'], [ethers_1.ethers.BigNumber.from(hatId), mask]);
398
- return (0, governance_1.encodeExecutorCall)('TaskManagerNew', taskManagerAddress, 'setConfig', [exports.CONFIG_KEY_ROLE_PERM, encodedValue]);
392
+ function buildSetGlobalRolePermCall(authorityAddress, hatId, mask) {
393
+ return (0, governance_1.encodeExecutorCall)('MembershipAuthority', authorityAddress, 'setPerm', [hatId, authority_1.AUTHORITY_KEYS.TM_PERMS, ethers_1.ethers.constants.HashZero, (0, authority_1.permissionWord)(mask)]);
399
394
  }
400
395
  /**
401
396
  * Port of `pop task perms propose-global` — src/commands/task/perms.ts:400.
@@ -406,7 +401,7 @@ function buildSetGlobalRolePermCall(taskManagerAddress, hatId, mask) {
406
401
  function buildProposeGlobalRolePerm(a) {
407
402
  const hatId = ethers_1.ethers.BigNumber.from(a.hatId);
408
403
  const permsLabel = (0, perms_1.formatMask)(a.mask);
409
- const title = `Set global task permissions for hat ${hatId.toString()} to ${permsLabel}`;
404
+ const title = `Set global task permissions for subject ${hatId.toString()} to ${permsLabel}`;
410
405
  return (0, governance_1.buildGovernanceProposal)({
411
406
  votingAddress: a.hybridVotingAddress,
412
407
  votingAbiName: 'HybridVotingNew',
@@ -415,7 +410,7 @@ function buildProposeGlobalRolePerm(a) {
415
410
  durationMinutes: a.durationMinutes,
416
411
  numOptions: 2,
417
412
  batches: [
418
- [buildSetGlobalRolePermCall(a.taskManagerAddress, hatId, a.mask)], // option 0: apply
413
+ [buildSetGlobalRolePermCall(a.authorityAddress, hatId, a.mask)], // option 0: apply
419
414
  [], // option 1: keep current
420
415
  ],
421
416
  hatIds: [],
@@ -547,7 +542,7 @@ async function createTaskIntent(ctx, p) {
547
542
  const { orgId, taskManagerAddress } = await resolveTaskManager(ctx, p.org);
548
543
  // Feature-gate: pre-v6 TaskManagers only expose the 7-arg createTask.
549
544
  const features = await requireFeatures(ctx, taskManagerAddress, orgId, p.features, 'createTask');
550
- if (!features.deadlines && deadlineFlagsSet) {
545
+ if (!features.deadlines) {
551
546
  throw new errors_1.CliError((0, version_1.featureUnavailable)('task deadlines', 'TaskManager v6', 'Re-run without --deadline/--completion-window, or upgrade the org TaskManager beacon.'), exit_codes_1.EXIT.PRECONDITION);
552
547
  }
553
548
  const pid = await resolveCreateProjectPid(ctx, orgId, p.project);
@@ -675,7 +670,7 @@ async function createTasksBatchIntents(ctx, p) {
675
670
  const cid = await (0, ipfs_1.pinJson)((0, task_3.serializeTaskMetadata)(metadata), ctx.ipfs);
676
671
  pinned.push({ row, cid, metadata });
677
672
  }
678
- if (features.batchCreate) {
673
+ {
679
674
  const intent = buildCreateTasksBatch({
680
675
  taskManagerAddress,
681
676
  projectId: pid,
@@ -694,23 +689,6 @@ async function createTasksBatchIntents(ctx, p) {
694
689
  intent.meta.ipfs = { cid: pinned[0].cid, metadata: pinned.map((x) => x.metadata) };
695
690
  return [intent];
696
691
  }
697
- // Legacy pre-v6 org: per-task 7-arg createTask intents (sequential sends).
698
- return pinned.map(({ row, cid, metadata }) => {
699
- const intent = buildCreateTask({
700
- taskManagerAddress,
701
- payout: row.payout,
702
- title: row.name,
703
- metadataHash: cid,
704
- projectId: pid,
705
- bountyToken: row.bountyToken,
706
- bountyAmount: row.bountyAmount,
707
- requiresApplication: row.requiresApplication,
708
- features: { deadlines: false },
709
- orgId,
710
- });
711
- intent.meta.ipfs = { cid, metadata };
712
- return intent;
713
- });
714
692
  }
715
693
  /** Port of `pop task claim` — src/commands/task/claim.ts. */
716
694
  async function claimTaskIntent(ctx, p) {
@@ -741,14 +719,13 @@ async function unclaimTaskIntent(ctx, p) {
741
719
  */
742
720
  async function submitTaskIntent(ctx, p) {
743
721
  const { orgId, taskManagerAddress } = await resolveTaskManager(ctx, p.org);
744
- const parsedTaskId = (0, encoding_1.parseTaskId)(p.task);
722
+ const parsedTaskId = (0, task_2.taskEntityId)(taskManagerAddress, p.task).split('-')[1];
745
723
  // Fetch existing metadata so the submission preserves it. Match on the
746
724
  // PARSED numeric id, fall back to IPFS before giving up — same ladder as
747
725
  // task update / edit-meta.
748
726
  let subgraphTask = null;
749
727
  try {
750
- const taskData = await ctx.client.query(task_1.FETCH_PROJECTS_DATA, { orgId }, ctx.chainId);
751
- subgraphTask = (0, task_2.findSubgraphTask)(taskData.organization?.taskManager?.projects || [], parsedTaskId);
728
+ subgraphTask = (await (0, task_2.fetchTaskData)(ctx.client, taskManagerAddress, p.task, ctx.chainId)).task;
752
729
  }
753
730
  catch { /* handled below */ }
754
731
  let existingMeta = subgraphTask?.metadata || null;
@@ -770,7 +747,7 @@ async function submitTaskIntent(ctx, p) {
770
747
  description: existingMeta?.description || '',
771
748
  location: existingMeta?.location || '',
772
749
  difficulty: existingMeta?.difficulty || '',
773
- estHours: existingMeta?.estimatedHours ? parseFloat(existingMeta.estimatedHours) : 0,
750
+ estHours: Number(existingMeta?.estimatedHours ?? existingMeta?.estHours ?? 0),
774
751
  submission: p.submission,
775
752
  // The subgraph re-points task.metadata at THIS submission JSON, so a
776
753
  // dueDate omitted here is gone for good. Appended last, only when set.
@@ -874,7 +851,7 @@ async function updateTaskIntent(ctx, p) {
874
851
  : undefined;
875
852
  // 1. Resolve org, gate on the v6 signature.
876
853
  const { orgId, taskManagerAddress } = await resolveTaskManager(ctx, p.org);
877
- const taskId = (0, encoding_1.parseTaskId)(p.task);
854
+ const taskId = (0, task_2.taskEntityId)(taskManagerAddress, p.task).split('-')[1];
878
855
  const features = await requireFeatures(ctx, taskManagerAddress, orgId, p.features, 'updateTask');
879
856
  if (!features.deadlines) {
880
857
  // Pre-v6 implementations expose a 6-field updateTask that no longer
@@ -893,8 +870,7 @@ async function updateTaskIntent(ctx, p) {
893
870
  const metadataChanging = p.name !== undefined || p.description !== undefined;
894
871
  let subgraphTask = null;
895
872
  try {
896
- const result = await ctx.client.query(task_1.FETCH_PROJECTS_DATA, { orgId }, ctx.chainId);
897
- subgraphTask = (0, task_2.findSubgraphTask)(result.organization?.taskManager?.projects || [], taskId);
873
+ subgraphTask = (await (0, task_2.fetchTaskData)(ctx.client, taskManagerAddress, p.task, ctx.chainId)).task;
898
874
  }
899
875
  catch { /* handled below based on what the merge needs */ }
900
876
  let metadata = subgraphTask?.metadata || null;
@@ -1007,7 +983,7 @@ async function editTaskMetadataIntent(ctx, p) {
1007
983
  throw new errors_1.CliError('Nothing to edit — pass --name and/or --description.', exit_codes_1.EXIT.USAGE);
1008
984
  }
1009
985
  const { orgId, taskManagerAddress } = await resolveTaskManager(ctx, p.org);
1010
- const taskId = (0, encoding_1.parseTaskId)(p.task);
986
+ const taskId = (0, task_2.taskEntityId)(taskManagerAddress, p.task).split('-')[1];
1011
987
  // Feature-gate: updateTaskMetadata shipped with TaskManager v5.
1012
988
  const features = await requireFeatures(ctx, taskManagerAddress, orgId, p.features, 'updateTaskMetadata');
1013
989
  if (!features.editMeta) {
@@ -1024,8 +1000,7 @@ async function editTaskMetadataIntent(ctx, p) {
1024
1000
  // READ current metadata: subgraph first, IPFS pointer as fallback.
1025
1001
  let subgraphTask = null;
1026
1002
  try {
1027
- const result = await ctx.client.query(task_1.FETCH_PROJECTS_DATA, { orgId }, ctx.chainId);
1028
- subgraphTask = (0, task_2.findSubgraphTask)(result.organization?.taskManager?.projects || [], taskId);
1003
+ subgraphTask = (await (0, task_2.fetchTaskData)(ctx.client, taskManagerAddress, p.task, ctx.chainId)).task;
1029
1004
  }
1030
1005
  catch { /* handled below */ }
1031
1006
  let metadata = subgraphTask?.metadata || null;
@@ -1064,16 +1039,13 @@ async function editTaskMetadataIntent(ctx, p) {
1064
1039
  intent.meta.ipfs = { cid, metadata: metadataJson };
1065
1040
  return intent;
1066
1041
  }
1067
- /**
1068
- * Port of `pop task perms set` — src/commands/task/perms.ts:309. Resolves the
1069
- * project by hex or title (PERMS_QUERY_FULL/LEGACY tiers), parses the perm
1070
- * list into a mask, and builds setProjectRolePerm. The creator-hat/executor
1071
- * gate stays on-chain (masks are not readable per-wearer).
1072
- */
1042
+ /** Resolve project and authority, then propose the executor-only permission write through governance. */
1073
1043
  async function setProjectRolePermIntent(ctx, p) {
1074
1044
  const mask = typeof p.perms === 'number' ? p.perms : (0, perms_1.parsePermList)(p.perms);
1075
1045
  const hatId = parseHatId(p.hat);
1076
- const { orgId, taskManagerAddress } = await resolveTaskManager(ctx, p.org);
1046
+ const modules = await (0, resolve_1.resolveOrgModules)(ctx.client, p.org, ctx.chainId);
1047
+ const orgId = modules.orgId;
1048
+ const authorityAddress = (0, resolve_1.requireModule)(modules, 'membershipAuthorityAddress');
1077
1049
  let pid;
1078
1050
  if (p.project.startsWith('0x') && p.project.length === 66) {
1079
1051
  pid = p.project;
@@ -1082,43 +1054,31 @@ async function setProjectRolePermIntent(ctx, p) {
1082
1054
  const { data } = await ctx.client.queryWithFieldFallback((0, task_2.taskPermsTiers)(orgId), { chainId: ctx.chainId });
1083
1055
  pid = (0, task_2.resolveProjectFromList)(data.organization?.taskManager?.projects || [], p.project).pid;
1084
1056
  }
1085
- return buildSetProjectRolePerm({ taskManagerAddress, projectId: pid, hatId, mask, orgId });
1057
+ const action = buildSetProjectRolePerm({ authorityAddress, projectId: pid, hatId, mask, orgId, inheritGlobal: p.inheritGlobal });
1058
+ return (0, governance_1.buildGovernanceProposal)({
1059
+ votingAddress: (0, resolve_1.requireModule)(modules, 'hybridVotingAddress'), votingAbiName: 'HybridVotingNew',
1060
+ title: `Set project task permissions for subject ${hatId.toString()}`, descriptionHash: ethers_1.ethers.constants.HashZero,
1061
+ durationMinutes: p.duration ?? 60, numOptions: 2, hatIds: [], orgId,
1062
+ batches: [[{ target: authorityAddress, value: 0, calldata: new ethers_1.ethers.utils.Interface(action.abi).encodeFunctionData(action.method, action.args) }], []],
1063
+ domain: 'task', action: 'perms-set', summary: action.meta.summary,
1064
+ });
1086
1065
  }
1087
1066
  /**
1088
1067
  * Port of `pop task perms propose-global` — src/commands/task/perms.ts:400.
1089
- * setConfig(ROLE_PERM) is executor-only, so the change ships as a HybridVoting
1090
- * proposal whose option-0 batch targets the TaskManager. Pins the proposal
1091
- * metadata {description, optionNames, createdAt} (exact key order), then
1092
- * delegates to buildProposeGlobalRolePerm.
1068
+ * MembershipAuthority.setPerm is executor-only; option 0 applies the change through the org executor.
1093
1069
  */
1094
1070
  async function proposeGlobalRolePermIntent(ctx, p) {
1095
1071
  const mask = typeof p.perms === 'number' ? p.perms : (0, perms_1.parsePermList)(p.perms);
1096
1072
  const hatId = parseHatId(p.hat);
1097
1073
  const duration = p.duration ?? 60;
1098
- const { orgId, taskManagerAddress, hybridVotingAddress } = await resolveTaskManager(ctx, p.org);
1074
+ const modules = await (0, resolve_1.resolveOrgModules)(ctx.client, p.org, ctx.chainId);
1075
+ const { orgId, hybridVotingAddress } = modules;
1076
+ const authorityAddress = (0, resolve_1.requireModule)(modules, 'membershipAuthorityAddress');
1099
1077
  if (!hybridVotingAddress) {
1100
1078
  throw new errors_1.CliError('HybridVoting not deployed for this org — cannot create a governance proposal.', exit_codes_1.EXIT.PRECONDITION);
1101
1079
  }
1102
- const permsLabel = (0, perms_1.formatMask)(mask);
1103
- const title = `Set global task permissions for hat ${hatId.toString()} to ${permsLabel}`;
1104
- // Proposal metadata — key order {description, optionNames, createdAt} is a
1105
- // protocol contract (same shape every governance wrap pins).
1106
- const metadata = (0, proposal_1.buildProposalMetadata)({
1107
- description: `Set the GLOBAL TaskPerm mask for hat ${hatId.toString()} to ${mask} (${permsLabel}) via TaskManager.setConfig(ROLE_PERM). ${(0, perms_1.describeMask)(mask).join('; ') || 'Revokes all global task permissions for this hat.'}`,
1108
- optionNames: [title, 'Keep current permissions'],
1109
- });
1110
- const cid = await (0, ipfs_1.pinJson)((0, proposal_1.serializeProposalMetadata)(metadata), ctx.ipfs);
1111
- const intent = buildProposeGlobalRolePerm({
1112
- hybridVotingAddress,
1113
- taskManagerAddress,
1114
- hatId,
1115
- mask,
1116
- durationMinutes: duration,
1117
- descriptionHash: cid,
1118
- orgId,
1119
- });
1120
- intent.meta.ipfs = { cid, metadata };
1121
- return intent;
1080
+ return buildProposeGlobalRolePerm({ hybridVotingAddress, authorityAddress, hatId, mask,
1081
+ durationMinutes: duration, descriptionHash: ethers_1.ethers.constants.HashZero, orgId });
1122
1082
  }
1123
1083
  /**
1124
1084
  * Port of `pop task folders set` — src/commands/task/folders.ts:286
package/dist/tx/user.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * User write builders — UniversalAccountRegistry (registerAccount /
3
3
  * changeUsername / setProfileMetadata) and QuickJoinNew (quickJoinWithUser /
4
- * claimHatsWithUser).
4
+ * authority autojoin).
5
5
  *
6
6
  * Level 1: pure, sync builders taking resolved addresses + prepared values.
7
7
  * Level 2: async `<action>Intent(ctx, params)` builders that resolve the
@@ -17,21 +17,11 @@
17
17
  * NOT ported (CLI-side revert prediction / flow UX): checkUsernameFree,
18
18
  * AccountUnknown prediction, the live re-read of quickJoin.accountRegistry()
19
19
  * before a 2-tx join (a write-target pointer that updateAddresses can
20
- * re-point — see src/commands/user/join.ts), and the claim-hats Multicall3
21
- * probes (NoUsername / MAX_HATS_PER_MINT / HatOpenlyClaimable sentinel).
20
+ * re-point — see src/commands/user/join.ts).
22
21
  */
23
- import { ethers } from 'ethers';
24
22
  import type { TxIntent } from './intent';
25
23
  import type { PopContext } from '../context';
26
24
  import { UserProfileUpdates } from '../metadata/user';
27
- /**
28
- * Parse a comma-separated hat-ID list into BigNumbers. Accepts decimal and
29
- * 0x-hex forms. Hats Protocol IDs are uint256 — far beyond 2^53 — so
30
- * parseInt/Number would silently corrupt them.
31
- * Port of parseHatIds in `pop user claim-hats` —
32
- * src/commands/user/claim-hats.ts (same messages and exit codes).
33
- */
34
- export declare function parseHatIds(input: string): ethers.BigNumber[];
35
25
  export interface RegisterAccountArgs {
36
26
  /** UniversalAccountRegistry address (home chain unless overridden). */
37
27
  registryAddress: string;
@@ -86,20 +76,6 @@ export interface QuickJoinWithUserArgs {
86
76
  * QuickJoin consults (register first via buildRegisterAccount when needed).
87
77
  */
88
78
  export declare function buildQuickJoinWithUser(a: QuickJoinWithUserArgs): TxIntent;
89
- export interface ClaimHatsWithUserArgs {
90
- quickJoinAddress: string;
91
- /** uint256 hat IDs — parse strings with parseHatIds, never parseInt. */
92
- hatIds: ethers.BigNumber[];
93
- orgId?: string;
94
- }
95
- /**
96
- * Port of `pop user claim-hats` — src/commands/user/claim-hats.ts.
97
- * QuickJoinNew.claimHatsWithUser(uint256[] claimHatIds). The caller must
98
- * already have a username (reverts NoUsername); since audit H-03 QuickJoin
99
- * refuses openly-claimable hats (reverts HatOpenlyClaimable), and the
100
- * executor bounds the batch at MAX_HATS_PER_MINT.
101
- */
102
- export declare function buildClaimHatsWithUser(a: ClaimHatsWithUserArgs): TxIntent;
103
79
  export interface RegisterAccountParams {
104
80
  username: string;
105
81
  /** Registry chain. Defaults to HOME_CHAIN_ID (Arbitrum) — NOT ctx.chainId. */
@@ -161,17 +137,3 @@ export interface QuickJoinParams {
161
137
  * against THAT registry first.
162
138
  */
163
139
  export declare function quickJoinWithUserIntent(ctx: PopContext, params: QuickJoinParams): Promise<TxIntent>;
164
- export interface ClaimHatsParams {
165
- /** Org name or hex ID. */
166
- org: string;
167
- /** Comma-separated hat-ID string (as the CLI's --hats), or pre-parsed IDs. */
168
- hats: string | Array<string | ethers.BigNumberish>;
169
- }
170
- /**
171
- * Resolved builder for `pop user claim-hats` —
172
- * src/commands/user/claim-hats.ts. Parses hat IDs with BigNumber (uint256 —
173
- * never parseInt), resolves the org's QuickJoin via the subgraph, and builds
174
- * the claimHatsWithUser intent. The CLI's Multicall3 preflight (NoUsername /
175
- * batch cap / open-hat sentinel probes) stays in the CLI.
176
- */
177
- export declare function claimHatsWithUserIntent(ctx: PopContext, params: ClaimHatsParams): Promise<TxIntent>;
package/dist/tx/user.js CHANGED
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * User write builders — UniversalAccountRegistry (registerAccount /
4
4
  * changeUsername / setProfileMetadata) and QuickJoinNew (quickJoinWithUser /
5
- * claimHatsWithUser).
5
+ * authority autojoin).
6
6
  *
7
7
  * Level 1: pure, sync builders taking resolved addresses + prepared values.
8
8
  * Level 2: async `<action>Intent(ctx, params)` builders that resolve the
@@ -18,22 +18,17 @@
18
18
  * NOT ported (CLI-side revert prediction / flow UX): checkUsernameFree,
19
19
  * AccountUnknown prediction, the live re-read of quickJoin.accountRegistry()
20
20
  * before a 2-tx join (a write-target pointer that updateAddresses can
21
- * re-point — see src/commands/user/join.ts), and the claim-hats Multicall3
22
- * probes (NoUsername / MAX_HATS_PER_MINT / HatOpenlyClaimable sentinel).
21
+ * re-point — see src/commands/user/join.ts).
23
22
  */
24
23
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.parseHatIds = parseHatIds;
26
24
  exports.buildRegisterAccount = buildRegisterAccount;
27
25
  exports.buildChangeUsername = buildChangeUsername;
28
26
  exports.buildSetProfileMetadata = buildSetProfileMetadata;
29
27
  exports.buildQuickJoinWithUser = buildQuickJoinWithUser;
30
- exports.buildClaimHatsWithUser = buildClaimHatsWithUser;
31
28
  exports.registerAccountIntent = registerAccountIntent;
32
29
  exports.changeUsernameIntent = changeUsernameIntent;
33
30
  exports.setProfileMetadataIntent = setProfileMetadataIntent;
34
31
  exports.quickJoinWithUserIntent = quickJoinWithUserIntent;
35
- exports.claimHatsWithUserIntent = claimHatsWithUserIntent;
36
- const ethers_1 = require("ethers");
37
32
  const contracts_1 = require("../contracts");
38
33
  const ipfs_1 = require("../ipfs");
39
34
  const encoding_1 = require("../encoding");
@@ -45,27 +40,6 @@ const infrastructure_1 = require("../graph/documents/infrastructure");
45
40
  const user_1 = require("../metadata/user");
46
41
  const resolve_1 = require("../reads/resolve");
47
42
  const user_2 = require("../reads/user");
48
- /**
49
- * Parse a comma-separated hat-ID list into BigNumbers. Accepts decimal and
50
- * 0x-hex forms. Hats Protocol IDs are uint256 — far beyond 2^53 — so
51
- * parseInt/Number would silently corrupt them.
52
- * Port of parseHatIds in `pop user claim-hats` —
53
- * src/commands/user/claim-hats.ts (same messages and exit codes).
54
- */
55
- function parseHatIds(input) {
56
- const parts = String(input).split(',').map(part => part.trim()).filter(part => part.length > 0);
57
- if (parts.length === 0) {
58
- throw new errors_1.CliError('No hat IDs given.', exit_codes_1.EXIT.USAGE, 'Pass --hats <id>[,<id>...] (see pop org roles for hat IDs).');
59
- }
60
- return parts.map(part => {
61
- try {
62
- return ethers_1.ethers.BigNumber.from(part);
63
- }
64
- catch {
65
- throw new errors_1.CliError(`Invalid hat ID "${part}".`, exit_codes_1.EXIT.USAGE, 'Hat IDs are uint256 integers — pass them as decimal or 0x-hex strings (see pop org roles).');
66
- }
67
- });
68
- }
69
43
  /**
70
44
  * Port of `pop user register` — src/commands/user/register.ts (also tx 1 of
71
45
  * the 2-tx `pop user join` flow — src/commands/user/join.ts).
@@ -149,29 +123,6 @@ function buildQuickJoinWithUser(a) {
149
123
  },
150
124
  };
151
125
  }
152
- /**
153
- * Port of `pop user claim-hats` — src/commands/user/claim-hats.ts.
154
- * QuickJoinNew.claimHatsWithUser(uint256[] claimHatIds). The caller must
155
- * already have a username (reverts NoUsername); since audit H-03 QuickJoin
156
- * refuses openly-claimable hats (reverts HatOpenlyClaimable), and the
157
- * executor bounds the batch at MAX_HATS_PER_MINT.
158
- */
159
- function buildClaimHatsWithUser(a) {
160
- return {
161
- to: a.quickJoinAddress,
162
- abi: (0, contracts_1.getAbi)('QuickJoinNew'),
163
- method: 'claimHatsWithUser',
164
- args: [a.hatIds],
165
- meta: {
166
- domain: 'user',
167
- action: 'claim-hats',
168
- orgId: a.orgId,
169
- summary: { hatIds: a.hatIds.map(id => id.toString()).join(',') },
170
- },
171
- };
172
- }
173
- // ──────────────────────────── Level 2 — resolved ───────────────────────────
174
- /** Validate a username with the CLI's wrapping (usage error, not a bare throw). */
175
126
  function requireUsernameArg(username) {
176
127
  try {
177
128
  return (0, validation_1.requireValidUsername)(username);
@@ -265,28 +216,3 @@ async function quickJoinWithUserIntent(ctx, params) {
265
216
  const quickJoinAddress = (0, resolve_1.requireModule)(modules, 'quickJoinAddress');
266
217
  return buildQuickJoinWithUser({ quickJoinAddress, orgId: modules.orgId });
267
218
  }
268
- /**
269
- * Resolved builder for `pop user claim-hats` —
270
- * src/commands/user/claim-hats.ts. Parses hat IDs with BigNumber (uint256 —
271
- * never parseInt), resolves the org's QuickJoin via the subgraph, and builds
272
- * the claimHatsWithUser intent. The CLI's Multicall3 preflight (NoUsername /
273
- * batch cap / open-hat sentinel probes) stays in the CLI.
274
- */
275
- async function claimHatsWithUserIntent(ctx, params) {
276
- const hatIds = typeof params.hats === 'string'
277
- ? parseHatIds(params.hats)
278
- : params.hats.map(part => {
279
- try {
280
- return ethers_1.ethers.BigNumber.from(part);
281
- }
282
- catch {
283
- throw new errors_1.CliError(`Invalid hat ID "${part}".`, exit_codes_1.EXIT.USAGE, 'Hat IDs are uint256 integers — pass them as decimal or 0x-hex strings (see pop org roles).');
284
- }
285
- });
286
- if (hatIds.length === 0) {
287
- throw new errors_1.CliError('No hat IDs given.', exit_codes_1.EXIT.USAGE, 'Pass --hats <id>[,<id>...] (see pop org roles for hat IDs).');
288
- }
289
- const modules = await (0, resolve_1.resolveOrgModules)(ctx.client, params.org, ctx.chainId);
290
- const quickJoinAddress = (0, resolve_1.requireModule)(modules, 'quickJoinAddress');
291
- return buildClaimHatsWithUser({ quickJoinAddress, hatIds, orgId: modules.orgId });
292
- }
package/dist/tx/vote.d.ts CHANGED
@@ -127,6 +127,9 @@ export interface CreateProposalParams {
127
127
  * parsed as BigNumbers from the raw values.
128
128
  */
129
129
  hatIds?: Array<string | ethers.BigNumberish>;
130
+ subjectIds?: ethers.BigNumberish[];
131
+ quorumOverride?: number;
132
+ equalWeight?: boolean;
130
133
  /** Execution calls for option 0 ({target, value, data} — the --calls shape). */
131
134
  calls?: ExecutionCallInput[];
132
135
  /** Metadata createdAt override (default Date.now()). */
@@ -290,6 +293,8 @@ export interface ParsedClassConfig {
290
293
  minBalance: ethers.BigNumber;
291
294
  asset: string;
292
295
  hatIds: ethers.BigNumber[];
296
+ /** Stable authority class binding. Omit to preserve it; zero clears it. */
297
+ subjectId?: ethers.BigNumber;
293
298
  }
294
299
  /**
295
300
  * Port of `parseClassConfigs` (src/commands/vote/classes.ts): validate +