@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,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paymaster reads — PaymasterHub infrastructure resolution + org sponsorship
|
|
3
|
+
* state. Port of src/commands/paymaster/helpers.ts (client-injected) plus the
|
|
4
|
+
* pure epoch helper from src/commands/paymaster/status.ts.
|
|
5
|
+
*
|
|
6
|
+
* The PaymasterHub is a singleton shared across all orgs (one proxy per
|
|
7
|
+
* chain), so its address comes from the infrastructure query, not the org's
|
|
8
|
+
* module list.
|
|
9
|
+
*
|
|
10
|
+
* ── Where the numbers come from (KEEP — verified field-by-field) ────────────
|
|
11
|
+
* ENTRY_POINT, the OrgConfig, the fee caps and EVERY budget come from the
|
|
12
|
+
* subgraph (see graph/documents/paymaster.ts for the field-by-field
|
|
13
|
+
* verification against both live deployments). Three things deliberately
|
|
14
|
+
* STAY ON RPC — the schema has fields for some of them, but the VALUES are
|
|
15
|
+
* wrong on live rows:
|
|
16
|
+
* • getOrgFinancials — PaymasterOrgConfig.totalSpent/.depositBalance are
|
|
17
|
+
* indexed WITHOUT the 1.01x solidarity fee the hub also debits, so they
|
|
18
|
+
* sit at exactly 1/1.01 of the contract's `spent` on both live chains
|
|
19
|
+
* (proven to the wei on Gnosis and Arbitrum). `available` decides whether
|
|
20
|
+
* sponsorship still works, so it must be the chain's number. The call also
|
|
21
|
+
* carries solidarityUsedThisPeriod + periodStart, which have no subgraph
|
|
22
|
+
* field at all.
|
|
23
|
+
* • getSolidarityFund — numActiveOrgs and feePercentageBps have no field,
|
|
24
|
+
* the indexed solidarityBalance is stale on Gnosis (6376552300000000 wei
|
|
25
|
+
* high), and solidarityDistributionPaused reads `false` on Arbitrum while
|
|
26
|
+
* the contract reports `true`.
|
|
27
|
+
* • EntryPoint.balanceOf — the ERC-4337 singleton is not a subgraph data
|
|
28
|
+
* source.
|
|
29
|
+
*
|
|
30
|
+
* Two ways to read an org's paymaster config, and the difference matters:
|
|
31
|
+
*
|
|
32
|
+
* readPaymasterOrgConfig() — authoritative eth_call. Use it
|
|
33
|
+
* wherever the answer decides whether a transaction gets broadcast
|
|
34
|
+
* (deposit's OrgNotRegistered gate). Subgraph lag there means knowingly
|
|
35
|
+
* sending a doomed tx.
|
|
36
|
+
* readPaymasterOrgConfigPreferSubgraph() — subgraph first, but ONLY trusts a
|
|
37
|
+
* POSITIVE "registered" answer; a negative one is always re-confirmed on
|
|
38
|
+
* chain before anything is written. The subgraph can lag behind a fresh
|
|
39
|
+
* registration, it can never invent one, so a positive is safe to trust and
|
|
40
|
+
* a negative is not.
|
|
41
|
+
*/
|
|
42
|
+
import { ethers } from 'ethers';
|
|
43
|
+
import type { GraphClient } from '../graph/client';
|
|
44
|
+
export interface PaymasterInfra {
|
|
45
|
+
paymasterHubAddress: string;
|
|
46
|
+
poaManagerAddress: string | null;
|
|
47
|
+
}
|
|
48
|
+
/** Resolve the chain's PaymasterHub proxy (+ PoaManager) from the subgraph. */
|
|
49
|
+
export declare function resolvePaymasterInfra(client: GraphClient, chainId?: number): Promise<PaymasterInfra>;
|
|
50
|
+
export interface PaymasterOrgConfig {
|
|
51
|
+
adminHatId: ethers.BigNumber;
|
|
52
|
+
operatorHatId: ethers.BigNumber;
|
|
53
|
+
paused: boolean;
|
|
54
|
+
registeredAt: number;
|
|
55
|
+
bannedFromSolidarity: boolean;
|
|
56
|
+
registered: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** Fee caps in raw contract units (wei per gas / gas units). */
|
|
59
|
+
export interface PaymasterFeeCaps {
|
|
60
|
+
maxFeePerGas: ethers.BigNumber;
|
|
61
|
+
maxPriorityFeePerGas: ethers.BigNumber;
|
|
62
|
+
maxCallGas: number;
|
|
63
|
+
maxVerificationGas: number;
|
|
64
|
+
maxPreVerificationGas: number;
|
|
65
|
+
}
|
|
66
|
+
/** One budget row as the subgraph has it. `totalUsed` is null on the legacy tier. */
|
|
67
|
+
export interface PaymasterBudgetRecord {
|
|
68
|
+
subjectKey: string;
|
|
69
|
+
capPerEpoch: ethers.BigNumber;
|
|
70
|
+
usedInEpoch: ethers.BigNumber;
|
|
71
|
+
epochLen: number;
|
|
72
|
+
epochStart: number;
|
|
73
|
+
totalUsed: ethers.BigNumber | null;
|
|
74
|
+
}
|
|
75
|
+
export interface PaymasterSubgraphState {
|
|
76
|
+
/** Hub address the indexer knows about — cross-check before trusting the rest. */
|
|
77
|
+
hubAddress: string | null;
|
|
78
|
+
/** Checksummed to match what ENTRY_POINT() would have returned. */
|
|
79
|
+
entryPoint: string | null;
|
|
80
|
+
orgConfig: PaymasterOrgConfig | null;
|
|
81
|
+
/**
|
|
82
|
+
* All-zero when the org row exists but has no PaymasterFeeCaps edge — that is
|
|
83
|
+
* the contract's "never configured" default, verified against getFeeCaps() on
|
|
84
|
+
* five orgs across both live deployments. Null only when the org row itself is
|
|
85
|
+
* missing, in which case the caller must fall back to RPC.
|
|
86
|
+
*/
|
|
87
|
+
feeCaps: PaymasterFeeCaps | null;
|
|
88
|
+
/** Null (not empty) when the org row is missing, so "no budgets" stays distinguishable. */
|
|
89
|
+
budgets: PaymasterBudgetRecord[] | null;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Read the hub state the subgraph can serve accurately: the immutable
|
|
93
|
+
* ENTRY_POINT, the org's OrgConfig, its fee caps and ALL of its budgets.
|
|
94
|
+
* Subgraph half of `pop paymaster status` (src/commands/paymaster/status.ts).
|
|
95
|
+
*
|
|
96
|
+
* Never throws — every failure (unreachable subgraph, chain with no deployment,
|
|
97
|
+
* unindexed org) degrades to nulls so the caller falls back to eth_calls.
|
|
98
|
+
*
|
|
99
|
+
* Financials and the solidarity fund are deliberately NOT here; see the module
|
|
100
|
+
* header for the measurements that disqualified them.
|
|
101
|
+
*/
|
|
102
|
+
export declare function fetchPaymasterSubgraphState(client: GraphClient, orgId: string, chainId?: number): Promise<PaymasterSubgraphState>;
|
|
103
|
+
/**
|
|
104
|
+
* True when the indexed hub is the hub we independently resolved. A mismatch
|
|
105
|
+
* (redeployed hub the indexer has not caught up with, a hand-set
|
|
106
|
+
* POP_*_SUBGRAPH pointing at another network) means the org row describes a
|
|
107
|
+
* different contract, so the caller must ignore the whole state object.
|
|
108
|
+
*/
|
|
109
|
+
export declare function subgraphMatchesHub(state: PaymasterSubgraphState, hubAddress: string): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Read the hub's OrgConfig for an org. `registered` is derived the same way
|
|
112
|
+
* the contract does it (adminHatId != 0 — see PaymasterHub._registerOrg).
|
|
113
|
+
*
|
|
114
|
+
* Authoritative eth_call. Keep using this one for revert-predicting gates.
|
|
115
|
+
*/
|
|
116
|
+
export declare function readPaymasterOrgConfig(provider: ethers.providers.Provider, hubAddress: string, orgId: string): Promise<PaymasterOrgConfig>;
|
|
117
|
+
/**
|
|
118
|
+
* Registration read for callers that may go on to WRITE.
|
|
119
|
+
*
|
|
120
|
+
* Asymmetric on purpose: an indexed registration is trusted (saves the eth_call
|
|
121
|
+
* on the common "already registered" path), an absent one is re-read on chain
|
|
122
|
+
* before any decision is made. The subgraph only ever lags reality, so a
|
|
123
|
+
* false-negative is possible and a false-positive is not — re-confirming just
|
|
124
|
+
* the negative keeps revert prediction exactly as strong as pure RPC.
|
|
125
|
+
*/
|
|
126
|
+
export declare function readPaymasterOrgConfigPreferSubgraph(client: GraphClient, provider: ethers.providers.Provider, hubAddress: string, orgId: string, chainId?: number): Promise<{
|
|
127
|
+
config: PaymasterOrgConfig;
|
|
128
|
+
source: 'subgraph' | 'rpc';
|
|
129
|
+
}>;
|
|
130
|
+
/** Subject key for a hat-scoped paymaster budget: the hat ID as bytes32. */
|
|
131
|
+
export declare function hatSubjectKey(hatId: ethers.BigNumberish): string;
|
|
132
|
+
/**
|
|
133
|
+
* Has this budget's epoch elapsed? Pure port of budgetEpochState from
|
|
134
|
+
* src/commands/paymaster/status.ts.
|
|
135
|
+
*
|
|
136
|
+
* PaymasterHub resets `usedInEpoch` LAZILY, on the next sponsored
|
|
137
|
+
* UserOperation, so a budget whose epoch elapsed months ago still reports the
|
|
138
|
+
* old spend — and getBudget() returns exactly the same stale figure the
|
|
139
|
+
* subgraph does (verified: both return 7993482525000000 for a Gnosis epoch
|
|
140
|
+
* that ended in May). Rather than present a stale number as current spend,
|
|
141
|
+
* check each row against epochStart + epochLen and report it as lapsed, with
|
|
142
|
+
* the effective (post-reset) spend of zero alongside the raw counter.
|
|
143
|
+
*/
|
|
144
|
+
export declare function budgetEpochState(epochStart: number, epochLen: number, now: number): {
|
|
145
|
+
epochEnd: number | null;
|
|
146
|
+
expired: boolean;
|
|
147
|
+
};
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Paymaster reads — PaymasterHub infrastructure resolution + org sponsorship
|
|
4
|
+
* state. Port of src/commands/paymaster/helpers.ts (client-injected) plus the
|
|
5
|
+
* pure epoch helper from src/commands/paymaster/status.ts.
|
|
6
|
+
*
|
|
7
|
+
* The PaymasterHub is a singleton shared across all orgs (one proxy per
|
|
8
|
+
* chain), so its address comes from the infrastructure query, not the org's
|
|
9
|
+
* module list.
|
|
10
|
+
*
|
|
11
|
+
* ── Where the numbers come from (KEEP — verified field-by-field) ────────────
|
|
12
|
+
* ENTRY_POINT, the OrgConfig, the fee caps and EVERY budget come from the
|
|
13
|
+
* subgraph (see graph/documents/paymaster.ts for the field-by-field
|
|
14
|
+
* verification against both live deployments). Three things deliberately
|
|
15
|
+
* STAY ON RPC — the schema has fields for some of them, but the VALUES are
|
|
16
|
+
* wrong on live rows:
|
|
17
|
+
* • getOrgFinancials — PaymasterOrgConfig.totalSpent/.depositBalance are
|
|
18
|
+
* indexed WITHOUT the 1.01x solidarity fee the hub also debits, so they
|
|
19
|
+
* sit at exactly 1/1.01 of the contract's `spent` on both live chains
|
|
20
|
+
* (proven to the wei on Gnosis and Arbitrum). `available` decides whether
|
|
21
|
+
* sponsorship still works, so it must be the chain's number. The call also
|
|
22
|
+
* carries solidarityUsedThisPeriod + periodStart, which have no subgraph
|
|
23
|
+
* field at all.
|
|
24
|
+
* • getSolidarityFund — numActiveOrgs and feePercentageBps have no field,
|
|
25
|
+
* the indexed solidarityBalance is stale on Gnosis (6376552300000000 wei
|
|
26
|
+
* high), and solidarityDistributionPaused reads `false` on Arbitrum while
|
|
27
|
+
* the contract reports `true`.
|
|
28
|
+
* • EntryPoint.balanceOf — the ERC-4337 singleton is not a subgraph data
|
|
29
|
+
* source.
|
|
30
|
+
*
|
|
31
|
+
* Two ways to read an org's paymaster config, and the difference matters:
|
|
32
|
+
*
|
|
33
|
+
* readPaymasterOrgConfig() — authoritative eth_call. Use it
|
|
34
|
+
* wherever the answer decides whether a transaction gets broadcast
|
|
35
|
+
* (deposit's OrgNotRegistered gate). Subgraph lag there means knowingly
|
|
36
|
+
* sending a doomed tx.
|
|
37
|
+
* readPaymasterOrgConfigPreferSubgraph() — subgraph first, but ONLY trusts a
|
|
38
|
+
* POSITIVE "registered" answer; a negative one is always re-confirmed on
|
|
39
|
+
* chain before anything is written. The subgraph can lag behind a fresh
|
|
40
|
+
* registration, it can never invent one, so a positive is safe to trust and
|
|
41
|
+
* a negative is not.
|
|
42
|
+
*/
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.resolvePaymasterInfra = resolvePaymasterInfra;
|
|
45
|
+
exports.fetchPaymasterSubgraphState = fetchPaymasterSubgraphState;
|
|
46
|
+
exports.subgraphMatchesHub = subgraphMatchesHub;
|
|
47
|
+
exports.readPaymasterOrgConfig = readPaymasterOrgConfig;
|
|
48
|
+
exports.readPaymasterOrgConfigPreferSubgraph = readPaymasterOrgConfigPreferSubgraph;
|
|
49
|
+
exports.hatSubjectKey = hatSubjectKey;
|
|
50
|
+
exports.budgetEpochState = budgetEpochState;
|
|
51
|
+
const ethers_1 = require("ethers");
|
|
52
|
+
const infrastructure_1 = require("../graph/documents/infrastructure");
|
|
53
|
+
const paymaster_1 = require("../graph/documents/paymaster");
|
|
54
|
+
const contracts_1 = require("../contracts");
|
|
55
|
+
const errors_1 = require("../errors");
|
|
56
|
+
/** Resolve the chain's PaymasterHub proxy (+ PoaManager) from the subgraph. */
|
|
57
|
+
async function resolvePaymasterInfra(client, chainId) {
|
|
58
|
+
const infra = await client.query(infrastructure_1.FETCH_INFRASTRUCTURE_ADDRESSES, {}, chainId);
|
|
59
|
+
const record = infra.poaManagerContracts?.[0];
|
|
60
|
+
const paymasterHubAddress = record?.paymasterHubProxy;
|
|
61
|
+
if (!paymasterHubAddress) {
|
|
62
|
+
throw new errors_1.PreconditionError('PaymasterHub not indexed for this chain.', 'The subgraph may still be syncing, or gas sponsorship is not deployed on this chain.');
|
|
63
|
+
}
|
|
64
|
+
return { paymasterHubAddress, poaManagerAddress: record?.id ?? null };
|
|
65
|
+
}
|
|
66
|
+
const EMPTY_STATE = {
|
|
67
|
+
hubAddress: null,
|
|
68
|
+
entryPoint: null,
|
|
69
|
+
orgConfig: null,
|
|
70
|
+
feeCaps: null,
|
|
71
|
+
budgets: null,
|
|
72
|
+
};
|
|
73
|
+
const ZERO_FEE_CAPS = {
|
|
74
|
+
maxFeePerGas: ethers_1.ethers.BigNumber.from(0),
|
|
75
|
+
maxPriorityFeePerGas: ethers_1.ethers.BigNumber.from(0),
|
|
76
|
+
maxCallGas: 0,
|
|
77
|
+
maxVerificationGas: 0,
|
|
78
|
+
maxPreVerificationGas: 0,
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Read the hub state the subgraph can serve accurately: the immutable
|
|
82
|
+
* ENTRY_POINT, the org's OrgConfig, its fee caps and ALL of its budgets.
|
|
83
|
+
* Subgraph half of `pop paymaster status` (src/commands/paymaster/status.ts).
|
|
84
|
+
*
|
|
85
|
+
* Never throws — every failure (unreachable subgraph, chain with no deployment,
|
|
86
|
+
* unindexed org) degrades to nulls so the caller falls back to eth_calls.
|
|
87
|
+
*
|
|
88
|
+
* Financials and the solidarity fund are deliberately NOT here; see the module
|
|
89
|
+
* header for the measurements that disqualified them.
|
|
90
|
+
*/
|
|
91
|
+
async function fetchPaymasterSubgraphState(client, orgId, chainId) {
|
|
92
|
+
let data;
|
|
93
|
+
try {
|
|
94
|
+
const result = await client.queryWithFieldFallback(paymaster_1.FETCH_PAYMASTER_STATE_TIERS.map(q => ({ query: q, variables: { orgId: orgId.toLowerCase() } })), { chainId });
|
|
95
|
+
data = result.data;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return EMPTY_STATE;
|
|
99
|
+
}
|
|
100
|
+
const hub = data?.paymasterHubContracts?.[0];
|
|
101
|
+
const row = data?.paymasterOrgConfigs?.[0];
|
|
102
|
+
let entryPoint = null;
|
|
103
|
+
if (hub?.entryPoint) {
|
|
104
|
+
// The subgraph stores Bytes lowercased; ENTRY_POINT() returns a checksummed
|
|
105
|
+
// address. Re-checksum so output is byte-identical either way.
|
|
106
|
+
try {
|
|
107
|
+
const checksummed = ethers_1.ethers.utils.getAddress(hub.entryPoint);
|
|
108
|
+
// The zero address is a documented PLACEHOLDER, not an answer. The mapping
|
|
109
|
+
// seeds hub.entryPoint = Address.zero() in getOrCreateHub, and the deploy
|
|
110
|
+
// path only fills it via a try_ENTRY_POINT() call that falls back to zero
|
|
111
|
+
// (PaymasterInitialized fires before InfrastructureDeployed, so
|
|
112
|
+
// handlePaymasterInitialized never runs for the initial deploy).
|
|
113
|
+
//
|
|
114
|
+
// getAddress() happily accepts it, so without this guard a placeholder
|
|
115
|
+
// becomes a non-null `entryPoint` that callers then use as an eth_call
|
|
116
|
+
// TARGET: balanceOf against address(0) returns '0x' and decoding throws
|
|
117
|
+
// CALL_EXCEPTION. null makes callers fall back to the ENTRY_POINT() read.
|
|
118
|
+
entryPoint = checksummed === ethers_1.ethers.constants.AddressZero ? null : checksummed;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
entryPoint = null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (!row) {
|
|
125
|
+
return { ...EMPTY_STATE, hubAddress: hub?.id ?? null, entryPoint };
|
|
126
|
+
}
|
|
127
|
+
let orgConfig = null;
|
|
128
|
+
try {
|
|
129
|
+
const adminHatId = ethers_1.ethers.BigNumber.from(row.adminHatId);
|
|
130
|
+
orgConfig = {
|
|
131
|
+
adminHatId,
|
|
132
|
+
operatorHatId: ethers_1.ethers.BigNumber.from(row.operatorHatId),
|
|
133
|
+
paused: Boolean(row.isPaused),
|
|
134
|
+
registeredAt: Number(row.registeredAt ?? 0) || 0,
|
|
135
|
+
bannedFromSolidarity: Boolean(row.isBannedFromSolidarity),
|
|
136
|
+
// Derived exactly like PaymasterHub._registerOrg does it.
|
|
137
|
+
registered: !adminHatId.isZero(),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return { ...EMPTY_STATE, hubAddress: hub?.id ?? null, entryPoint };
|
|
142
|
+
}
|
|
143
|
+
const feeCaps = row.feeCaps
|
|
144
|
+
? {
|
|
145
|
+
maxFeePerGas: ethers_1.ethers.BigNumber.from(row.feeCaps.maxFeePerGas),
|
|
146
|
+
maxPriorityFeePerGas: ethers_1.ethers.BigNumber.from(row.feeCaps.maxPriorityFeePerGas),
|
|
147
|
+
maxCallGas: Number(row.feeCaps.maxCallGas ?? 0),
|
|
148
|
+
maxVerificationGas: Number(row.feeCaps.maxVerificationGas ?? 0),
|
|
149
|
+
maxPreVerificationGas: Number(row.feeCaps.maxPreVerificationGas ?? 0),
|
|
150
|
+
}
|
|
151
|
+
: ZERO_FEE_CAPS;
|
|
152
|
+
const budgets = (row.budgets ?? []).map(b => ({
|
|
153
|
+
subjectKey: b.subjectKey,
|
|
154
|
+
capPerEpoch: ethers_1.ethers.BigNumber.from(b.capPerEpoch),
|
|
155
|
+
usedInEpoch: ethers_1.ethers.BigNumber.from(b.usedInEpoch),
|
|
156
|
+
epochLen: Number(b.epochLen ?? 0),
|
|
157
|
+
epochStart: Number(b.epochStart ?? 0),
|
|
158
|
+
totalUsed: b.totalUsed !== undefined && b.totalUsed !== null
|
|
159
|
+
? ethers_1.ethers.BigNumber.from(b.totalUsed)
|
|
160
|
+
: null,
|
|
161
|
+
}));
|
|
162
|
+
return {
|
|
163
|
+
hubAddress: row.paymasterHub?.id ?? hub?.id ?? null,
|
|
164
|
+
entryPoint,
|
|
165
|
+
orgConfig,
|
|
166
|
+
feeCaps,
|
|
167
|
+
budgets,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* True when the indexed hub is the hub we independently resolved. A mismatch
|
|
172
|
+
* (redeployed hub the indexer has not caught up with, a hand-set
|
|
173
|
+
* POP_*_SUBGRAPH pointing at another network) means the org row describes a
|
|
174
|
+
* different contract, so the caller must ignore the whole state object.
|
|
175
|
+
*/
|
|
176
|
+
function subgraphMatchesHub(state, hubAddress) {
|
|
177
|
+
return !!state.hubAddress && state.hubAddress.toLowerCase() === hubAddress.toLowerCase();
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Read the hub's OrgConfig for an org. `registered` is derived the same way
|
|
181
|
+
* the contract does it (adminHatId != 0 — see PaymasterHub._registerOrg).
|
|
182
|
+
*
|
|
183
|
+
* Authoritative eth_call. Keep using this one for revert-predicting gates.
|
|
184
|
+
*/
|
|
185
|
+
async function readPaymasterOrgConfig(provider, hubAddress, orgId) {
|
|
186
|
+
const hub = (0, contracts_1.createReadContract)(hubAddress, 'PaymasterHub', provider);
|
|
187
|
+
const cfg = await hub.getOrgConfig(orgId);
|
|
188
|
+
const adminHatId = ethers_1.ethers.BigNumber.from(cfg.adminHatId);
|
|
189
|
+
return {
|
|
190
|
+
adminHatId,
|
|
191
|
+
operatorHatId: ethers_1.ethers.BigNumber.from(cfg.operatorHatId),
|
|
192
|
+
paused: Boolean(cfg.paused),
|
|
193
|
+
registeredAt: Number(cfg.registeredAt ?? 0),
|
|
194
|
+
bannedFromSolidarity: Boolean(cfg.bannedFromSolidarity),
|
|
195
|
+
registered: !adminHatId.isZero(),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Registration read for callers that may go on to WRITE.
|
|
200
|
+
*
|
|
201
|
+
* Asymmetric on purpose: an indexed registration is trusted (saves the eth_call
|
|
202
|
+
* on the common "already registered" path), an absent one is re-read on chain
|
|
203
|
+
* before any decision is made. The subgraph only ever lags reality, so a
|
|
204
|
+
* false-negative is possible and a false-positive is not — re-confirming just
|
|
205
|
+
* the negative keeps revert prediction exactly as strong as pure RPC.
|
|
206
|
+
*/
|
|
207
|
+
async function readPaymasterOrgConfigPreferSubgraph(client, provider, hubAddress, orgId, chainId) {
|
|
208
|
+
const state = await fetchPaymasterSubgraphState(client, orgId, chainId);
|
|
209
|
+
if (state.orgConfig?.registered && subgraphMatchesHub(state, hubAddress)) {
|
|
210
|
+
return { config: state.orgConfig, source: 'subgraph' };
|
|
211
|
+
}
|
|
212
|
+
return { config: await readPaymasterOrgConfig(provider, hubAddress, orgId), source: 'rpc' };
|
|
213
|
+
}
|
|
214
|
+
/** Subject key for a hat-scoped paymaster budget: the hat ID as bytes32. */
|
|
215
|
+
function hatSubjectKey(hatId) {
|
|
216
|
+
return ethers_1.ethers.utils.hexZeroPad(ethers_1.ethers.BigNumber.from(hatId).toHexString(), 32);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Has this budget's epoch elapsed? Pure port of budgetEpochState from
|
|
220
|
+
* src/commands/paymaster/status.ts.
|
|
221
|
+
*
|
|
222
|
+
* PaymasterHub resets `usedInEpoch` LAZILY, on the next sponsored
|
|
223
|
+
* UserOperation, so a budget whose epoch elapsed months ago still reports the
|
|
224
|
+
* old spend — and getBudget() returns exactly the same stale figure the
|
|
225
|
+
* subgraph does (verified: both return 7993482525000000 for a Gnosis epoch
|
|
226
|
+
* that ended in May). Rather than present a stale number as current spend,
|
|
227
|
+
* check each row against epochStart + epochLen and report it as lapsed, with
|
|
228
|
+
* the effective (post-reset) spend of zero alongside the raw counter.
|
|
229
|
+
*/
|
|
230
|
+
function budgetEpochState(epochStart, epochLen, now) {
|
|
231
|
+
if (!epochLen || !epochStart)
|
|
232
|
+
return { epochEnd: null, expired: false };
|
|
233
|
+
const epochEnd = epochStart + epochLen;
|
|
234
|
+
return { epochEnd, expired: now >= epochEnd };
|
|
235
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-domain subgraph reads and project-id resolution.
|
|
3
|
+
*
|
|
4
|
+
* Ports the read path of `pop project list` (src/commands/project/list.ts) and
|
|
5
|
+
* the project-input resolver shared by `pop project delete`
|
|
6
|
+
* (src/commands/project/delete.ts resolveProjectInput) onto the injected
|
|
7
|
+
* GraphClient. Projects live under the task domain's FETCH_PROJECTS_DATA
|
|
8
|
+
* document — there is no separate projects query.
|
|
9
|
+
*/
|
|
10
|
+
import type { GraphClient } from '../graph/client';
|
|
11
|
+
import type { SubgraphProject } from './task';
|
|
12
|
+
/**
|
|
13
|
+
* List an org's (non-deleted) projects, tasks included.
|
|
14
|
+
* Port of the read at src/commands/project/list.ts:37 — a bare
|
|
15
|
+
* FETCH_PROJECTS_DATA query (no tier fallback; `pop project list` never used
|
|
16
|
+
* the deadline/release fields, so the base document always validates).
|
|
17
|
+
*/
|
|
18
|
+
export declare function listProjects(client: GraphClient, orgId: string, chainId?: number): Promise<SubgraphProject[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Resolve project input to the on-chain bytes32 pid:
|
|
21
|
+
* bytes32 hex and subgraph composite IDs resolve locally; a plain decimal
|
|
22
|
+
* maps to bytes32(uint) (on-chain pids are counters — verified against
|
|
23
|
+
* _createProjectCore in TaskManager.sol); anything else is treated as a
|
|
24
|
+
* project title and matched via the subgraph.
|
|
25
|
+
*
|
|
26
|
+
* Port of src/commands/project/delete.ts resolveProjectInput (same messages,
|
|
27
|
+
* same resolution order — note decimal beats title here, unlike task create's
|
|
28
|
+
* resolver which tries the title first).
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveProjectInput(client: GraphClient, input: string, orgId: string, chainId?: number): Promise<{
|
|
31
|
+
pid: string;
|
|
32
|
+
title?: string;
|
|
33
|
+
}>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Project-domain subgraph reads and project-id resolution.
|
|
4
|
+
*
|
|
5
|
+
* Ports the read path of `pop project list` (src/commands/project/list.ts) and
|
|
6
|
+
* the project-input resolver shared by `pop project delete`
|
|
7
|
+
* (src/commands/project/delete.ts resolveProjectInput) onto the injected
|
|
8
|
+
* GraphClient. Projects live under the task domain's FETCH_PROJECTS_DATA
|
|
9
|
+
* document — there is no separate projects query.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.listProjects = listProjects;
|
|
13
|
+
exports.resolveProjectInput = resolveProjectInput;
|
|
14
|
+
const ethers_1 = require("ethers");
|
|
15
|
+
const task_1 = require("../graph/documents/task");
|
|
16
|
+
const encoding_1 = require("../encoding");
|
|
17
|
+
const errors_1 = require("../errors");
|
|
18
|
+
const exit_codes_1 = require("../exit-codes");
|
|
19
|
+
/**
|
|
20
|
+
* List an org's (non-deleted) projects, tasks included.
|
|
21
|
+
* Port of the read at src/commands/project/list.ts:37 — a bare
|
|
22
|
+
* FETCH_PROJECTS_DATA query (no tier fallback; `pop project list` never used
|
|
23
|
+
* the deadline/release fields, so the base document always validates).
|
|
24
|
+
*/
|
|
25
|
+
async function listProjects(client, orgId, chainId) {
|
|
26
|
+
const result = await client.query(task_1.FETCH_PROJECTS_DATA, { orgId }, chainId);
|
|
27
|
+
return result.organization?.taskManager?.projects || [];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolve project input to the on-chain bytes32 pid:
|
|
31
|
+
* bytes32 hex and subgraph composite IDs resolve locally; a plain decimal
|
|
32
|
+
* maps to bytes32(uint) (on-chain pids are counters — verified against
|
|
33
|
+
* _createProjectCore in TaskManager.sol); anything else is treated as a
|
|
34
|
+
* project title and matched via the subgraph.
|
|
35
|
+
*
|
|
36
|
+
* Port of src/commands/project/delete.ts resolveProjectInput (same messages,
|
|
37
|
+
* same resolution order — note decimal beats title here, unlike task create's
|
|
38
|
+
* resolver which tries the title first).
|
|
39
|
+
*/
|
|
40
|
+
async function resolveProjectInput(client, input, orgId, chainId) {
|
|
41
|
+
if (input.startsWith('0x') && input.length === 66)
|
|
42
|
+
return { pid: input };
|
|
43
|
+
if (/^0x[a-fA-F0-9]{40}-/.test(input))
|
|
44
|
+
return { pid: (0, encoding_1.parseProjectId)(input) };
|
|
45
|
+
if (/^\d+$/.test(input)) {
|
|
46
|
+
return { pid: ethers_1.ethers.utils.hexZeroPad(ethers_1.ethers.BigNumber.from(input).toHexString(), 32) };
|
|
47
|
+
}
|
|
48
|
+
// Title lookup via the subgraph (case-insensitive).
|
|
49
|
+
let projects = [];
|
|
50
|
+
try {
|
|
51
|
+
const result = await client.query(task_1.FETCH_PROJECTS_DATA, { orgId }, chainId);
|
|
52
|
+
projects = result.organization?.taskManager?.projects || [];
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw new errors_1.CliError(`Could not resolve project "${input}" — the subgraph is unavailable for title lookup.`, exit_codes_1.EXIT.INFRA, 'Pass the 0x-prefixed bytes32 project ID instead (pop project list --json).');
|
|
56
|
+
}
|
|
57
|
+
const match = projects.find((p) => (p.title || '').toLowerCase() === input.toLowerCase());
|
|
58
|
+
if (match)
|
|
59
|
+
return { pid: (0, encoding_1.parseProjectId)(match.id), title: match.title ?? undefined };
|
|
60
|
+
const available = projects.map((p) => p.title).filter(Boolean).join(', ');
|
|
61
|
+
throw new errors_1.CliError(`Project "${input}" not found.`, exit_codes_1.EXIT.USAGE, `Available projects: ${available || 'none'} (or pass the 0x-prefixed bytes32 project ID).`);
|
|
62
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared org/contract resolution helpers.
|
|
3
|
+
* Single source of truth for resolving org names to IDs and fetching contract
|
|
4
|
+
* addresses. Port of src/lib/resolve.ts: functions take the GraphClient
|
|
5
|
+
* explicitly instead of importing a process-global one.
|
|
6
|
+
*/
|
|
7
|
+
import type { GraphClient } from '../graph/client';
|
|
8
|
+
/**
|
|
9
|
+
* Resolve an org identifier (name or hex ID) to its bytes32 ID.
|
|
10
|
+
* Throws a helpful error if org is not provided.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveOrgId(client: GraphClient, orgIdOrName: string | undefined, chainId?: number): Promise<string>;
|
|
13
|
+
export interface OrgModules {
|
|
14
|
+
orgId: string;
|
|
15
|
+
taskManagerAddress: string | null;
|
|
16
|
+
hybridVotingAddress: string | null;
|
|
17
|
+
ddVotingAddress: string | null;
|
|
18
|
+
participationTokenAddress: string | null;
|
|
19
|
+
educationHubAddress: string | null;
|
|
20
|
+
executorAddress: string | null;
|
|
21
|
+
quickJoinAddress: string | null;
|
|
22
|
+
eligibilityModuleAddress: string | null;
|
|
23
|
+
paymentManagerAddress: string | null;
|
|
24
|
+
/** ZkEmailInvites proxy — null for orgs deployed without the optional ZK Email module. */
|
|
25
|
+
zkEmailInvitesAddress: string | null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve an org's deployed module addresses via subgraph.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveOrgModules(client: GraphClient, orgIdOrName: string | undefined, chainId?: number): Promise<OrgModules>;
|
|
31
|
+
/**
|
|
32
|
+
* Require a specific module address, throwing a helpful error if not deployed.
|
|
33
|
+
*/
|
|
34
|
+
export declare function requireModule(modules: OrgModules, moduleName: keyof OrgModules): string;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared org/contract resolution helpers.
|
|
4
|
+
* Single source of truth for resolving org names to IDs and fetching contract
|
|
5
|
+
* addresses. Port of src/lib/resolve.ts: functions take the GraphClient
|
|
6
|
+
* explicitly instead of importing a process-global one.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.resolveOrgId = resolveOrgId;
|
|
10
|
+
exports.resolveOrgModules = resolveOrgModules;
|
|
11
|
+
exports.requireModule = requireModule;
|
|
12
|
+
const org_1 = require("../graph/documents/org");
|
|
13
|
+
/**
|
|
14
|
+
* Resolve an org identifier (name or hex ID) to its bytes32 ID.
|
|
15
|
+
* Throws a helpful error if org is not provided.
|
|
16
|
+
*/
|
|
17
|
+
async function resolveOrgId(client, orgIdOrName, chainId) {
|
|
18
|
+
if (!orgIdOrName) {
|
|
19
|
+
throw new Error('Missing --org flag. Provide --org or set POP_DEFAULT_ORG in .env');
|
|
20
|
+
}
|
|
21
|
+
if (orgIdOrName.startsWith('0x')) {
|
|
22
|
+
return orgIdOrName;
|
|
23
|
+
}
|
|
24
|
+
const result = await client.query(org_1.GET_ORG_BY_NAME, { name: orgIdOrName }, chainId);
|
|
25
|
+
if (!result.organizations?.length) {
|
|
26
|
+
throw new Error(`Organization "${orgIdOrName}" not found. Use the hex ID or check the org name.`);
|
|
27
|
+
}
|
|
28
|
+
return result.organizations[0].id;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolve an org's deployed module addresses via subgraph.
|
|
32
|
+
*/
|
|
33
|
+
async function resolveOrgModules(client, orgIdOrName, chainId) {
|
|
34
|
+
const orgId = await resolveOrgId(client, orgIdOrName, chainId);
|
|
35
|
+
const result = await client.query(org_1.FETCH_ORG_BY_ID, { id: orgId }, chainId);
|
|
36
|
+
if (!result.organization) {
|
|
37
|
+
throw new Error(`Organization ${orgId} not found on this chain`);
|
|
38
|
+
}
|
|
39
|
+
const org = result.organization;
|
|
40
|
+
return {
|
|
41
|
+
orgId: org.id,
|
|
42
|
+
taskManagerAddress: org.taskManager?.id || null,
|
|
43
|
+
hybridVotingAddress: org.hybridVoting?.id || null,
|
|
44
|
+
ddVotingAddress: org.directDemocracyVoting?.id || null,
|
|
45
|
+
participationTokenAddress: org.participationToken?.id || null,
|
|
46
|
+
educationHubAddress: org.educationHub?.id || null,
|
|
47
|
+
executorAddress: org.executorContract?.id || null,
|
|
48
|
+
quickJoinAddress: org.quickJoin?.id || null,
|
|
49
|
+
eligibilityModuleAddress: org.eligibilityModule?.id || null,
|
|
50
|
+
paymentManagerAddress: org.paymentManager?.id || null,
|
|
51
|
+
zkEmailInvitesAddress: org.zkEmailInvites?.id || null,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Require a specific module address, throwing a helpful error if not deployed.
|
|
56
|
+
*/
|
|
57
|
+
function requireModule(modules, moduleName) {
|
|
58
|
+
const addr = modules[moduleName];
|
|
59
|
+
if (!addr || typeof addr !== 'string') {
|
|
60
|
+
const friendlyName = moduleName.replace('Address', '').replace(/([A-Z])/g, ' $1').trim();
|
|
61
|
+
throw new Error(`Organization has no ${friendlyName} deployed`);
|
|
62
|
+
}
|
|
63
|
+
return addr;
|
|
64
|
+
}
|