@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.
- package/README.md +2 -0
- package/dist/abis/AuthorityRouter.d.ts +448 -0
- package/dist/abis/AuthorityRouter.js +584 -0
- package/dist/abis/CutoverVerifier.d.ts +194 -0
- package/dist/abis/CutoverVerifier.js +259 -0
- package/dist/abis/DirectDemocracyVotingNew.d.ts +168 -30
- package/dist/abis/DirectDemocracyVotingNew.js +214 -35
- package/dist/abis/EducationHubNew.d.ts +32 -75
- package/dist/abis/EducationHubNew.js +38 -94
- package/dist/abis/Executor.d.ts +56 -86
- package/dist/abis/Executor.js +68 -104
- package/dist/abis/HybridVotingNew.d.ts +279 -35
- package/dist/abis/HybridVotingNew.js +357 -40
- package/dist/abis/{EligibilityModuleNew.d.ts → MembershipAuthority.d.ts} +1437 -718
- package/dist/abis/{EligibilityModuleNew.js → MembershipAuthority.js} +1821 -899
- package/dist/abis/OrgDeployerNew.d.ts +193 -127
- package/dist/abis/OrgDeployerNew.js +244 -160
- package/dist/abis/OrgRegistry.d.ts +40 -0
- package/dist/abis/OrgRegistry.js +51 -0
- package/dist/abis/ParticipationToken.d.ts +32 -75
- package/dist/abis/ParticipationToken.js +38 -94
- package/dist/abis/PasskeyAccount.d.ts +28 -0
- package/dist/abis/PasskeyAccount.js +35 -0
- package/dist/abis/PaymasterHub.d.ts +527 -47
- package/dist/abis/PaymasterHub.js +750 -135
- package/dist/abis/QuickJoinNew.d.ts +59 -170
- package/dist/abis/QuickJoinNew.js +71 -215
- package/dist/abis/TaskManagerNew.d.ts +27 -44
- package/dist/abis/TaskManagerNew.js +31 -52
- package/dist/abis/UniversalAccountRegistry.d.ts +24 -0
- package/dist/abis/UniversalAccountRegistry.js +30 -0
- package/dist/abis/ZkEmailInvites.d.ts +44 -0
- package/dist/abis/ZkEmailInvites.js +55 -0
- package/dist/abis/index.d.ts +6 -4
- package/dist/abis/index.js +10 -7
- package/dist/chains.js +3 -3
- package/dist/error-catalog.js +125 -7
- package/dist/graph/documents/activity.d.ts +3 -1
- package/dist/graph/documents/activity.js +19 -14
- package/dist/graph/documents/org.d.ts +4 -4
- package/dist/graph/documents/org.js +10 -4
- package/dist/graph/documents/task.d.ts +10 -1
- package/dist/graph/documents/task.js +157 -3
- package/dist/graph/documents/user.d.ts +5 -30
- package/dist/graph/documents/user.js +2 -42
- package/dist/graph/documents/voting-classes.d.ts +23 -2
- package/dist/graph/documents/voting-classes.js +119 -10
- package/dist/metadata/index.d.ts +0 -1
- package/dist/metadata/index.js +1 -2
- package/dist/perms.d.ts +0 -15
- package/dist/perms.js +1 -21
- package/dist/preflight.d.ts +2 -2
- package/dist/preflight.js +14 -22
- package/dist/reads/authority.d.ts +33 -0
- package/dist/reads/authority.js +196 -0
- package/dist/reads/index.d.ts +1 -1
- package/dist/reads/index.js +2 -2
- package/dist/reads/org.d.ts +20 -20
- package/dist/reads/org.js +94 -28
- package/dist/reads/project.js +3 -3
- package/dist/reads/resolve.d.ts +1 -1
- package/dist/reads/resolve.js +12 -3
- package/dist/reads/task.d.ts +44 -22
- package/dist/reads/task.js +126 -67
- package/dist/reads/user.d.ts +8 -43
- package/dist/reads/user.js +27 -44
- package/dist/reads/vote.d.ts +26 -2
- package/dist/reads/vote.js +104 -23
- package/dist/tx/authority.d.ts +33 -0
- package/dist/tx/authority.js +62 -0
- package/dist/tx/governance.d.ts +6 -0
- package/dist/tx/governance.js +20 -2
- package/dist/tx/index.d.ts +1 -1
- package/dist/tx/index.js +2 -2
- package/dist/tx/org.d.ts +23 -18
- package/dist/tx/org.js +203 -67
- package/dist/tx/project.d.ts +3 -2
- package/dist/tx/project.js +28 -10
- package/dist/tx/task.d.ts +13 -24
- package/dist/tx/task.js +45 -85
- package/dist/tx/user.d.ts +2 -40
- package/dist/tx/user.js +2 -76
- package/dist/tx/vote.d.ts +5 -0
- package/dist/tx/vote.js +54 -43
- package/dist/version.d.ts +0 -5
- package/dist/version.js +1 -13
- package/package.json +1 -1
- package/dist/abis/ToggleModule.d.ts +0 -193
- package/dist/abis/ToggleModule.js +0 -255
- package/dist/metadata/role.d.ts +0 -38
- package/dist/metadata/role.js +0 -35
- package/dist/reads/eligibility.d.ts +0 -377
- package/dist/reads/eligibility.js +0 -687
- package/dist/tx/eligibility.d.ts +0 -511
- package/dist/tx/eligibility.js +0 -818
package/dist/tx/index.js
CHANGED
|
@@ -40,10 +40,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
40
40
|
};
|
|
41
41
|
})();
|
|
42
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
-
exports.zkemail = exports.vote = exports.user = exports.treasury = exports.token = exports.task = exports.project = exports.paymaster = exports.org = exports.governance = exports.
|
|
43
|
+
exports.authority = exports.zkemail = exports.vote = exports.user = exports.treasury = exports.token = exports.task = exports.project = exports.paymaster = exports.org = exports.governance = exports.education = void 0;
|
|
44
44
|
__exportStar(require("./intent"), exports);
|
|
45
45
|
exports.education = __importStar(require("./education"));
|
|
46
|
-
exports.eligibility = __importStar(require("./eligibility"));
|
|
47
46
|
exports.governance = __importStar(require("./governance"));
|
|
48
47
|
exports.org = __importStar(require("./org"));
|
|
49
48
|
exports.paymaster = __importStar(require("./paymaster"));
|
|
@@ -54,3 +53,4 @@ exports.treasury = __importStar(require("./treasury"));
|
|
|
54
53
|
exports.user = __importStar(require("./user"));
|
|
55
54
|
exports.vote = __importStar(require("./vote"));
|
|
56
55
|
exports.zkemail = __importStar(require("./zkemail"));
|
|
56
|
+
exports.authority = __importStar(require("./authority"));
|
package/dist/tx/org.d.ts
CHANGED
|
@@ -27,44 +27,45 @@ export interface OrgDeployConfig {
|
|
|
27
27
|
autoUpgrade?: boolean;
|
|
28
28
|
hybridVoting: {
|
|
29
29
|
thresholdPct: number;
|
|
30
|
+
quorum?: number;
|
|
30
31
|
classes: Array<{
|
|
31
32
|
strategy: 'DIRECT' | 'ERC20_BAL';
|
|
32
33
|
slicePct: number;
|
|
33
34
|
quadratic?: boolean;
|
|
34
35
|
minBalance?: string;
|
|
35
36
|
asset?: string;
|
|
36
|
-
|
|
37
|
+
subjectIds?: string[];
|
|
37
38
|
}>;
|
|
38
39
|
};
|
|
39
|
-
directDemocracy
|
|
40
|
+
directDemocracy?: {
|
|
40
41
|
thresholdPct: number;
|
|
42
|
+
quorum?: number;
|
|
41
43
|
};
|
|
42
44
|
roles: Array<{
|
|
43
45
|
name: string;
|
|
44
46
|
image?: string;
|
|
45
47
|
canVote: boolean;
|
|
48
|
+
metadataCID?: string;
|
|
49
|
+
open: boolean;
|
|
50
|
+
maxMembers?: number;
|
|
46
51
|
vouching?: {
|
|
47
52
|
enabled: boolean;
|
|
48
53
|
quorum: number;
|
|
49
54
|
voucherRoleIndex: number;
|
|
50
|
-
combineWithHierarchy?: boolean;
|
|
51
|
-
};
|
|
52
|
-
defaults?: {
|
|
53
|
-
eligible: boolean;
|
|
54
|
-
standing: boolean;
|
|
55
|
-
};
|
|
56
|
-
hierarchy?: {
|
|
57
|
-
adminRoleIndex: number;
|
|
58
55
|
};
|
|
59
56
|
distribution?: {
|
|
60
57
|
mintToDeployer: boolean;
|
|
61
58
|
additionalWearers?: string[];
|
|
62
59
|
};
|
|
63
|
-
hatConfig?: {
|
|
64
|
-
maxSupply: number;
|
|
65
|
-
mutableHat: boolean;
|
|
66
|
-
};
|
|
67
60
|
}>;
|
|
61
|
+
groups?: Array<{
|
|
62
|
+
name: string;
|
|
63
|
+
memberRoleIndices: number[];
|
|
64
|
+
}>;
|
|
65
|
+
token?: {
|
|
66
|
+
name?: string;
|
|
67
|
+
symbol?: string;
|
|
68
|
+
};
|
|
68
69
|
roleAssignments: {
|
|
69
70
|
quickJoinRoles: number[];
|
|
70
71
|
tokenMemberRoles: number[];
|
|
@@ -90,7 +91,7 @@ export interface OrgDeployConfig {
|
|
|
90
91
|
};
|
|
91
92
|
/**
|
|
92
93
|
* Optional org-wide TaskManager ROLE_PERM grants applied at deploy time
|
|
93
|
-
* (OrgDeployer.TaskManagerPermConfig — roleIndices resolve to
|
|
94
|
+
* (OrgDeployer.TaskManagerPermConfig — roleIndices resolve to subject IDs,
|
|
94
95
|
* masks are TaskPerm bitmasks: 1=create 2=claim 4=review 8=assign …).
|
|
95
96
|
*/
|
|
96
97
|
taskManagerPerms?: {
|
|
@@ -103,13 +104,15 @@ export declare function indicesToBitmap(indices: number[]): ethers.BigNumber;
|
|
|
103
104
|
/**
|
|
104
105
|
* Reject role indices that do not name a role in the config.
|
|
105
106
|
*
|
|
106
|
-
*
|
|
107
|
+
* The deployer rejects any bitmap bit without a registered role
|
|
107
108
|
* (audit M-09) — previously hat 0 was silently stored as an "authorized" hat and the deploy
|
|
108
109
|
* succeeded with a broken allowlist. Either way the config is wrong, and we know roles.length
|
|
109
110
|
* here, so name the offending field instead of surfacing a bare index from gas estimation
|
|
110
111
|
* (older deployers) or an aborted deploy (upgraded ones).
|
|
111
112
|
*/
|
|
112
113
|
export declare function assertRoleIndices(field: string, indices: number[] | undefined, roleCount: number): void;
|
|
114
|
+
/** Reject legacy access configs and validate the authority's genesis invariants before I/O. */
|
|
115
|
+
export declare function validateOrgDeployConfig(config: OrgDeployConfig): void;
|
|
113
116
|
/**
|
|
114
117
|
* Derive the deterministic orgId + normalized name the deployer uses:
|
|
115
118
|
* orgId = keccak256(orgName.toLowerCase().replace(/\s+/g, '-')).
|
|
@@ -189,7 +192,7 @@ export declare const DEPLOY_FULL_ORG_GAS_LIMIT = 15000000;
|
|
|
189
192
|
/**
|
|
190
193
|
* Pure assembly of the DeploymentParams struct — port of the param build in
|
|
191
194
|
* `pop org deploy` (src/commands/org/deploy.ts:257-403), byte-for-byte the
|
|
192
|
-
*
|
|
195
|
+
* native authority encoding. Validates taskManagerPerms lengths and every roleAssignments
|
|
193
196
|
* index exactly like the CLI (both gate the broadcast).
|
|
194
197
|
*
|
|
195
198
|
* ABI field order (verified against src/abi/OrgDeployerNew.json +
|
|
@@ -197,10 +200,12 @@ export declare const DEPLOY_FULL_ORG_GAS_LIMIT = 15000000;
|
|
|
197
200
|
* orgId, orgName, metadataHash, registryAddr, deployerAddress,
|
|
198
201
|
* deployerUsername, regDeadline, regNonce, regSignature, autoUpgrade,
|
|
199
202
|
* hybridThresholdPct, ddThresholdPct, hybridClasses, ddInitialTargets,
|
|
200
|
-
* roles, roleAssignments, metadataAdminRoleIndex, passkeyEnabled,
|
|
203
|
+
* roles, groups, roleAssignments, metadataAdminRoleIndex, passkeyEnabled,
|
|
201
204
|
* educationHubConfig, bootstrap, paymasterConfig, taskManagerPerms
|
|
202
205
|
*/
|
|
203
206
|
export declare function buildDeploymentParams(config: OrgDeployConfig, resolved: DeploymentResolvedInputs): unknown[];
|
|
207
|
+
/** Fail before publishing or signing when serving infrastructure still uses the retired deployer. */
|
|
208
|
+
export declare function requireAuthorityDeployerVersion(version: string): void;
|
|
204
209
|
export interface DeployFullOrgArgs {
|
|
205
210
|
/** OrgDeployer proxy (orgDeployerProxy from infrastructure). */
|
|
206
211
|
orgDeployerAddress: string;
|
package/dist/tx/org.js
CHANGED
|
@@ -15,10 +15,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.DEPLOY_FULL_ORG_GAS_LIMIT = exports.REGISTER_ACCOUNT_TYPES = void 0;
|
|
16
16
|
exports.indicesToBitmap = indicesToBitmap;
|
|
17
17
|
exports.assertRoleIndices = assertRoleIndices;
|
|
18
|
+
exports.validateOrgDeployConfig = validateOrgDeployConfig;
|
|
18
19
|
exports.deriveOrgId = deriveOrgId;
|
|
19
20
|
exports.registerAccountDomain = registerAccountDomain;
|
|
20
21
|
exports.signRegisterAccount = signRegisterAccount;
|
|
21
22
|
exports.buildDeploymentParams = buildDeploymentParams;
|
|
23
|
+
exports.requireAuthorityDeployerVersion = requireAuthorityDeployerVersion;
|
|
22
24
|
exports.buildDeployFullOrg = buildDeployFullOrg;
|
|
23
25
|
exports.deployFullOrgIntent = deployFullOrgIntent;
|
|
24
26
|
exports.buildUpdateOrgMetaAsAdmin = buildUpdateOrgMetaAsAdmin;
|
|
@@ -64,7 +66,7 @@ function indicesToBitmap(indices) {
|
|
|
64
66
|
/**
|
|
65
67
|
* Reject role indices that do not name a role in the config.
|
|
66
68
|
*
|
|
67
|
-
*
|
|
69
|
+
* The deployer rejects any bitmap bit without a registered role
|
|
68
70
|
* (audit M-09) — previously hat 0 was silently stored as an "authorized" hat and the deploy
|
|
69
71
|
* succeeded with a broken allowlist. Either way the config is wrong, and we know roles.length
|
|
70
72
|
* here, so name the offending field instead of surfacing a bare index from gas estimation
|
|
@@ -78,6 +80,152 @@ function assertRoleIndices(field, indices, roleCount) {
|
|
|
78
80
|
}
|
|
79
81
|
}
|
|
80
82
|
}
|
|
83
|
+
/** Reject legacy access configs and validate the authority's genesis invariants before I/O. */
|
|
84
|
+
function validateOrgDeployConfig(config) {
|
|
85
|
+
const invalid = (message) => { throw new errors_1.CliError('Config invalid: ' + message, exit_codes_1.EXIT.USAGE); };
|
|
86
|
+
const uint = (value, label, max = 4294967295) => {
|
|
87
|
+
if (typeof value !== 'number' || !Number.isInteger(value) || value < 0 || value > max)
|
|
88
|
+
invalid(label + ' must be an integer between 0 and ' + max);
|
|
89
|
+
};
|
|
90
|
+
if (!config?.orgName?.trim())
|
|
91
|
+
invalid('orgName is required');
|
|
92
|
+
if (!Array.isArray(config.roles) || config.roles.length < 1 || config.roles.length > 16)
|
|
93
|
+
invalid('roles must contain 1–16 authority roles');
|
|
94
|
+
if (!config.hybridVoting || !Array.isArray(config.hybridVoting.classes) || !config.hybridVoting.classes.length)
|
|
95
|
+
invalid('hybridVoting.classes is required');
|
|
96
|
+
if (config.hybridVoting.classes.length > 8)
|
|
97
|
+
invalid('hybridVoting.classes supports at most 8 classes');
|
|
98
|
+
uint(config.hybridVoting.thresholdPct, 'hybridVoting.thresholdPct', 100);
|
|
99
|
+
uint(config.directDemocracy?.thresholdPct ?? 51, 'directDemocracy.thresholdPct', 100);
|
|
100
|
+
if (config.hybridVoting.thresholdPct === 0 || config.directDemocracy?.thresholdPct === 0)
|
|
101
|
+
invalid('voting thresholds must be between 1 and 100');
|
|
102
|
+
uint(config.hybridVoting.quorum ?? 0, 'hybridVoting.quorum');
|
|
103
|
+
uint(config.directDemocracy?.quorum ?? 0, 'directDemocracy.quorum');
|
|
104
|
+
let slices = 0;
|
|
105
|
+
for (const c of config.hybridVoting.classes) {
|
|
106
|
+
if ('hatIds' in c)
|
|
107
|
+
invalid('hybridVoting.classes.hatIds is unsupported; use authority subjectIds');
|
|
108
|
+
if (c.strategy !== 'DIRECT' && c.strategy !== 'ERC20_BAL')
|
|
109
|
+
invalid('unknown voting class strategy');
|
|
110
|
+
uint(c.slicePct, 'hybridVoting.classes.slicePct', 100);
|
|
111
|
+
if (c.slicePct === 0)
|
|
112
|
+
invalid('hybridVoting.classes.slicePct must be positive');
|
|
113
|
+
slices += c.slicePct;
|
|
114
|
+
if (c.asset && !ethers_1.ethers.utils.isAddress(c.asset))
|
|
115
|
+
invalid('invalid voting asset address');
|
|
116
|
+
if (c.subjectIds && (!Array.isArray(c.subjectIds) || c.subjectIds.some(id => typeof id !== 'string' || !/^[0-9]+$/.test(id))))
|
|
117
|
+
invalid('subjectIds must be decimal strings');
|
|
118
|
+
if (c.subjectIds?.some(id => ethers_1.ethers.BigNumber.from(id).gt(ethers_1.ethers.constants.MaxUint256)))
|
|
119
|
+
invalid('subjectIds must fit uint256');
|
|
120
|
+
if (c.quadratic !== undefined && typeof c.quadratic !== 'boolean')
|
|
121
|
+
invalid('hybridVoting.classes.quadratic must be a boolean');
|
|
122
|
+
try {
|
|
123
|
+
const minimum = ethers_1.ethers.utils.parseUnits(c.minBalance ?? '0', 18);
|
|
124
|
+
if (minimum.lt(0) || minimum.gt(ethers_1.ethers.constants.MaxUint256))
|
|
125
|
+
invalid('hybridVoting.classes.minBalance must fit uint256');
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
invalid('hybridVoting.classes.minBalance must be a non-negative decimal amount with at most 18 decimals');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (slices !== 100)
|
|
132
|
+
invalid('hybridVoting class slices must sum to 100');
|
|
133
|
+
for (const [i, role] of config.roles.entries()) {
|
|
134
|
+
if (!role.name?.trim())
|
|
135
|
+
invalid('roles[' + i + '].name is required');
|
|
136
|
+
if ('hatConfig' in role || 'defaults' in role || 'hierarchy' in role || (role.vouching && 'combineWithHierarchy' in role.vouching))
|
|
137
|
+
invalid('legacy Hats role configuration is unsupported; use open, maxMembers and authority vouching');
|
|
138
|
+
if (typeof role.open !== 'boolean')
|
|
139
|
+
invalid('roles[' + i + '].open must explicitly be true or false');
|
|
140
|
+
if (typeof role.canVote !== 'boolean')
|
|
141
|
+
invalid('roles[' + i + '].canVote must be a boolean');
|
|
142
|
+
uint(role.maxMembers ?? 0, 'roles[' + i + '].maxMembers');
|
|
143
|
+
if (role.metadataCID !== undefined && !ethers_1.ethers.utils.isHexString(role.metadataCID, 32))
|
|
144
|
+
invalid('roles[' + i + '].metadataCID must be a bytes32 digest');
|
|
145
|
+
if (role.vouching?.enabled !== undefined && typeof role.vouching.enabled !== 'boolean')
|
|
146
|
+
invalid('roles[' + i + '].vouching.enabled must be a boolean');
|
|
147
|
+
if (role.distribution?.mintToDeployer !== undefined && typeof role.distribution.mintToDeployer !== 'boolean')
|
|
148
|
+
invalid('roles[' + i + '].distribution.mintToDeployer must be a boolean');
|
|
149
|
+
// Disabled vouch rows are still ABI encoded, so validate every supplied value.
|
|
150
|
+
if (role.vouching?.quorum !== undefined)
|
|
151
|
+
uint(role.vouching.quorum, 'roles[' + i + '].vouching.quorum');
|
|
152
|
+
if (role.vouching?.voucherRoleIndex !== undefined)
|
|
153
|
+
uint(role.vouching.voucherRoleIndex, 'roles[' + i + '].vouching.voucherRoleIndex');
|
|
154
|
+
if (role.vouching?.enabled) {
|
|
155
|
+
uint(role.vouching.quorum, 'roles[' + i + '].vouching.quorum');
|
|
156
|
+
if (!role.vouching.quorum)
|
|
157
|
+
invalid('enabled vouching requires a positive quorum');
|
|
158
|
+
assertRoleIndices('roles[' + i + '].vouching.voucherRoleIndex', [role.vouching.voucherRoleIndex], config.roles.length);
|
|
159
|
+
}
|
|
160
|
+
const wearers = role.distribution?.additionalWearers ?? [];
|
|
161
|
+
if (!Array.isArray(wearers) || wearers.some(w => !ethers_1.ethers.utils.isAddress(w) || w === ethers_1.ethers.constants.AddressZero))
|
|
162
|
+
invalid('invalid additional wearer address');
|
|
163
|
+
if (new Set(wearers.map(w => w.toLowerCase())).size !== wearers.length)
|
|
164
|
+
invalid('duplicate additional wearer');
|
|
165
|
+
const seeded = wearers.length + ((role.distribution?.mintToDeployer ?? true) ? 1 : 0);
|
|
166
|
+
if (role.maxMembers && seeded > role.maxMembers)
|
|
167
|
+
invalid('roles[' + i + '].maxMembers is below the genesis membership count');
|
|
168
|
+
}
|
|
169
|
+
if (!config.roleAssignments || typeof config.roleAssignments !== 'object')
|
|
170
|
+
invalid('roleAssignments is required');
|
|
171
|
+
const assignmentFields = ['quickJoinRoles', 'tokenMemberRoles', 'tokenApproverRoles', 'taskCreatorRoles', 'educationCreatorRoles', 'educationMemberRoles', 'hybridProposalCreatorRoles', 'ddVotingRoles', 'ddCreatorRoles'];
|
|
172
|
+
for (const field of Object.keys(config.roleAssignments))
|
|
173
|
+
if (!assignmentFields.includes(field))
|
|
174
|
+
invalid('unknown roleAssignments.' + field);
|
|
175
|
+
for (const field of assignmentFields) {
|
|
176
|
+
const indices = config.roleAssignments[field] ?? [];
|
|
177
|
+
if (!Array.isArray(indices))
|
|
178
|
+
invalid('roleAssignments.' + field + ' must be an array');
|
|
179
|
+
assertRoleIndices('roleAssignments.' + field, indices, config.roles.length);
|
|
180
|
+
}
|
|
181
|
+
for (const i of config.roleAssignments.quickJoinRoles ?? [])
|
|
182
|
+
if (!config.roles[i].open)
|
|
183
|
+
invalid('QuickJoin role ' + i + ' must be open');
|
|
184
|
+
if (config.groups && (!Array.isArray(config.groups) || config.groups.length > 8))
|
|
185
|
+
invalid('groups must contain at most 8 groups');
|
|
186
|
+
for (const [i, group] of (config.groups ?? []).entries()) {
|
|
187
|
+
if (!group.name?.trim() || !Array.isArray(group.memberRoleIndices) || group.memberRoleIndices.length < 1 || group.memberRoleIndices.length > 16)
|
|
188
|
+
invalid('groups[' + i + '] requires a name and 1–16 memberRoleIndices');
|
|
189
|
+
assertRoleIndices('groups[' + i + '].memberRoleIndices', group.memberRoleIndices, config.roles.length);
|
|
190
|
+
if (new Set(group.memberRoleIndices).size !== group.memberRoleIndices.length)
|
|
191
|
+
invalid('duplicate group member role');
|
|
192
|
+
}
|
|
193
|
+
if (config.metadataAdminRoleIndex !== undefined)
|
|
194
|
+
assertRoleIndices('metadataAdminRoleIndex', [config.metadataAdminRoleIndex], config.roles.length);
|
|
195
|
+
if (config.paymaster) {
|
|
196
|
+
const pm = config.paymaster;
|
|
197
|
+
assertRoleIndices('paymaster.operatorRoleIndex', [pm.operatorRoleIndex], config.roles.length);
|
|
198
|
+
uint(pm.defaultBudgetEpochLen, 'paymaster.defaultBudgetEpochLen');
|
|
199
|
+
for (const [field, decimals, bits] of [['maxFeePerGas', 9, 256], ['maxPriorityFeePerGas', 9, 256], ['defaultBudgetCapPerEpoch', 18, 128], ['funding', 18, 256]]) {
|
|
200
|
+
const raw = pm[field];
|
|
201
|
+
if (field === 'funding' && raw === undefined)
|
|
202
|
+
continue;
|
|
203
|
+
try {
|
|
204
|
+
const value = ethers_1.ethers.utils.parseUnits(raw, decimals);
|
|
205
|
+
if (value.lt(0) || value.gte(ethers_1.ethers.BigNumber.from(2).pow(bits)))
|
|
206
|
+
invalid('paymaster.' + field + ' is outside uint' + bits);
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
invalid('paymaster.' + field + ' must be a non-negative decimal amount that fits uint' + bits);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (config.autoUpgrade !== undefined && typeof config.autoUpgrade !== 'boolean')
|
|
214
|
+
invalid('autoUpgrade must be a boolean');
|
|
215
|
+
if (config.educationHub?.enabled !== undefined && typeof config.educationHub.enabled !== 'boolean')
|
|
216
|
+
invalid('educationHub.enabled must be a boolean');
|
|
217
|
+
for (const field of ['name', 'symbol'])
|
|
218
|
+
if (config.token?.[field] !== undefined && typeof config.token[field] !== 'string')
|
|
219
|
+
invalid('token.' + field + ' must be a string');
|
|
220
|
+
const tm = config.taskManagerPerms;
|
|
221
|
+
if (tm) {
|
|
222
|
+
if (!Array.isArray(tm.roleIndices) || !Array.isArray(tm.masks) || tm.roleIndices.length !== tm.masks.length)
|
|
223
|
+
invalid('taskManagerPerms.roleIndices and masks must be arrays of equal length');
|
|
224
|
+
assertRoleIndices('taskManagerPerms.roleIndices', tm.roleIndices, config.roles.length);
|
|
225
|
+
for (const mask of tm.masks)
|
|
226
|
+
uint(mask, 'taskManagerPerms.masks', 255);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
81
229
|
/**
|
|
82
230
|
* Derive the deterministic orgId + normalized name the deployer uses:
|
|
83
231
|
* orgId = keccak256(orgName.toLowerCase().replace(/\s+/g, '-')).
|
|
@@ -129,7 +277,7 @@ exports.DEPLOY_FULL_ORG_GAS_LIMIT = 15000000;
|
|
|
129
277
|
/**
|
|
130
278
|
* Pure assembly of the DeploymentParams struct — port of the param build in
|
|
131
279
|
* `pop org deploy` (src/commands/org/deploy.ts:257-403), byte-for-byte the
|
|
132
|
-
*
|
|
280
|
+
* native authority encoding. Validates taskManagerPerms lengths and every roleAssignments
|
|
133
281
|
* index exactly like the CLI (both gate the broadcast).
|
|
134
282
|
*
|
|
135
283
|
* ABI field order (verified against src/abi/OrgDeployerNew.json +
|
|
@@ -137,51 +285,26 @@ exports.DEPLOY_FULL_ORG_GAS_LIMIT = 15000000;
|
|
|
137
285
|
* orgId, orgName, metadataHash, registryAddr, deployerAddress,
|
|
138
286
|
* deployerUsername, regDeadline, regNonce, regSignature, autoUpgrade,
|
|
139
287
|
* hybridThresholdPct, ddThresholdPct, hybridClasses, ddInitialTargets,
|
|
140
|
-
* roles, roleAssignments, metadataAdminRoleIndex, passkeyEnabled,
|
|
288
|
+
* roles, groups, roleAssignments, metadataAdminRoleIndex, passkeyEnabled,
|
|
141
289
|
* educationHubConfig, bootstrap, paymasterConfig, taskManagerPerms
|
|
142
290
|
*/
|
|
143
291
|
function buildDeploymentParams(config, resolved) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
c.
|
|
148
|
-
c.
|
|
149
|
-
c.
|
|
150
|
-
c.
|
|
151
|
-
c.
|
|
152
|
-
c.hatIds || [], // uint256[]
|
|
292
|
+
validateOrgDeployConfig(config);
|
|
293
|
+
const hybridClasses = config.hybridVoting.classes.map(c => [
|
|
294
|
+
c.strategy === 'DIRECT' ? 0 : 1,
|
|
295
|
+
c.slicePct,
|
|
296
|
+
c.quadratic ?? false,
|
|
297
|
+
c.minBalance ? ethers_1.ethers.utils.parseUnits(c.minBalance, 18) : 0,
|
|
298
|
+
c.asset || ethers_1.ethers.constants.AddressZero,
|
|
299
|
+
c.subjectIds || [], // ABI retains the hatIds label; values are authority subjects.
|
|
153
300
|
]);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
r.name, // string
|
|
160
|
-
r.image || '', // string
|
|
161
|
-
ethers_1.ethers.constants.HashZero, // bytes32 metadataCID
|
|
162
|
-
r.canVote, // bool
|
|
163
|
-
[
|
|
164
|
-
r.vouching?.enabled || false,
|
|
165
|
-
r.vouching?.quorum || 0,
|
|
166
|
-
r.vouching?.voucherRoleIndex ?? ethers_1.ethers.constants.MaxUint256,
|
|
167
|
-
r.vouching?.combineWithHierarchy || false,
|
|
168
|
-
],
|
|
169
|
-
[
|
|
170
|
-
r.defaults?.eligible ?? true,
|
|
171
|
-
r.defaults?.standing ?? true,
|
|
172
|
-
],
|
|
173
|
-
[
|
|
174
|
-
r.hierarchy?.adminRoleIndex ?? ethers_1.ethers.constants.MaxUint256,
|
|
175
|
-
],
|
|
176
|
-
[
|
|
177
|
-
r.distribution?.mintToDeployer ?? true,
|
|
178
|
-
r.distribution?.additionalWearers || [],
|
|
179
|
-
],
|
|
180
|
-
[
|
|
181
|
-
r.hatConfig?.maxSupply ?? MAX_UINT32, // uint32, NOT uint256
|
|
182
|
-
r.hatConfig?.mutableHat ?? true,
|
|
183
|
-
],
|
|
301
|
+
const roles = config.roles.map(r => [
|
|
302
|
+
r.name, r.image || '', r.metadataCID || ethers_1.ethers.constants.HashZero,
|
|
303
|
+
r.canVote, r.open, r.maxMembers ?? 0,
|
|
304
|
+
[r.vouching?.enabled ?? false, r.vouching?.quorum ?? 0, r.vouching?.voucherRoleIndex ?? 0],
|
|
305
|
+
[r.distribution?.mintToDeployer ?? true, r.distribution?.additionalWearers || []],
|
|
184
306
|
]);
|
|
307
|
+
const groups = (config.groups || []).map(g => [g.name, g.memberRoleIndices]);
|
|
185
308
|
// Build role assignment bitmaps
|
|
186
309
|
const ra = config.roleAssignments;
|
|
187
310
|
// Every index must name a real role BEFORE anything is broadcast — a stale index is
|
|
@@ -197,15 +320,15 @@ function buildDeploymentParams(config, resolved) {
|
|
|
197
320
|
assertRoleIndices('roleAssignments.ddVotingRoles', ra.ddVotingRoles, roleCount);
|
|
198
321
|
assertRoleIndices('roleAssignments.ddCreatorRoles', ra.ddCreatorRoles, roleCount);
|
|
199
322
|
const roleAssignments = [
|
|
200
|
-
indicesToBitmap(ra.quickJoinRoles),
|
|
201
|
-
indicesToBitmap(ra.tokenMemberRoles),
|
|
202
|
-
indicesToBitmap(ra.tokenApproverRoles),
|
|
203
|
-
indicesToBitmap(ra.taskCreatorRoles),
|
|
323
|
+
indicesToBitmap(ra.quickJoinRoles || []),
|
|
324
|
+
indicesToBitmap(ra.tokenMemberRoles || []),
|
|
325
|
+
indicesToBitmap(ra.tokenApproverRoles || []),
|
|
326
|
+
indicesToBitmap(ra.taskCreatorRoles || []),
|
|
204
327
|
indicesToBitmap(ra.educationCreatorRoles || []),
|
|
205
328
|
indicesToBitmap(ra.educationMemberRoles || []),
|
|
206
|
-
indicesToBitmap(ra.hybridProposalCreatorRoles),
|
|
207
|
-
indicesToBitmap(ra.ddVotingRoles),
|
|
208
|
-
indicesToBitmap(ra.ddCreatorRoles),
|
|
329
|
+
indicesToBitmap(ra.hybridProposalCreatorRoles || []),
|
|
330
|
+
indicesToBitmap(ra.ddVotingRoles || []),
|
|
331
|
+
indicesToBitmap(ra.ddCreatorRoles || []),
|
|
209
332
|
];
|
|
210
333
|
// Build paymaster config
|
|
211
334
|
// ABI: operatorRoleIndex(uint256), autoWhitelistContracts(bool),
|
|
@@ -234,18 +357,15 @@ function buildDeploymentParams(config, resolved) {
|
|
|
234
357
|
0, // defaultBudgetCapPerEpoch
|
|
235
358
|
0, // defaultBudgetEpochLen
|
|
236
359
|
];
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if (tmPerms && (tmPerms.roleIndices?.length || 0) !== (tmPerms.masks?.length || 0)) {
|
|
243
|
-
throw new errors_1.CliError('Config invalid: taskManagerPerms.roleIndices and taskManagerPerms.masks must be the same length.', exit_codes_1.EXIT.USAGE);
|
|
360
|
+
// Config task creators can create both projects and tasks. The project creator
|
|
361
|
+
// array alone does not grant native TM_PERMS.CREATE, so seed that bit explicitly.
|
|
362
|
+
const taskMasks = new Map();
|
|
363
|
+
for (const [i, role] of (config.taskManagerPerms?.roleIndices ?? []).entries()) {
|
|
364
|
+
taskMasks.set(role, config.taskManagerPerms.masks[i]);
|
|
244
365
|
}
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
];
|
|
366
|
+
for (const role of config.roleAssignments.taskCreatorRoles ?? [])
|
|
367
|
+
taskMasks.set(role, (taskMasks.get(role) ?? 0) | 1);
|
|
368
|
+
const taskManagerPerms = [[...taskMasks.keys()], [...taskMasks.values()]];
|
|
249
369
|
return [
|
|
250
370
|
resolved.orgId, // bytes32
|
|
251
371
|
config.orgName, // string
|
|
@@ -258,10 +378,11 @@ function buildDeploymentParams(config, resolved) {
|
|
|
258
378
|
resolved.regSignature, // bytes
|
|
259
379
|
config.autoUpgrade ?? true, // bool
|
|
260
380
|
config.hybridVoting.thresholdPct, // uint8
|
|
261
|
-
config.directDemocracy?.thresholdPct
|
|
381
|
+
config.directDemocracy?.thresholdPct ?? 51, // uint8
|
|
262
382
|
hybridClasses, // ClassConfig[]
|
|
263
383
|
[], // address[] ddInitialTargets
|
|
264
384
|
roles, // RoleConfig[]
|
|
385
|
+
groups, // GroupConfig[]
|
|
265
386
|
roleAssignments, // RoleAssignments struct
|
|
266
387
|
config.metadataAdminRoleIndex ?? ethers_1.ethers.constants.MaxUint256, // uint256
|
|
267
388
|
true, // bool passkeyEnabled
|
|
@@ -269,8 +390,17 @@ function buildDeploymentParams(config, resolved) {
|
|
|
269
390
|
[[], []], // BootstrapConfig struct (projects, tasks)
|
|
270
391
|
paymasterConfig, // PaymasterConfig struct
|
|
271
392
|
taskManagerPerms, // TaskManagerPermConfig struct (roleIndices, masks)
|
|
393
|
+
config.hybridVoting.quorum ?? 0,
|
|
394
|
+
config.directDemocracy?.quorum ?? 0,
|
|
395
|
+
config.token?.name ?? "",
|
|
396
|
+
config.token?.symbol ?? "",
|
|
272
397
|
];
|
|
273
398
|
}
|
|
399
|
+
/** Fail before publishing or signing when serving infrastructure still uses the retired deployer. */
|
|
400
|
+
function requireAuthorityDeployerVersion(version) {
|
|
401
|
+
if (!/^2\./.test(version))
|
|
402
|
+
throw new errors_1.CliError(`OrgDeployer ${version || 'unknown'} is unsupported; deployer version 2 is required for native MembershipAuthority organizations.`, exit_codes_1.EXIT.PRECONDITION);
|
|
403
|
+
}
|
|
274
404
|
/**
|
|
275
405
|
* Port of `pop org deploy` — src/commands/org/deploy.ts.
|
|
276
406
|
* OrgDeployer.deployFullOrg([DeploymentParams]) — the single on-chain write,
|
|
@@ -312,12 +442,17 @@ function buildDeployFullOrg(a) {
|
|
|
312
442
|
async function deployFullOrgIntent(ctx, params) {
|
|
313
443
|
const config = params.config;
|
|
314
444
|
// ── Fail fast on config problems before any network work ───────────
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
445
|
+
validateOrgDeployConfig(config);
|
|
446
|
+
// Validate full ABI encoding before infrastructure reads, IPFS publication or signing.
|
|
447
|
+
const preview = buildDeploymentParams(config, {
|
|
448
|
+
orgId: ethers_1.ethers.constants.HashZero, metadataHash: ethers_1.ethers.constants.HashZero,
|
|
449
|
+
registryAddr: ethers_1.ethers.constants.AddressZero, deployerAddress: params.deployerAddress,
|
|
450
|
+
deployerUsername: '', regDeadline: 0, regNonce: 0, regSignature: '0x',
|
|
451
|
+
});
|
|
452
|
+
new ethers_1.ethers.utils.Interface((0, contracts_1.getAbi)('OrgDeployerNew')).encodeFunctionData('deployFullOrg', [preview]);
|
|
453
|
+
if (config.paymaster?.funding && ethers_1.ethers.utils.parseEther(config.paymaster.funding).lt(0)) {
|
|
454
|
+
throw new errors_1.CliError('Paymaster funding must not be negative', exit_codes_1.EXIT.USAGE);
|
|
455
|
+
}
|
|
321
456
|
if (!ctx.provider) {
|
|
322
457
|
throw new errors_1.CliError('deployFullOrgIntent requires ctx.provider (UniversalAccountRegistry.nonces read)', exit_codes_1.EXIT.USAGE);
|
|
323
458
|
}
|
|
@@ -332,6 +467,7 @@ async function deployFullOrgIntent(ctx, params) {
|
|
|
332
467
|
throw new errors_1.CliError('Could not resolve OrgDeployer address', exit_codes_1.EXIT.INFRA);
|
|
333
468
|
if (!registryAddr)
|
|
334
469
|
throw new errors_1.CliError('Could not resolve UniversalAccountRegistry address', exit_codes_1.EXIT.INFRA);
|
|
470
|
+
requireAuthorityDeployerVersion(await (0, contracts_1.createReadContract)(orgDeployerAddr, 'OrgDeployerNew', ctx.provider).VERSION());
|
|
335
471
|
// Generate orgId: keccak256(orgName.toLowerCase().replace(/\s+/g, '-'))
|
|
336
472
|
const { orgId, normalizedName } = deriveOrgId(config.orgName);
|
|
337
473
|
const deployerUsername = config.deployerUsername || normalizedName;
|
package/dist/tx/project.d.ts
CHANGED
|
@@ -75,6 +75,7 @@ export interface ProposeProjectArgs {
|
|
|
75
75
|
metadataHash?: string;
|
|
76
76
|
/** Human PT cap (0/omitted = unlimited). */
|
|
77
77
|
cap?: number | string;
|
|
78
|
+
managers?: string[];
|
|
78
79
|
createHats?: ethers.BigNumberish[];
|
|
79
80
|
claimHats?: ethers.BigNumberish[];
|
|
80
81
|
reviewHats?: ethers.BigNumberish[];
|
|
@@ -88,8 +89,7 @@ export interface ProposeProjectArgs {
|
|
|
88
89
|
/**
|
|
89
90
|
* Port of `pop project propose` — src/commands/project/propose.ts.
|
|
90
91
|
* HybridVoting.createProposal(`Create project: <name>`, descriptionHash,
|
|
91
|
-
* duration, 2, [[createProject call], []], []).
|
|
92
|
-
* bountyCaps are forced empty (hat-based), matching the CLI struct.
|
|
92
|
+
* duration, 2, [[createProject call], []], []). Explicit address managers remain supported; authority TM_PERMS replaces the retired role-mask arrays.
|
|
93
93
|
*/
|
|
94
94
|
export declare function buildProposeProject(a: ProposeProjectArgs): TxIntent;
|
|
95
95
|
export interface CreateProjectParams {
|
|
@@ -130,6 +130,7 @@ export interface ProposeProjectParams {
|
|
|
130
130
|
name: string;
|
|
131
131
|
description?: string;
|
|
132
132
|
cap?: number;
|
|
133
|
+
managers?: string[];
|
|
133
134
|
/** Vote duration in minutes (CLI default 1440 = 24h). */
|
|
134
135
|
duration?: number;
|
|
135
136
|
createHats?: Array<string | number>;
|
package/dist/tx/project.js
CHANGED
|
@@ -33,18 +33,34 @@ const proposal_1 = require("../metadata/proposal");
|
|
|
33
33
|
* governance-wrapped paths so the two cannot drift.
|
|
34
34
|
*/
|
|
35
35
|
function encodeProjectStruct(a) {
|
|
36
|
-
|
|
36
|
+
if ([a.createHats, a.claimHats, a.reviewHats, a.assignHats].some(rows => rows?.length))
|
|
37
|
+
throw new Error('Project permission arrays were removed. Configure MembershipAuthority TM_PERMS using projectId + 1 after creating the project.');
|
|
38
|
+
const title = (0, encoding_1.stringToBytes)(a.name);
|
|
39
|
+
if (title.length === 0 || title.length > 256)
|
|
40
|
+
throw new Error('Project title must contain 1–256 UTF-8 bytes.');
|
|
41
|
+
const cap = ethers_1.ethers.utils.parseUnits(String(a.cap ?? 0), 18);
|
|
42
|
+
const caps = (a.bountyCaps ?? []).map(c => ethers_1.ethers.BigNumber.from(c));
|
|
43
|
+
const maxPayout = ethers_1.ethers.BigNumber.from(10).pow(24);
|
|
44
|
+
const unlimited = ethers_1.ethers.BigNumber.from(2).pow(128).sub(1);
|
|
45
|
+
if ([cap, ...caps].some(value => value.lt(0) || (value.gt(maxPayout) && !value.eq(unlimited))))
|
|
46
|
+
throw new Error('Project and bounty caps must be at most 1e24 base units or the uint128 unlimited sentinel.');
|
|
47
|
+
if ((a.bountyTokens ?? []).length !== caps.length)
|
|
48
|
+
throw new Error('Bounty tokens and caps must have equal lengths.');
|
|
49
|
+
for (const address of [...(a.managers ?? []), ...(a.bountyTokens ?? [])]) {
|
|
50
|
+
if (!ethers_1.ethers.utils.isAddress(address) || address.toLowerCase() === ethers_1.ethers.constants.AddressZero)
|
|
51
|
+
throw new Error('Project managers and bounty tokens must be non-zero addresses.');
|
|
52
|
+
}
|
|
37
53
|
return [
|
|
38
|
-
|
|
54
|
+
title,
|
|
39
55
|
a.metadataHash ? (0, encoding_1.ipfsCidToBytes32)(a.metadataHash) : ethers_1.ethers.constants.HashZero,
|
|
40
56
|
cap,
|
|
41
57
|
a.managers ?? [],
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
58
|
+
[],
|
|
59
|
+
[],
|
|
60
|
+
[],
|
|
61
|
+
[],
|
|
46
62
|
a.bountyTokens ?? [],
|
|
47
|
-
|
|
63
|
+
caps,
|
|
48
64
|
];
|
|
49
65
|
}
|
|
50
66
|
/**
|
|
@@ -90,8 +106,7 @@ function buildCreateProjectCall(a) {
|
|
|
90
106
|
/**
|
|
91
107
|
* Port of `pop project propose` — src/commands/project/propose.ts.
|
|
92
108
|
* HybridVoting.createProposal(`Create project: <name>`, descriptionHash,
|
|
93
|
-
* duration, 2, [[createProject call], []], []).
|
|
94
|
-
* bountyCaps are forced empty (hat-based), matching the CLI struct.
|
|
109
|
+
* duration, 2, [[createProject call], []], []). Explicit address managers remain supported; authority TM_PERMS replaces the retired role-mask arrays.
|
|
95
110
|
*/
|
|
96
111
|
function buildProposeProject(a) {
|
|
97
112
|
const call = buildCreateProjectCall({
|
|
@@ -99,7 +114,7 @@ function buildProposeProject(a) {
|
|
|
99
114
|
name: a.name,
|
|
100
115
|
metadataHash: a.metadataHash,
|
|
101
116
|
cap: a.cap,
|
|
102
|
-
managers: [],
|
|
117
|
+
managers: a.managers ?? [],
|
|
103
118
|
createHats: a.createHats,
|
|
104
119
|
claimHats: a.claimHats,
|
|
105
120
|
reviewHats: a.reviewHats,
|
|
@@ -131,6 +146,7 @@ function buildProposeProject(a) {
|
|
|
131
146
|
* delegates to buildCreateProject.
|
|
132
147
|
*/
|
|
133
148
|
async function createProjectIntent(ctx, p) {
|
|
149
|
+
encodeProjectStruct({ ...p, taskManagerAddress: ethers_1.ethers.constants.AddressZero });
|
|
134
150
|
const modules = await (0, resolve_1.resolveOrgModules)(ctx.client, p.org, ctx.chainId);
|
|
135
151
|
const taskManagerAddress = (0, resolve_1.requireModule)(modules, 'taskManagerAddress');
|
|
136
152
|
let metaCid;
|
|
@@ -179,6 +195,7 @@ async function deleteProjectIntent(ctx, p) {
|
|
|
179
195
|
* wraps the createProject calldata in a HybridVoting proposal.
|
|
180
196
|
*/
|
|
181
197
|
async function proposeProjectIntent(ctx, p) {
|
|
198
|
+
encodeProjectStruct({ ...p, taskManagerAddress: ethers_1.ethers.constants.AddressZero });
|
|
182
199
|
const modules = await (0, resolve_1.resolveOrgModules)(ctx.client, p.org, ctx.chainId);
|
|
183
200
|
const taskManagerAddress = (0, resolve_1.requireModule)(modules, 'taskManagerAddress');
|
|
184
201
|
const hybridVotingAddress = modules.hybridVotingAddress;
|
|
@@ -204,6 +221,7 @@ async function proposeProjectIntent(ctx, p) {
|
|
|
204
221
|
name: p.name,
|
|
205
222
|
metadataHash: metaCid,
|
|
206
223
|
cap: p.cap,
|
|
224
|
+
managers: p.managers,
|
|
207
225
|
createHats: p.createHats,
|
|
208
226
|
claimHats: p.claimHats,
|
|
209
227
|
reviewHats: p.reviewHats,
|