lightnode-sdk 0.4.8 → 0.5.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/dist/dao.d.ts ADDED
@@ -0,0 +1,439 @@
1
+ /**
2
+ * DAO SDK: typed wrapper around the LCAI Governor (OpenZeppelin Governor v5)
3
+ * on Ethereum mainnet. Addresses extracted from
4
+ * `lightchain-protocol/LCAI-dao-frontend/config/index.ts`.
5
+ *
6
+ * Governance is currently Ethereum-side (chain 1). Voting on LCAI proposals
7
+ * happens via the LCAI ERC-20 wrapped as IVotes (LCAIBallots). Execution
8
+ * goes through LCAITimeLock with the timelock controller managing actual
9
+ * calldata dispatch.
10
+ *
11
+ * Voting parameters (hard-coded in LCAIGovernor.sol constructor):
12
+ * - votingDelay = 7,200 blocks (~1 day at 12s)
13
+ * - votingPeriod = 100,800 blocks (~14 days at 12s)
14
+ * - proposalThreshold = 140,000 LCAI (votes required to create a proposal)
15
+ * - quorum = 3% of total supply (3-15 by admin)
16
+ *
17
+ * This module covers the OZ Governor v5 surface: state machine, propose,
18
+ * castVote, queue, execute. Plus convenience reads of the constants.
19
+ */
20
+ export type DaoChain = "ethereum";
21
+ export interface DaoAddresses {
22
+ chainId: number;
23
+ /** OZ Governor contract. */
24
+ governor: `0x${string}`;
25
+ /** Timelock controller. queue/execute dispatch through this. */
26
+ timelock: `0x${string}`;
27
+ /** ERC-20 wrapped as IVotes; this is what users delegate / hold to vote. */
28
+ ballots: `0x${string}`;
29
+ /** LCAI ERC-20 (the underlying governance token). */
30
+ token: `0x${string}`;
31
+ /** Treasury contract holding DAO funds. */
32
+ treasury: `0x${string}`;
33
+ explorer: string;
34
+ }
35
+ /** Confirmed Ethereum mainnet addresses (chain 1). */
36
+ export declare const DAO_ADDRESSES: Record<DaoChain, DaoAddresses>;
37
+ /**
38
+ * The 8-state OZ Governor v5 enum. The string label is what most builders
39
+ * will want to surface in a UI.
40
+ */
41
+ export declare enum ProposalState {
42
+ Pending = 0,
43
+ Active = 1,
44
+ Canceled = 2,
45
+ Defeated = 3,
46
+ Succeeded = 4,
47
+ Queued = 5,
48
+ Expired = 6,
49
+ Executed = 7
50
+ }
51
+ export declare const PROPOSAL_STATE_LABEL: Record<ProposalState, string>;
52
+ /** Vote support values. Maps to OZ's GovernorCountingSimple. */
53
+ export declare enum VoteSupport {
54
+ Against = 0,
55
+ For = 1,
56
+ Abstain = 2
57
+ }
58
+ /** OZ Governor v5 ABI (subset). */
59
+ export declare const GOVERNOR_ABI: readonly [{
60
+ readonly name: "propose";
61
+ readonly type: "function";
62
+ readonly stateMutability: "nonpayable";
63
+ readonly inputs: readonly [{
64
+ readonly type: "address[]";
65
+ readonly name: "targets";
66
+ }, {
67
+ readonly type: "uint256[]";
68
+ readonly name: "values";
69
+ }, {
70
+ readonly type: "bytes[]";
71
+ readonly name: "calldatas";
72
+ }, {
73
+ readonly type: "string";
74
+ readonly name: "description";
75
+ }];
76
+ readonly outputs: readonly [{
77
+ readonly type: "uint256";
78
+ readonly name: "proposalId";
79
+ }];
80
+ }, {
81
+ readonly name: "castVote";
82
+ readonly type: "function";
83
+ readonly stateMutability: "nonpayable";
84
+ readonly inputs: readonly [{
85
+ readonly type: "uint256";
86
+ readonly name: "proposalId";
87
+ }, {
88
+ readonly type: "uint8";
89
+ readonly name: "support";
90
+ }];
91
+ readonly outputs: readonly [{
92
+ readonly type: "uint256";
93
+ }];
94
+ }, {
95
+ readonly name: "castVoteWithReason";
96
+ readonly type: "function";
97
+ readonly stateMutability: "nonpayable";
98
+ readonly inputs: readonly [{
99
+ readonly type: "uint256";
100
+ readonly name: "proposalId";
101
+ }, {
102
+ readonly type: "uint8";
103
+ readonly name: "support";
104
+ }, {
105
+ readonly type: "string";
106
+ readonly name: "reason";
107
+ }];
108
+ readonly outputs: readonly [{
109
+ readonly type: "uint256";
110
+ }];
111
+ }, {
112
+ readonly name: "queue";
113
+ readonly type: "function";
114
+ readonly stateMutability: "nonpayable";
115
+ readonly inputs: readonly [{
116
+ readonly type: "address[]";
117
+ readonly name: "targets";
118
+ }, {
119
+ readonly type: "uint256[]";
120
+ readonly name: "values";
121
+ }, {
122
+ readonly type: "bytes[]";
123
+ readonly name: "calldatas";
124
+ }, {
125
+ readonly type: "bytes32";
126
+ readonly name: "descriptionHash";
127
+ }];
128
+ readonly outputs: readonly [{
129
+ readonly type: "uint256";
130
+ }];
131
+ }, {
132
+ readonly name: "execute";
133
+ readonly type: "function";
134
+ readonly stateMutability: "payable";
135
+ readonly inputs: readonly [{
136
+ readonly type: "address[]";
137
+ readonly name: "targets";
138
+ }, {
139
+ readonly type: "uint256[]";
140
+ readonly name: "values";
141
+ }, {
142
+ readonly type: "bytes[]";
143
+ readonly name: "calldatas";
144
+ }, {
145
+ readonly type: "bytes32";
146
+ readonly name: "descriptionHash";
147
+ }];
148
+ readonly outputs: readonly [{
149
+ readonly type: "uint256";
150
+ }];
151
+ }, {
152
+ readonly name: "state";
153
+ readonly type: "function";
154
+ readonly stateMutability: "view";
155
+ readonly inputs: readonly [{
156
+ readonly type: "uint256";
157
+ readonly name: "proposalId";
158
+ }];
159
+ readonly outputs: readonly [{
160
+ readonly type: "uint8";
161
+ }];
162
+ }, {
163
+ readonly name: "hashProposal";
164
+ readonly type: "function";
165
+ readonly stateMutability: "pure";
166
+ readonly inputs: readonly [{
167
+ readonly type: "address[]";
168
+ readonly name: "targets";
169
+ }, {
170
+ readonly type: "uint256[]";
171
+ readonly name: "values";
172
+ }, {
173
+ readonly type: "bytes[]";
174
+ readonly name: "calldatas";
175
+ }, {
176
+ readonly type: "bytes32";
177
+ readonly name: "descriptionHash";
178
+ }];
179
+ readonly outputs: readonly [{
180
+ readonly type: "uint256";
181
+ }];
182
+ }, {
183
+ readonly name: "votingDelay";
184
+ readonly type: "function";
185
+ readonly stateMutability: "view";
186
+ readonly inputs: readonly [];
187
+ readonly outputs: readonly [{
188
+ readonly type: "uint256";
189
+ }];
190
+ }, {
191
+ readonly name: "votingPeriod";
192
+ readonly type: "function";
193
+ readonly stateMutability: "view";
194
+ readonly inputs: readonly [];
195
+ readonly outputs: readonly [{
196
+ readonly type: "uint256";
197
+ }];
198
+ }, {
199
+ readonly name: "proposalThreshold";
200
+ readonly type: "function";
201
+ readonly stateMutability: "view";
202
+ readonly inputs: readonly [];
203
+ readonly outputs: readonly [{
204
+ readonly type: "uint256";
205
+ }];
206
+ }, {
207
+ readonly name: "quorum";
208
+ readonly type: "function";
209
+ readonly stateMutability: "view";
210
+ readonly inputs: readonly [{
211
+ readonly type: "uint256";
212
+ readonly name: "timepoint";
213
+ }];
214
+ readonly outputs: readonly [{
215
+ readonly type: "uint256";
216
+ }];
217
+ }, {
218
+ readonly name: "proposalVotes";
219
+ readonly type: "function";
220
+ readonly stateMutability: "view";
221
+ readonly inputs: readonly [{
222
+ readonly type: "uint256";
223
+ readonly name: "proposalId";
224
+ }];
225
+ readonly outputs: readonly [{
226
+ readonly type: "uint256";
227
+ readonly name: "againstVotes";
228
+ }, {
229
+ readonly type: "uint256";
230
+ readonly name: "forVotes";
231
+ }, {
232
+ readonly type: "uint256";
233
+ readonly name: "abstainVotes";
234
+ }];
235
+ }, {
236
+ readonly name: "proposalSnapshot";
237
+ readonly type: "function";
238
+ readonly stateMutability: "view";
239
+ readonly inputs: readonly [{
240
+ readonly type: "uint256";
241
+ readonly name: "proposalId";
242
+ }];
243
+ readonly outputs: readonly [{
244
+ readonly type: "uint256";
245
+ }];
246
+ }, {
247
+ readonly name: "proposalDeadline";
248
+ readonly type: "function";
249
+ readonly stateMutability: "view";
250
+ readonly inputs: readonly [{
251
+ readonly type: "uint256";
252
+ readonly name: "proposalId";
253
+ }];
254
+ readonly outputs: readonly [{
255
+ readonly type: "uint256";
256
+ }];
257
+ }, {
258
+ readonly name: "proposalProposer";
259
+ readonly type: "function";
260
+ readonly stateMutability: "view";
261
+ readonly inputs: readonly [{
262
+ readonly type: "uint256";
263
+ readonly name: "proposalId";
264
+ }];
265
+ readonly outputs: readonly [{
266
+ readonly type: "address";
267
+ }];
268
+ }, {
269
+ readonly name: "proposalEta";
270
+ readonly type: "function";
271
+ readonly stateMutability: "view";
272
+ readonly inputs: readonly [{
273
+ readonly type: "uint256";
274
+ readonly name: "proposalId";
275
+ }];
276
+ readonly outputs: readonly [{
277
+ readonly type: "uint256";
278
+ }];
279
+ }, {
280
+ readonly name: "getVotes";
281
+ readonly type: "function";
282
+ readonly stateMutability: "view";
283
+ readonly inputs: readonly [{
284
+ readonly type: "address";
285
+ readonly name: "account";
286
+ }, {
287
+ readonly type: "uint256";
288
+ readonly name: "timepoint";
289
+ }];
290
+ readonly outputs: readonly [{
291
+ readonly type: "uint256";
292
+ }];
293
+ }, {
294
+ readonly name: "hasVoted";
295
+ readonly type: "function";
296
+ readonly stateMutability: "view";
297
+ readonly inputs: readonly [{
298
+ readonly type: "uint256";
299
+ readonly name: "proposalId";
300
+ }, {
301
+ readonly type: "address";
302
+ readonly name: "account";
303
+ }];
304
+ readonly outputs: readonly [{
305
+ readonly type: "bool";
306
+ }];
307
+ }];
308
+ /** Minimal IVotes ABI for delegate + balance reads (LCAIBallots). */
309
+ export declare const VOTES_ABI: readonly [{
310
+ readonly name: "balanceOf";
311
+ readonly type: "function";
312
+ readonly stateMutability: "view";
313
+ readonly inputs: readonly [{
314
+ readonly type: "address";
315
+ }];
316
+ readonly outputs: readonly [{
317
+ readonly type: "uint256";
318
+ }];
319
+ }, {
320
+ readonly name: "getVotes";
321
+ readonly type: "function";
322
+ readonly stateMutability: "view";
323
+ readonly inputs: readonly [{
324
+ readonly type: "address";
325
+ }];
326
+ readonly outputs: readonly [{
327
+ readonly type: "uint256";
328
+ }];
329
+ }, {
330
+ readonly name: "delegates";
331
+ readonly type: "function";
332
+ readonly stateMutability: "view";
333
+ readonly inputs: readonly [{
334
+ readonly type: "address";
335
+ }];
336
+ readonly outputs: readonly [{
337
+ readonly type: "address";
338
+ }];
339
+ }, {
340
+ readonly name: "delegate";
341
+ readonly type: "function";
342
+ readonly stateMutability: "nonpayable";
343
+ readonly inputs: readonly [{
344
+ readonly type: "address";
345
+ readonly name: "delegatee";
346
+ }];
347
+ readonly outputs: readonly [{
348
+ readonly type: "bool";
349
+ }];
350
+ }];
351
+ interface MinimalPublicClient {
352
+ readContract: (args: {
353
+ address: `0x${string}`;
354
+ abi: readonly unknown[];
355
+ functionName: string;
356
+ args?: readonly unknown[];
357
+ }) => Promise<unknown>;
358
+ }
359
+ interface MinimalWalletClient {
360
+ writeContract: (args: {
361
+ address: `0x${string}`;
362
+ abi: readonly unknown[];
363
+ functionName: string;
364
+ args: readonly unknown[];
365
+ value?: bigint;
366
+ gas?: bigint;
367
+ }) => Promise<`0x${string}`>;
368
+ }
369
+ export interface ProposalSummary {
370
+ id: bigint;
371
+ state: ProposalState;
372
+ stateLabel: string;
373
+ proposer: `0x${string}` | null;
374
+ snapshot: bigint;
375
+ deadline: bigint;
376
+ eta: bigint;
377
+ votes: {
378
+ againstWei: bigint;
379
+ forWei: bigint;
380
+ abstainWei: bigint;
381
+ };
382
+ }
383
+ export interface DaoConfig {
384
+ votingDelayBlocks: bigint;
385
+ votingPeriodBlocks: bigint;
386
+ proposalThresholdWei: bigint;
387
+ /** Approx voting period in seconds, assuming 12s/block on Ethereum. */
388
+ votingPeriodSecs: number;
389
+ }
390
+ /**
391
+ * DAO client. Wraps reads (proposal state, config) + writes (propose, vote,
392
+ * queue, execute) on the Ethereum LCAIGovernor.
393
+ */
394
+ export declare class DAO {
395
+ private readonly publicClient;
396
+ private readonly walletClient?;
397
+ /** Addresses for the configured DAO chain. Currently only Ethereum mainnet. */
398
+ readonly addresses: DaoAddresses;
399
+ constructor(publicClient: MinimalPublicClient, chain?: DaoChain, walletClient?: MinimalWalletClient | undefined);
400
+ /** Current proposal state by id. */
401
+ state(proposalId: bigint): Promise<ProposalState>;
402
+ /** Full proposal summary by id. Aggregates state + votes + key blocks. */
403
+ proposal(proposalId: bigint): Promise<ProposalSummary>;
404
+ /** Whether `voter` has cast a vote on `proposalId`. */
405
+ hasVoted(proposalId: bigint, voter: `0x${string}`): Promise<boolean>;
406
+ /** Voting weight of `voter` at a specific block (use the proposal's `snapshot`). */
407
+ getVotes(voter: `0x${string}`, timepoint: bigint): Promise<bigint>;
408
+ /** Aggregated voting parameters of the LCAIGovernor. */
409
+ config(): Promise<DaoConfig>;
410
+ /** Quorum required at a given timepoint (in wei of voting weight). */
411
+ quorum(timepoint: bigint): Promise<bigint>;
412
+ /** Cast a For / Against / Abstain vote. Wallet must be the voter and have delegated their LCAI. */
413
+ castVote(proposalId: bigint, support: VoteSupport, reason?: string): Promise<`0x${string}`>;
414
+ /** Submit a new proposal. Wallet must hold at least `proposalThreshold` delegated votes. */
415
+ propose(args: {
416
+ targets: `0x${string}`[];
417
+ values: bigint[];
418
+ calldatas: `0x${string}`[];
419
+ description: string;
420
+ }): Promise<`0x${string}`>;
421
+ /** Queue a Succeeded proposal into the timelock. */
422
+ queue(args: {
423
+ targets: `0x${string}`[];
424
+ values: bigint[];
425
+ calldatas: `0x${string}`[];
426
+ descriptionHash: `0x${string}`;
427
+ }): Promise<`0x${string}`>;
428
+ /**
429
+ * Execute a Queued proposal. The Governor enforces
430
+ * `msg.value == sum(values)`; pass the sum as `value`.
431
+ */
432
+ execute(args: {
433
+ targets: `0x${string}`[];
434
+ values: bigint[];
435
+ calldatas: `0x${string}`[];
436
+ descriptionHash: `0x${string}`;
437
+ }): Promise<`0x${string}`>;
438
+ }
439
+ export {};
package/dist/dao.js ADDED
@@ -0,0 +1,234 @@
1
+ /**
2
+ * DAO SDK: typed wrapper around the LCAI Governor (OpenZeppelin Governor v5)
3
+ * on Ethereum mainnet. Addresses extracted from
4
+ * `lightchain-protocol/LCAI-dao-frontend/config/index.ts`.
5
+ *
6
+ * Governance is currently Ethereum-side (chain 1). Voting on LCAI proposals
7
+ * happens via the LCAI ERC-20 wrapped as IVotes (LCAIBallots). Execution
8
+ * goes through LCAITimeLock with the timelock controller managing actual
9
+ * calldata dispatch.
10
+ *
11
+ * Voting parameters (hard-coded in LCAIGovernor.sol constructor):
12
+ * - votingDelay = 7,200 blocks (~1 day at 12s)
13
+ * - votingPeriod = 100,800 blocks (~14 days at 12s)
14
+ * - proposalThreshold = 140,000 LCAI (votes required to create a proposal)
15
+ * - quorum = 3% of total supply (3-15 by admin)
16
+ *
17
+ * This module covers the OZ Governor v5 surface: state machine, propose,
18
+ * castVote, queue, execute. Plus convenience reads of the constants.
19
+ */
20
+ import { parseAbi } from "viem";
21
+ /** Confirmed Ethereum mainnet addresses (chain 1). */
22
+ export const DAO_ADDRESSES = {
23
+ ethereum: {
24
+ chainId: 1,
25
+ governor: "0x6dfa413B5900a1a7947BC75E68AbBA093cB2492d",
26
+ timelock: "0xbE1c37F8C4DA77dD06F4A8AC5098Ec70273093d7",
27
+ ballots: "0x75F3D01c4D960FE986A598B7954A3b786B29cE49",
28
+ token: "0x9cA8530CA349c966Fe9ef903Df17a75B8A778927",
29
+ treasury: "0x07A716a551E5f4CA7D6C71Da9dF1cb1429Dba826",
30
+ explorer: "https://etherscan.io",
31
+ },
32
+ };
33
+ /**
34
+ * The 8-state OZ Governor v5 enum. The string label is what most builders
35
+ * will want to surface in a UI.
36
+ */
37
+ export var ProposalState;
38
+ (function (ProposalState) {
39
+ ProposalState[ProposalState["Pending"] = 0] = "Pending";
40
+ ProposalState[ProposalState["Active"] = 1] = "Active";
41
+ ProposalState[ProposalState["Canceled"] = 2] = "Canceled";
42
+ ProposalState[ProposalState["Defeated"] = 3] = "Defeated";
43
+ ProposalState[ProposalState["Succeeded"] = 4] = "Succeeded";
44
+ ProposalState[ProposalState["Queued"] = 5] = "Queued";
45
+ ProposalState[ProposalState["Expired"] = 6] = "Expired";
46
+ ProposalState[ProposalState["Executed"] = 7] = "Executed";
47
+ })(ProposalState || (ProposalState = {}));
48
+ export const PROPOSAL_STATE_LABEL = {
49
+ [ProposalState.Pending]: "pending",
50
+ [ProposalState.Active]: "active",
51
+ [ProposalState.Canceled]: "canceled",
52
+ [ProposalState.Defeated]: "defeated",
53
+ [ProposalState.Succeeded]: "succeeded",
54
+ [ProposalState.Queued]: "queued",
55
+ [ProposalState.Expired]: "expired",
56
+ [ProposalState.Executed]: "executed",
57
+ };
58
+ /** Vote support values. Maps to OZ's GovernorCountingSimple. */
59
+ export var VoteSupport;
60
+ (function (VoteSupport) {
61
+ VoteSupport[VoteSupport["Against"] = 0] = "Against";
62
+ VoteSupport[VoteSupport["For"] = 1] = "For";
63
+ VoteSupport[VoteSupport["Abstain"] = 2] = "Abstain";
64
+ })(VoteSupport || (VoteSupport = {}));
65
+ /** OZ Governor v5 ABI (subset). */
66
+ export const GOVERNOR_ABI = parseAbi([
67
+ "function propose(address[] targets, uint256[] values, bytes[] calldatas, string description) external returns (uint256 proposalId)",
68
+ "function castVote(uint256 proposalId, uint8 support) external returns (uint256)",
69
+ "function castVoteWithReason(uint256 proposalId, uint8 support, string reason) external returns (uint256)",
70
+ "function queue(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) external returns (uint256)",
71
+ "function execute(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) external payable returns (uint256)",
72
+ "function state(uint256 proposalId) external view returns (uint8)",
73
+ "function hashProposal(address[] targets, uint256[] values, bytes[] calldatas, bytes32 descriptionHash) external pure returns (uint256)",
74
+ "function votingDelay() external view returns (uint256)",
75
+ "function votingPeriod() external view returns (uint256)",
76
+ "function proposalThreshold() external view returns (uint256)",
77
+ "function quorum(uint256 timepoint) external view returns (uint256)",
78
+ "function proposalVotes(uint256 proposalId) external view returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes)",
79
+ "function proposalSnapshot(uint256 proposalId) external view returns (uint256)",
80
+ "function proposalDeadline(uint256 proposalId) external view returns (uint256)",
81
+ "function proposalProposer(uint256 proposalId) external view returns (address)",
82
+ "function proposalEta(uint256 proposalId) external view returns (uint256)",
83
+ "function getVotes(address account, uint256 timepoint) external view returns (uint256)",
84
+ "function hasVoted(uint256 proposalId, address account) external view returns (bool)",
85
+ ]);
86
+ /** Minimal IVotes ABI for delegate + balance reads (LCAIBallots). */
87
+ export const VOTES_ABI = parseAbi([
88
+ "function balanceOf(address) external view returns (uint256)",
89
+ "function getVotes(address) external view returns (uint256)",
90
+ "function delegates(address) external view returns (address)",
91
+ "function delegate(address delegatee) external returns (bool)",
92
+ ]);
93
+ /**
94
+ * DAO client. Wraps reads (proposal state, config) + writes (propose, vote,
95
+ * queue, execute) on the Ethereum LCAIGovernor.
96
+ */
97
+ export class DAO {
98
+ constructor(publicClient, chain = "ethereum", walletClient) {
99
+ this.publicClient = publicClient;
100
+ this.walletClient = walletClient;
101
+ this.addresses = DAO_ADDRESSES[chain];
102
+ }
103
+ // -------- Reads --------
104
+ /** Current proposal state by id. */
105
+ async state(proposalId) {
106
+ const raw = (await this.publicClient.readContract({
107
+ address: this.addresses.governor,
108
+ abi: GOVERNOR_ABI,
109
+ functionName: "state",
110
+ args: [proposalId],
111
+ }));
112
+ return raw;
113
+ }
114
+ /** Full proposal summary by id. Aggregates state + votes + key blocks. */
115
+ async proposal(proposalId) {
116
+ const [stateRaw, votesRaw, snapshot, deadline, eta, proposerRaw] = (await Promise.all([
117
+ this.publicClient.readContract({ address: this.addresses.governor, abi: GOVERNOR_ABI, functionName: "state", args: [proposalId] }),
118
+ this.publicClient.readContract({ address: this.addresses.governor, abi: GOVERNOR_ABI, functionName: "proposalVotes", args: [proposalId] }),
119
+ this.publicClient.readContract({ address: this.addresses.governor, abi: GOVERNOR_ABI, functionName: "proposalSnapshot", args: [proposalId] }),
120
+ this.publicClient.readContract({ address: this.addresses.governor, abi: GOVERNOR_ABI, functionName: "proposalDeadline", args: [proposalId] }),
121
+ this.publicClient.readContract({ address: this.addresses.governor, abi: GOVERNOR_ABI, functionName: "proposalEta", args: [proposalId] }).catch(() => 0n),
122
+ this.publicClient.readContract({ address: this.addresses.governor, abi: GOVERNOR_ABI, functionName: "proposalProposer", args: [proposalId] }).catch(() => null),
123
+ ]));
124
+ const state = stateRaw;
125
+ return {
126
+ id: proposalId,
127
+ state,
128
+ stateLabel: PROPOSAL_STATE_LABEL[state] ?? "unknown",
129
+ proposer: proposerRaw,
130
+ snapshot,
131
+ deadline,
132
+ eta,
133
+ votes: { againstWei: votesRaw[0], forWei: votesRaw[1], abstainWei: votesRaw[2] },
134
+ };
135
+ }
136
+ /** Whether `voter` has cast a vote on `proposalId`. */
137
+ hasVoted(proposalId, voter) {
138
+ return this.publicClient.readContract({
139
+ address: this.addresses.governor,
140
+ abi: GOVERNOR_ABI,
141
+ functionName: "hasVoted",
142
+ args: [proposalId, voter],
143
+ });
144
+ }
145
+ /** Voting weight of `voter` at a specific block (use the proposal's `snapshot`). */
146
+ getVotes(voter, timepoint) {
147
+ return this.publicClient.readContract({
148
+ address: this.addresses.governor,
149
+ abi: GOVERNOR_ABI,
150
+ functionName: "getVotes",
151
+ args: [voter, timepoint],
152
+ });
153
+ }
154
+ /** Aggregated voting parameters of the LCAIGovernor. */
155
+ async config() {
156
+ const [delay, period, threshold] = (await Promise.all([
157
+ this.publicClient.readContract({ address: this.addresses.governor, abi: GOVERNOR_ABI, functionName: "votingDelay" }),
158
+ this.publicClient.readContract({ address: this.addresses.governor, abi: GOVERNOR_ABI, functionName: "votingPeriod" }),
159
+ this.publicClient.readContract({ address: this.addresses.governor, abi: GOVERNOR_ABI, functionName: "proposalThreshold" }),
160
+ ]));
161
+ return {
162
+ votingDelayBlocks: delay,
163
+ votingPeriodBlocks: period,
164
+ proposalThresholdWei: threshold,
165
+ votingPeriodSecs: Number(period) * 12,
166
+ };
167
+ }
168
+ /** Quorum required at a given timepoint (in wei of voting weight). */
169
+ quorum(timepoint) {
170
+ return this.publicClient.readContract({
171
+ address: this.addresses.governor,
172
+ abi: GOVERNOR_ABI,
173
+ functionName: "quorum",
174
+ args: [timepoint],
175
+ });
176
+ }
177
+ // -------- Writes --------
178
+ /** Cast a For / Against / Abstain vote. Wallet must be the voter and have delegated their LCAI. */
179
+ castVote(proposalId, support, reason) {
180
+ if (!this.walletClient)
181
+ throw new Error("DAO: no wallet client; pass one to the DAO constructor for writes");
182
+ return reason
183
+ ? this.walletClient.writeContract({
184
+ address: this.addresses.governor,
185
+ abi: GOVERNOR_ABI,
186
+ functionName: "castVoteWithReason",
187
+ args: [proposalId, support, reason],
188
+ })
189
+ : this.walletClient.writeContract({
190
+ address: this.addresses.governor,
191
+ abi: GOVERNOR_ABI,
192
+ functionName: "castVote",
193
+ args: [proposalId, support],
194
+ });
195
+ }
196
+ /** Submit a new proposal. Wallet must hold at least `proposalThreshold` delegated votes. */
197
+ propose(args) {
198
+ if (!this.walletClient)
199
+ throw new Error("DAO: no wallet client; pass one to the DAO constructor for writes");
200
+ return this.walletClient.writeContract({
201
+ address: this.addresses.governor,
202
+ abi: GOVERNOR_ABI,
203
+ functionName: "propose",
204
+ args: [args.targets, args.values, args.calldatas, args.description],
205
+ });
206
+ }
207
+ /** Queue a Succeeded proposal into the timelock. */
208
+ queue(args) {
209
+ if (!this.walletClient)
210
+ throw new Error("DAO: no wallet client; pass one to the DAO constructor for writes");
211
+ return this.walletClient.writeContract({
212
+ address: this.addresses.governor,
213
+ abi: GOVERNOR_ABI,
214
+ functionName: "queue",
215
+ args: [args.targets, args.values, args.calldatas, args.descriptionHash],
216
+ });
217
+ }
218
+ /**
219
+ * Execute a Queued proposal. The Governor enforces
220
+ * `msg.value == sum(values)`; pass the sum as `value`.
221
+ */
222
+ execute(args) {
223
+ if (!this.walletClient)
224
+ throw new Error("DAO: no wallet client; pass one to the DAO constructor for writes");
225
+ const totalValue = args.values.reduce((acc, v) => acc + v, 0n);
226
+ return this.walletClient.writeContract({
227
+ address: this.addresses.governor,
228
+ abi: GOVERNOR_ABI,
229
+ functionName: "execute",
230
+ args: [args.targets, args.values, args.calldatas, args.descriptionHash],
231
+ value: totalValue,
232
+ });
233
+ }
234
+ }