@poa-box/core 0.1.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 +201 -0
- package/dist/abis/DirectDemocracyVotingNew.d.ts +749 -0
- package/dist/abis/DirectDemocracyVotingNew.js +961 -0
- package/dist/abis/ERC20.d.ts +90 -0
- package/dist/abis/ERC20.js +125 -0
- package/dist/abis/EducationHubNew.d.ts +590 -0
- package/dist/abis/EducationHubNew.js +762 -0
- package/dist/abis/EligibilityModuleNew.d.ts +1615 -0
- package/dist/abis/EligibilityModuleNew.js +2082 -0
- package/dist/abis/Executor.d.ts +619 -0
- package/dist/abis/Executor.js +796 -0
- package/dist/abis/HybridVotingNew.d.ts +898 -0
- package/dist/abis/HybridVotingNew.js +1149 -0
- package/dist/abis/ImplementationRegistry.d.ts +270 -0
- package/dist/abis/ImplementationRegistry.js +355 -0
- package/dist/abis/OrgDeployerNew.d.ts +1275 -0
- package/dist/abis/OrgDeployerNew.js +1630 -0
- package/dist/abis/OrgRegistry.d.ts +670 -0
- package/dist/abis/OrgRegistry.js +868 -0
- package/dist/abis/ParticipationToken.d.ts +1086 -0
- package/dist/abis/ParticipationToken.js +1415 -0
- package/dist/abis/PasskeyAccount.d.ts +788 -0
- package/dist/abis/PasskeyAccount.js +1019 -0
- package/dist/abis/PasskeyAccountFactory.d.ts +344 -0
- package/dist/abis/PasskeyAccountFactory.js +449 -0
- package/dist/abis/PaymasterHub.d.ts +1603 -0
- package/dist/abis/PaymasterHub.js +2048 -0
- package/dist/abis/PaymentManager.d.ts +520 -0
- package/dist/abis/PaymentManager.js +671 -0
- package/dist/abis/PoaManager.d.ts +344 -0
- package/dist/abis/PoaManager.js +449 -0
- package/dist/abis/QuickJoinNew.d.ts +855 -0
- package/dist/abis/QuickJoinNew.js +1098 -0
- package/dist/abis/TaskManagerNew.d.ts +1236 -0
- package/dist/abis/TaskManagerNew.js +1573 -0
- package/dist/abis/ToggleModule.d.ts +193 -0
- package/dist/abis/ToggleModule.js +255 -0
- package/dist/abis/UniversalAccountRegistry.d.ts +577 -0
- package/dist/abis/UniversalAccountRegistry.js +750 -0
- package/dist/abis/ZkEmailInvites.d.ts +823 -0
- package/dist/abis/ZkEmailInvites.js +1060 -0
- package/dist/abis/external/AaveGovernanceV2.d.ts +128 -0
- package/dist/abis/external/AaveGovernanceV2.js +177 -0
- package/dist/abis/external/AaveGovernanceV3.d.ts +160 -0
- package/dist/abis/external/AaveGovernanceV3.js +220 -0
- package/dist/abis/external/AragonVoting.d.ts +107 -0
- package/dist/abis/external/AragonVoting.js +150 -0
- package/dist/abis/external/CurveGaugeController.d.ts +95 -0
- package/dist/abis/external/CurveGaugeController.js +130 -0
- package/dist/abis/external/CurveVotingEscrow.d.ts +86 -0
- package/dist/abis/external/CurveVotingEscrow.js +116 -0
- package/dist/abis/external/GovernorAlpha.d.ts +172 -0
- package/dist/abis/external/GovernorAlpha.js +228 -0
- package/dist/abis/external/MakerDAOChief.d.ts +92 -0
- package/dist/abis/external/MakerDAOChief.js +129 -0
- package/dist/abis/external/OZGovernor.d.ts +227 -0
- package/dist/abis/external/OZGovernor.js +317 -0
- package/dist/abis/external/SolidlyVotingEscrow.d.ts +196 -0
- package/dist/abis/external/SolidlyVotingEscrow.js +260 -0
- package/dist/abis/index.d.ts +62 -0
- package/dist/abis/index.js +98 -0
- package/dist/chains.d.ts +150 -0
- package/dist/chains.js +320 -0
- package/dist/context.d.ts +48 -0
- package/dist/context.js +38 -0
- package/dist/contracts.d.ts +24 -0
- package/dist/contracts.js +41 -0
- package/dist/encoding.d.ts +58 -0
- package/dist/encoding.js +243 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.js +4 -0
- package/dist/error-catalog.d.ts +41 -0
- package/dist/error-catalog.js +941 -0
- package/dist/errors.d.ts +27 -0
- package/dist/errors.js +60 -0
- package/dist/execute/ethers.d.ts +93 -0
- package/dist/execute/ethers.js +323 -0
- package/dist/execute/index.d.ts +7 -0
- package/dist/execute/index.js +23 -0
- package/dist/execute/sponsored.d.ts +68 -0
- package/dist/execute/sponsored.js +277 -0
- package/dist/exit-codes.d.ts +18 -0
- package/dist/exit-codes.js +21 -0
- package/dist/format.d.ts +21 -0
- package/dist/format.js +89 -0
- package/dist/graph/client.d.ts +298 -0
- package/dist/graph/client.js +702 -0
- package/dist/graph/documents/activity.d.ts +9 -0
- package/dist/graph/documents/activity.js +164 -0
- package/dist/graph/documents/beacons.d.ts +172 -0
- package/dist/graph/documents/beacons.js +345 -0
- package/dist/graph/documents/index.d.ts +21 -0
- package/dist/graph/documents/index.js +57 -0
- package/dist/graph/documents/infrastructure.d.ts +30 -0
- package/dist/graph/documents/infrastructure.js +34 -0
- package/dist/graph/documents/org.d.ts +15 -0
- package/dist/graph/documents/org.js +249 -0
- package/dist/graph/documents/paymaster.d.ts +95 -0
- package/dist/graph/documents/paymaster.js +101 -0
- package/dist/graph/documents/role.d.ts +6 -0
- package/dist/graph/documents/role.js +41 -0
- package/dist/graph/documents/roles.d.ts +50 -0
- package/dist/graph/documents/roles.js +112 -0
- package/dist/graph/documents/task.d.ts +84 -0
- package/dist/graph/documents/task.js +236 -0
- package/dist/graph/documents/token.d.ts +13 -0
- package/dist/graph/documents/token.js +126 -0
- package/dist/graph/documents/treasury.d.ts +39 -0
- package/dist/graph/documents/treasury.js +136 -0
- package/dist/graph/documents/user.d.ts +120 -0
- package/dist/graph/documents/user.js +302 -0
- package/dist/graph/documents/voting-classes.d.ts +69 -0
- package/dist/graph/documents/voting-classes.js +149 -0
- package/dist/graph/documents/voting.d.ts +28 -0
- package/dist/graph/documents/voting.js +163 -0
- package/dist/graph/documents/vouch.d.ts +79 -0
- package/dist/graph/documents/vouch.js +171 -0
- package/dist/graph/documents/zkemail.d.ts +63 -0
- package/dist/graph/documents/zkemail.js +188 -0
- package/dist/graph/index.d.ts +2 -0
- package/dist/graph/index.js +41 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.js +92 -0
- package/dist/ipfs.d.ts +39 -0
- package/dist/ipfs.js +214 -0
- package/dist/label-aliases.d.ts +31 -0
- package/dist/label-aliases.js +70 -0
- package/dist/metadata/education.d.ts +30 -0
- package/dist/metadata/education.js +31 -0
- package/dist/metadata/index.d.ts +12 -0
- package/dist/metadata/index.js +48 -0
- package/dist/metadata/org.d.ts +92 -0
- package/dist/metadata/org.js +93 -0
- package/dist/metadata/proposal.d.ts +44 -0
- package/dist/metadata/proposal.js +45 -0
- package/dist/metadata/role.d.ts +38 -0
- package/dist/metadata/role.js +35 -0
- package/dist/metadata/task.d.ts +108 -0
- package/dist/metadata/task.js +81 -0
- package/dist/metadata/token.d.ts +32 -0
- package/dist/metadata/token.js +36 -0
- package/dist/metadata/user.d.ts +63 -0
- package/dist/metadata/user.js +70 -0
- package/dist/multicall.d.ts +32 -0
- package/dist/multicall.js +96 -0
- package/dist/payout.d.ts +59 -0
- package/dist/payout.js +96 -0
- package/dist/perms.d.ts +47 -0
- package/dist/perms.js +120 -0
- package/dist/preflight.d.ts +72 -0
- package/dist/preflight.js +269 -0
- package/dist/reads/education.d.ts +79 -0
- package/dist/reads/education.js +122 -0
- package/dist/reads/eligibility.d.ts +377 -0
- package/dist/reads/eligibility.js +687 -0
- package/dist/reads/index.d.ts +16 -0
- package/dist/reads/index.js +55 -0
- package/dist/reads/org.d.ts +258 -0
- package/dist/reads/org.js +220 -0
- package/dist/reads/paymaster.d.ts +147 -0
- package/dist/reads/paymaster.js +235 -0
- package/dist/reads/project.d.ts +33 -0
- package/dist/reads/project.js +62 -0
- package/dist/reads/resolve.d.ts +34 -0
- package/dist/reads/resolve.js +64 -0
- package/dist/reads/task.d.ts +286 -0
- package/dist/reads/task.js +280 -0
- package/dist/reads/token.d.ts +94 -0
- package/dist/reads/token.js +75 -0
- package/dist/reads/treasury.d.ts +222 -0
- package/dist/reads/treasury.js +241 -0
- package/dist/reads/user.d.ts +229 -0
- package/dist/reads/user.js +155 -0
- package/dist/reads/vote.d.ts +296 -0
- package/dist/reads/vote.js +392 -0
- package/dist/reads/zkemail.d.ts +117 -0
- package/dist/reads/zkemail.js +217 -0
- package/dist/similarity.d.ts +36 -0
- package/dist/similarity.js +67 -0
- package/dist/sponsorship-config.d.ts +47 -0
- package/dist/sponsorship-config.js +41 -0
- package/dist/stats.d.ts +11 -0
- package/dist/stats.js +27 -0
- package/dist/task-lens.d.ts +113 -0
- package/dist/task-lens.js +210 -0
- package/dist/tx/education.d.ts +169 -0
- package/dist/tx/education.js +344 -0
- package/dist/tx/eligibility.d.ts +511 -0
- package/dist/tx/eligibility.js +818 -0
- package/dist/tx/governance.d.ts +85 -0
- package/dist/tx/governance.js +87 -0
- package/dist/tx/index.d.ts +17 -0
- package/dist/tx/index.js +56 -0
- package/dist/tx/intent.d.ts +67 -0
- package/dist/tx/intent.js +48 -0
- package/dist/tx/org.d.ts +321 -0
- package/dist/tx/org.js +544 -0
- package/dist/tx/paymaster.d.ts +140 -0
- package/dist/tx/paymaster.js +251 -0
- package/dist/tx/project.d.ts +146 -0
- package/dist/tx/project.js +217 -0
- package/dist/tx/task.d.ts +480 -0
- package/dist/tx/task.js +1149 -0
- package/dist/tx/token.d.ts +96 -0
- package/dist/tx/token.js +165 -0
- package/dist/tx/treasury.d.ts +474 -0
- package/dist/tx/treasury.js +911 -0
- package/dist/tx/user.d.ts +177 -0
- package/dist/tx/user.js +292 -0
- package/dist/tx/vote.d.ts +332 -0
- package/dist/tx/vote.js +762 -0
- package/dist/tx/zkemail.d.ts +90 -0
- package/dist/tx/zkemail.js +210 -0
- package/dist/validation.d.ts +8 -0
- package/dist/validation.js +39 -0
- package/dist/version.d.ts +142 -0
- package/dist/version.js +257 -0
- package/dist/zkemail.d.ts +161 -0
- package/dist/zkemail.js +299 -0
- package/package.json +130 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Education write builders.
|
|
4
|
+
*
|
|
5
|
+
* Ports:
|
|
6
|
+
* - `pop education create` — src/commands/education/create-module.ts
|
|
7
|
+
* - `pop education complete` — src/commands/education/complete.ts
|
|
8
|
+
* - `pop education update` — src/commands/education/update.ts
|
|
9
|
+
* - `pop education remove` — src/commands/education/remove.ts
|
|
10
|
+
*
|
|
11
|
+
* EducationHub facts (verified contracts origin/main src/EducationHub.sol):
|
|
12
|
+
* - createModule hashes the correct answer into the module PERMANENTLY —
|
|
13
|
+
* updateModule never touches answerHash, so changing quiz content cannot
|
|
14
|
+
* change which answer index passes (remove + recreate to change it).
|
|
15
|
+
* - updateModule is a FULL OVERWRITE of title + contentHash + payout.
|
|
16
|
+
* - removeModule is a permanent delete with no undo.
|
|
17
|
+
* - The chain stores only {answerHash, payout, exists}; module metadata is
|
|
18
|
+
* event-only, so preservation reads go through the subgraph/IPFS.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.buildCreateModule = buildCreateModule;
|
|
22
|
+
exports.buildCompleteModule = buildCompleteModule;
|
|
23
|
+
exports.buildUpdateModule = buildUpdateModule;
|
|
24
|
+
exports.buildRemoveModule = buildRemoveModule;
|
|
25
|
+
exports.createModuleIntent = createModuleIntent;
|
|
26
|
+
exports.completeModuleIntent = completeModuleIntent;
|
|
27
|
+
exports.updateModuleIntent = updateModuleIntent;
|
|
28
|
+
exports.removeModuleIntent = removeModuleIntent;
|
|
29
|
+
const ethers_1 = require("ethers");
|
|
30
|
+
const contracts_1 = require("../contracts");
|
|
31
|
+
const encoding_1 = require("../encoding");
|
|
32
|
+
const ipfs_1 = require("../ipfs");
|
|
33
|
+
const errors_1 = require("../errors");
|
|
34
|
+
const exit_codes_1 = require("../exit-codes");
|
|
35
|
+
const resolve_1 = require("../reads/resolve");
|
|
36
|
+
const education_1 = require("../metadata/education");
|
|
37
|
+
const education_2 = require("../reads/education");
|
|
38
|
+
/**
|
|
39
|
+
* Port of `pop education create` — src/commands/education/create-module.ts.
|
|
40
|
+
* EducationHubNew.createModule(stringToBytes(name), contentHash,
|
|
41
|
+
* payoutWei(18d), correctAnswer uint8). Validates payout > 0 (the contract
|
|
42
|
+
* reverts InvalidPayout for 0) and correctAnswer 0-255, same messages as the
|
|
43
|
+
* CLI.
|
|
44
|
+
*/
|
|
45
|
+
function buildCreateModule(a) {
|
|
46
|
+
const payoutNum = Number(a.payout);
|
|
47
|
+
if (!(payoutNum > 0) || !isFinite(payoutNum)) {
|
|
48
|
+
throw new errors_1.CliError(`--payout must be a positive number (the contract reverts InvalidPayout for 0), got: ${a.payout}`, exit_codes_1.EXIT.USAGE);
|
|
49
|
+
}
|
|
50
|
+
if (!Number.isInteger(a.correctAnswer) || a.correctAnswer < 0 || a.correctAnswer > 255) {
|
|
51
|
+
throw new errors_1.CliError(`--correct-answer must be an integer 0-255 (uint8), got: ${a.correctAnswer}`, exit_codes_1.EXIT.USAGE);
|
|
52
|
+
}
|
|
53
|
+
const titleBytes = (0, encoding_1.stringToBytes)(a.name);
|
|
54
|
+
const payoutWei = ethers_1.ethers.utils.parseUnits(a.payout.toString(), 18);
|
|
55
|
+
return {
|
|
56
|
+
to: a.educationHubAddress,
|
|
57
|
+
abi: (0, contracts_1.getAbi)('EducationHubNew'),
|
|
58
|
+
method: 'createModule',
|
|
59
|
+
args: [titleBytes, a.contentHash, payoutWei, a.correctAnswer],
|
|
60
|
+
meta: {
|
|
61
|
+
domain: 'education',
|
|
62
|
+
action: 'create-module',
|
|
63
|
+
orgId: a.orgId,
|
|
64
|
+
summary: {
|
|
65
|
+
name: a.name,
|
|
66
|
+
payout: `${a.payout} PT`,
|
|
67
|
+
correctAnswer: `index ${a.correctAnswer} (permanent)`,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Port of `pop education complete` — src/commands/education/complete.ts.
|
|
74
|
+
* EducationHubNew.completeModule(moduleId, answer uint8) — pays PT once per
|
|
75
|
+
* account (reverts AlreadyCompleted on a second attempt, ModuleUnknown for
|
|
76
|
+
* missing modules). Validates answer 0-255, same message as the CLI.
|
|
77
|
+
*/
|
|
78
|
+
function buildCompleteModule(a) {
|
|
79
|
+
if (!Number.isInteger(a.answer) || a.answer < 0 || a.answer > 255) {
|
|
80
|
+
throw new errors_1.CliError(`--answer must be an integer 0-255 (uint8), got: ${a.answer}`, exit_codes_1.EXIT.USAGE);
|
|
81
|
+
}
|
|
82
|
+
const moduleId = (0, encoding_1.parseModuleId)(a.moduleId);
|
|
83
|
+
return {
|
|
84
|
+
to: a.educationHubAddress,
|
|
85
|
+
abi: (0, contracts_1.getAbi)('EducationHubNew'),
|
|
86
|
+
method: 'completeModule',
|
|
87
|
+
args: [moduleId, a.answer],
|
|
88
|
+
meta: {
|
|
89
|
+
domain: 'education',
|
|
90
|
+
action: 'complete',
|
|
91
|
+
orgId: a.orgId,
|
|
92
|
+
summary: { moduleId, answer: `index ${a.answer}` },
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Port of `pop education update` — src/commands/education/update.ts.
|
|
98
|
+
* EducationHubNew.updateModule(id, stringToBytes(name), contentHash,
|
|
99
|
+
* payoutWei) — full overwrite of title + contentHash + payout; the answer
|
|
100
|
+
* hash is IMMUTABLE.
|
|
101
|
+
*/
|
|
102
|
+
function buildUpdateModule(a) {
|
|
103
|
+
const moduleId = (0, encoding_1.parseModuleId)(a.moduleId);
|
|
104
|
+
return {
|
|
105
|
+
to: a.educationHubAddress,
|
|
106
|
+
abi: (0, contracts_1.getAbi)('EducationHubNew'),
|
|
107
|
+
method: 'updateModule',
|
|
108
|
+
args: [moduleId, (0, encoding_1.stringToBytes)(a.name), a.contentHash, a.payoutWei],
|
|
109
|
+
meta: {
|
|
110
|
+
domain: 'education',
|
|
111
|
+
action: 'update',
|
|
112
|
+
orgId: a.orgId,
|
|
113
|
+
summary: { moduleId, title: a.name },
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Port of `pop education remove` — src/commands/education/remove.ts.
|
|
119
|
+
* EducationHubNew.removeModule(moduleId) — PERMANENT delete, no undo; past
|
|
120
|
+
* completions keep their minted PT but the module disappears for everyone.
|
|
121
|
+
*/
|
|
122
|
+
function buildRemoveModule(a) {
|
|
123
|
+
const moduleId = (0, encoding_1.parseModuleId)(a.moduleId);
|
|
124
|
+
return {
|
|
125
|
+
to: a.educationHubAddress,
|
|
126
|
+
abi: (0, contracts_1.getAbi)('EducationHubNew'),
|
|
127
|
+
method: 'removeModule',
|
|
128
|
+
args: [moduleId],
|
|
129
|
+
meta: {
|
|
130
|
+
domain: 'education',
|
|
131
|
+
action: 'remove',
|
|
132
|
+
orgId: a.orgId,
|
|
133
|
+
summary: {
|
|
134
|
+
module: a.title ? `#${moduleId} — ${a.title}` : `#${moduleId}`,
|
|
135
|
+
warning: 'permanent removal — no undo; the module and its payout disappear for everyone',
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Resolved builder for `pop education create` — src/commands/education/create-module.ts.
|
|
142
|
+
* Resolves the org's EducationHub, pins the module metadata
|
|
143
|
+
* ({name, description, link, quiz, answers} — key order load-bearing), and
|
|
144
|
+
* delegates to buildCreateModule.
|
|
145
|
+
*/
|
|
146
|
+
async function createModuleIntent(ctx, params) {
|
|
147
|
+
const quiz = params.quiz || [];
|
|
148
|
+
const answers = params.answers || [];
|
|
149
|
+
if (quiz.length > 0 && answers.length > 0 && quiz.length !== answers.length) {
|
|
150
|
+
throw new errors_1.CliError(`Quiz has ${quiz.length} questions but ${answers.length} answer sets. They must match.`, exit_codes_1.EXIT.USAGE);
|
|
151
|
+
}
|
|
152
|
+
const modules = await (0, resolve_1.resolveOrgModules)(ctx.client, params.org, ctx.chainId);
|
|
153
|
+
const educationHubAddress = (0, resolve_1.requireModule)(modules, 'educationHubAddress');
|
|
154
|
+
const metadata = (0, education_1.buildEducationModuleMetadata)({
|
|
155
|
+
name: params.name,
|
|
156
|
+
description: params.description,
|
|
157
|
+
link: params.link,
|
|
158
|
+
quiz,
|
|
159
|
+
answers,
|
|
160
|
+
});
|
|
161
|
+
const cid = await (0, ipfs_1.pinJson)((0, education_1.serializeEducationModuleMetadata)(metadata), ctx.ipfs);
|
|
162
|
+
const contentHash = (0, encoding_1.ipfsCidToBytes32)(cid);
|
|
163
|
+
const intent = buildCreateModule({
|
|
164
|
+
educationHubAddress,
|
|
165
|
+
name: params.name,
|
|
166
|
+
contentHash,
|
|
167
|
+
payout: params.payout,
|
|
168
|
+
correctAnswer: params.correctAnswer,
|
|
169
|
+
orgId: modules.orgId,
|
|
170
|
+
});
|
|
171
|
+
intent.meta.ipfs = { cid, metadata };
|
|
172
|
+
return intent;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Resolved builder for `pop education complete` — src/commands/education/complete.ts.
|
|
176
|
+
* Resolves the org's EducationHub and delegates to buildCompleteModule. The
|
|
177
|
+
* CLI's pre-flight (module exists via getModule, not-already-completed via
|
|
178
|
+
* hasCompleted) is a host concern — see checkModuleExists/checkNotCompleted
|
|
179
|
+
* in the CLI's education helpers.
|
|
180
|
+
*/
|
|
181
|
+
async function completeModuleIntent(ctx, params) {
|
|
182
|
+
const modules = await (0, resolve_1.resolveOrgModules)(ctx.client, params.org, ctx.chainId);
|
|
183
|
+
const educationHubAddress = (0, resolve_1.requireModule)(modules, 'educationHubAddress');
|
|
184
|
+
return buildCompleteModule({
|
|
185
|
+
educationHubAddress,
|
|
186
|
+
moduleId: params.module,
|
|
187
|
+
answer: params.answer,
|
|
188
|
+
orgId: modules.orgId,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Resolved builder for `pop education update` — src/commands/education/update.ts.
|
|
193
|
+
*
|
|
194
|
+
* READ-MERGE issued concurrently (Promise.allSettled): payout + existence
|
|
195
|
+
* from on-chain getModule — deliberately NOT the indexed payout, because a
|
|
196
|
+
* full overwrite writes the read-back value and a stale one would silently
|
|
197
|
+
* ROLL BACK a concurrent raise; the same call is the ModuleUnknown existence
|
|
198
|
+
* gate. Title/metadata come from FETCH_MODULES_FOR_UPDATE (the chain stores
|
|
199
|
+
* only {answerHash, payout, exists} — metadata is event-only) with an IPFS
|
|
200
|
+
* fallback. Metadata is re-pinned ONLY when its content actually changes —
|
|
201
|
+
* same key order as create ({name, description, link, quiz, answers}).
|
|
202
|
+
*
|
|
203
|
+
* Requires ctx.provider (the on-chain getModule read).
|
|
204
|
+
*/
|
|
205
|
+
async function updateModuleIntent(ctx, params) {
|
|
206
|
+
// ── 0. Fail fast on input problems before any network work ─────────
|
|
207
|
+
const metadataChanging = params.name !== undefined
|
|
208
|
+
|| params.description !== undefined
|
|
209
|
+
|| params.link !== undefined
|
|
210
|
+
|| params.quiz !== undefined
|
|
211
|
+
|| params.answers !== undefined;
|
|
212
|
+
const payoutChanging = params.payout !== undefined;
|
|
213
|
+
if (!metadataChanging && !payoutChanging) {
|
|
214
|
+
throw new errors_1.CliError('Nothing to update — pass at least one field flag.', exit_codes_1.EXIT.USAGE, 'Available: --payout, --name, --description, --link, --quiz, --answers');
|
|
215
|
+
}
|
|
216
|
+
if (payoutChanging && (!(params.payout > 0) || !isFinite(params.payout))) {
|
|
217
|
+
throw new errors_1.CliError(`--payout must be a positive number (the contract reverts InvalidPayout for 0), got: ${params.payout}`, exit_codes_1.EXIT.USAGE);
|
|
218
|
+
}
|
|
219
|
+
if (!ctx.provider) {
|
|
220
|
+
throw new errors_1.CliError('updateModuleIntent requires ctx.provider (on-chain getModule read — see the payout note above)', exit_codes_1.EXIT.USAGE);
|
|
221
|
+
}
|
|
222
|
+
const modules = await (0, resolve_1.resolveOrgModules)(ctx.client, params.org, ctx.chainId);
|
|
223
|
+
const educationHubAddress = (0, resolve_1.requireModule)(modules, 'educationHubAddress');
|
|
224
|
+
const moduleId = (0, encoding_1.parseModuleId)(params.module);
|
|
225
|
+
// ── 1+2. READ: on-chain payout/existence AND the indexed metadata ──
|
|
226
|
+
const hub = (0, contracts_1.createReadContract)(educationHubAddress, 'EducationHubNew', ctx.provider);
|
|
227
|
+
const [chainRead, indexedRead] = await Promise.allSettled([
|
|
228
|
+
hub.getModule(moduleId),
|
|
229
|
+
ctx.client.query(education_2.FETCH_MODULES_FOR_UPDATE, { orgId: modules.orgId }, ctx.chainId),
|
|
230
|
+
]);
|
|
231
|
+
if (chainRead.status === 'rejected') {
|
|
232
|
+
throw new errors_1.PreconditionError(`Could not read module ${moduleId} on-chain — it may not exist (getModule reverts ModuleUnknown).`, 'List modules with: pop education list');
|
|
233
|
+
}
|
|
234
|
+
const currentPayout = chainRead.value[0];
|
|
235
|
+
// Subgraph unavailable — handled below based on what the merge needs.
|
|
236
|
+
let subgraphModule = null;
|
|
237
|
+
if (indexedRead.status === 'fulfilled') {
|
|
238
|
+
const rows = indexedRead.value.organization?.educationHub?.modules || [];
|
|
239
|
+
subgraphModule = rows.find((m) => String(m.moduleId) === String(moduleId)) || null;
|
|
240
|
+
}
|
|
241
|
+
let ipfsMetadata = null;
|
|
242
|
+
const currentCid = subgraphModule?.contentHash ? (0, encoding_1.bytes32ToIpfsCid)(subgraphModule.contentHash) : null;
|
|
243
|
+
if (currentCid) {
|
|
244
|
+
try {
|
|
245
|
+
ipfsMetadata = await (0, ipfs_1.fetchJson)(currentCid, ctx.ipfs);
|
|
246
|
+
}
|
|
247
|
+
catch { /* IPFS lag — fall back to subgraph fields */ }
|
|
248
|
+
}
|
|
249
|
+
const currentName = ipfsMetadata?.name ?? subgraphModule?.title ?? undefined;
|
|
250
|
+
const currentDescription = ipfsMetadata?.description ?? subgraphModule?.metadata?.description ?? undefined;
|
|
251
|
+
const currentLink = ipfsMetadata?.link ?? subgraphModule?.metadata?.link ?? undefined;
|
|
252
|
+
const currentQuiz = ipfsMetadata?.quiz ?? subgraphModule?.metadata?.quiz ?? undefined;
|
|
253
|
+
let currentAnswers = ipfsMetadata?.answers;
|
|
254
|
+
if (currentAnswers === undefined && subgraphModule?.metadata?.answersJson) {
|
|
255
|
+
try {
|
|
256
|
+
currentAnswers = JSON.parse(subgraphModule.metadata.answersJson);
|
|
257
|
+
}
|
|
258
|
+
catch { /* unparseable — treated as unknown */ }
|
|
259
|
+
}
|
|
260
|
+
const currentContentHash = subgraphModule?.contentHash ?? undefined;
|
|
261
|
+
// updateModule overwrites title + contentHash even when only payout
|
|
262
|
+
// changed — so the current values must be recoverable.
|
|
263
|
+
if (!metadataChanging && (currentName === undefined || !currentContentHash)) {
|
|
264
|
+
throw new errors_1.CliError(`Module ${moduleId} metadata is not indexed yet (subgraph lag) — cannot preserve the current title/metadata through a full-overwrite update.`, exit_codes_1.EXIT.INFRA, 'Retry in a few seconds, or pass --name and --description explicitly.');
|
|
265
|
+
}
|
|
266
|
+
if (metadataChanging
|
|
267
|
+
&& (params.name === undefined || params.description === undefined)
|
|
268
|
+
&& (currentName === undefined || currentDescription === undefined)) {
|
|
269
|
+
throw new errors_1.CliError(`Module ${moduleId} metadata is not indexed yet (subgraph lag) — cannot merge a partial metadata edit.`, exit_codes_1.EXIT.INFRA, 'Retry in a few seconds, or pass BOTH --name and --description.');
|
|
270
|
+
}
|
|
271
|
+
// ── 3. MERGE: passed fields override, everything else preserved ────
|
|
272
|
+
const finalPayout = payoutChanging
|
|
273
|
+
? ethers_1.ethers.utils.parseUnits(params.payout.toString(), 18)
|
|
274
|
+
: currentPayout;
|
|
275
|
+
const finalName = params.name ?? currentName ?? '';
|
|
276
|
+
const finalDescription = params.description ?? currentDescription ?? '';
|
|
277
|
+
const finalLink = params.link ?? currentLink ?? '';
|
|
278
|
+
const finalQuiz = params.quiz ?? currentQuiz ?? [];
|
|
279
|
+
const finalAnswers = params.answers ?? currentAnswers ?? [];
|
|
280
|
+
if (finalQuiz.length > 0 && finalAnswers.length > 0 && finalQuiz.length !== finalAnswers.length) {
|
|
281
|
+
throw new errors_1.CliError(`Quiz has ${finalQuiz.length} questions but ${finalAnswers.length} answer sets. They must match.`, exit_codes_1.EXIT.USAGE);
|
|
282
|
+
}
|
|
283
|
+
// Re-pin only when the metadata content actually changes.
|
|
284
|
+
let finalContentHash = currentContentHash
|
|
285
|
+
? currentContentHash
|
|
286
|
+
: ethers_1.ethers.constants.HashZero;
|
|
287
|
+
let newCid;
|
|
288
|
+
let metadataDoc;
|
|
289
|
+
const metadataActuallyChanged = metadataChanging && (finalName !== currentName
|
|
290
|
+
|| finalDescription !== (currentDescription ?? '')
|
|
291
|
+
|| finalLink !== (currentLink ?? '')
|
|
292
|
+
|| JSON.stringify(finalQuiz) !== JSON.stringify(currentQuiz ?? [])
|
|
293
|
+
|| JSON.stringify(finalAnswers) !== JSON.stringify(currentAnswers ?? []));
|
|
294
|
+
if (metadataActuallyChanged) {
|
|
295
|
+
// NOTE (CLI warns here): when neither IPFS nor the subgraph could supply
|
|
296
|
+
// the current metadata, unspecified fields reset to defaults in the
|
|
297
|
+
// re-pinned JSON.
|
|
298
|
+
// Key order MUST match metadata/education.ts (frontend/subgraph parity).
|
|
299
|
+
metadataDoc = (0, education_1.buildEducationModuleMetadata)({
|
|
300
|
+
name: finalName,
|
|
301
|
+
description: finalDescription,
|
|
302
|
+
link: finalLink,
|
|
303
|
+
quiz: finalQuiz,
|
|
304
|
+
answers: finalAnswers,
|
|
305
|
+
});
|
|
306
|
+
newCid = await (0, ipfs_1.pinJson)((0, education_1.serializeEducationModuleMetadata)(metadataDoc), ctx.ipfs);
|
|
307
|
+
finalContentHash = (0, encoding_1.ipfsCidToBytes32)(newCid);
|
|
308
|
+
}
|
|
309
|
+
const intent = buildUpdateModule({
|
|
310
|
+
educationHubAddress,
|
|
311
|
+
moduleId,
|
|
312
|
+
name: finalName,
|
|
313
|
+
contentHash: finalContentHash,
|
|
314
|
+
payoutWei: finalPayout,
|
|
315
|
+
orgId: modules.orgId,
|
|
316
|
+
});
|
|
317
|
+
intent.meta.summary.metadataChanged = metadataActuallyChanged;
|
|
318
|
+
if (newCid)
|
|
319
|
+
intent.meta.ipfs = { cid: newCid, metadata: metadataDoc };
|
|
320
|
+
return intent;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Resolved builder for `pop education remove` — src/commands/education/remove.ts.
|
|
324
|
+
* Resolves the org's EducationHub, fetches a best-effort title for the
|
|
325
|
+
* confirmation summary (subgraph may lag — never blocks), and delegates to
|
|
326
|
+
* buildRemoveModule. DESTRUCTIVE: hosts should require explicit confirmation.
|
|
327
|
+
*/
|
|
328
|
+
async function removeModuleIntent(ctx, params) {
|
|
329
|
+
const modules = await (0, resolve_1.resolveOrgModules)(ctx.client, params.org, ctx.chainId);
|
|
330
|
+
const educationHubAddress = (0, resolve_1.requireModule)(modules, 'educationHubAddress');
|
|
331
|
+
const moduleId = (0, encoding_1.parseModuleId)(params.module);
|
|
332
|
+
// Best-effort title for the confirmation summary (subgraph may lag).
|
|
333
|
+
let title;
|
|
334
|
+
try {
|
|
335
|
+
title = await (0, education_2.getModuleTitle)(ctx.client, modules.orgId, moduleId, ctx.chainId);
|
|
336
|
+
}
|
|
337
|
+
catch { /* confirm falls back to the bare ID */ }
|
|
338
|
+
return buildRemoveModule({
|
|
339
|
+
educationHubAddress,
|
|
340
|
+
moduleId,
|
|
341
|
+
orgId: modules.orgId,
|
|
342
|
+
title,
|
|
343
|
+
});
|
|
344
|
+
}
|