@chipi-stack/chipi-react 14.7.0 → 14.8.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.
@@ -0,0 +1,350 @@
1
+ import * as _tanstack_react_query from '@tanstack/react-query';
2
+
3
+ /**
4
+ * Framework-agnostic action-template engine for SHHH multisig governance.
5
+ *
6
+ * An {@link ActionTemplate} maps friendly, typed form fields → an
7
+ * OutsideExecution call list + a human-readable title. It's the seam that
8
+ * turns "call any contract" (powerful, scary) into "fill in this form"
9
+ * (founder-grade) — and the whitelabel seam: every integrator registers
10
+ * its own templates (Roca: create_pool / borrow / repay), while `Vote`
11
+ * ships built-in. The raw-call escape hatch lives in the UI layer, not
12
+ * here, because its arguments are open-ended.
13
+ *
14
+ * Pure: no React, no network — so the same template renders the proposer's
15
+ * form, every approver's inbox, and the notification, from one source of
16
+ * truth, and `toCalls` is deterministic (proposer and executor build the
17
+ * identical OE → the hash matches).
18
+ */
19
+ type FeltLike = string | number | bigint;
20
+ /** One call in an action — the shape the OE builder consumes. */
21
+ interface CallSpec {
22
+ to: string;
23
+ entrypoint: string;
24
+ /** Flat 0x-hex felts. */
25
+ calldata: string[];
26
+ }
27
+ /** A typed input in an action template. */
28
+ type FieldSpec = {
29
+ name: string;
30
+ label: string;
31
+ type: "amount";
32
+ decimals: number;
33
+ help?: string;
34
+ } | {
35
+ name: string;
36
+ label: string;
37
+ type: "address";
38
+ help?: string;
39
+ } | {
40
+ name: string;
41
+ label: string;
42
+ type: "number" | "bps" | "days" | "felt";
43
+ help?: string;
44
+ } | {
45
+ name: string;
46
+ label: string;
47
+ type: "select";
48
+ options: {
49
+ label: string;
50
+ value: string;
51
+ }[];
52
+ help?: string;
53
+ } | {
54
+ name: string;
55
+ label: string;
56
+ type: "text";
57
+ help?: string;
58
+ };
59
+ interface ActionTemplate<V = Record<string, unknown>> {
60
+ /** Stable id, persisted on the proposal. */
61
+ key: string;
62
+ /** Display label ("Create pool"). */
63
+ label: string;
64
+ description?: string;
65
+ /** Typed inputs rendered by `<ProposeAction>`. */
66
+ fields: FieldSpec[];
67
+ /** Pure: validated field values → the OE call list. */
68
+ toCalls: (v: V) => CallSpec[];
69
+ /** Pure: the plain-language title shown in the preview, inbox, and email. */
70
+ title: (v: V) => string;
71
+ /** Optional metadata persisted with the proposal so the approver's app
72
+ * can render business context (e.g. `{ poolId }`). */
73
+ meta?: (v: V) => Record<string, string | number>;
74
+ }
75
+ /** Starknet felt252 field prime — args must be a non-negative felt below it. */
76
+ declare const FELT_PRIME: bigint;
77
+ /** Parse a decimal or 0x-hex value to a canonical `0x` felt. Throws on a
78
+ * non-numeric or out-of-range value. */
79
+ declare function toFelt(v: FeltLike): string;
80
+ /** Split a u256 value into its `[low, high]` felts (Cairo calling convention). */
81
+ declare function u256(v: FeltLike): [string, string];
82
+ /** Convert a human amount ("10.5") to base units given a token's decimals. */
83
+ declare function amountToBase(amount: string, decimals: number): bigint;
84
+ /**
85
+ * Identity + light validation for a template registry: keys are present
86
+ * and unique. Returns the same array (typed) so call sites keep inference.
87
+ */
88
+ declare function defineActions<T extends ActionTemplate<any>[]>(templates: [...T]): [...T];
89
+ interface VoteValues {
90
+ contract: string;
91
+ proposalId: string;
92
+ choice: string;
93
+ }
94
+ /**
95
+ * Built-in `Vote` template — `vote(proposalId, choice)` on a governance
96
+ * contract. Pin the contract and/or entrypoint up front (then they drop
97
+ * out of the form), or leave them for the proposer to fill.
98
+ */
99
+ declare function voteTemplate(opts?: {
100
+ governanceContract?: string;
101
+ entrypoint?: string;
102
+ }): ActionTemplate<VoteValues>;
103
+
104
+ /** shortString.encodeShortString("SN_MAIN") — Starknet mainnet. */
105
+ declare const SN_MAIN_CHAIN_ID = "0x534e5f4d41494e";
106
+ /**
107
+ * Max on-chain OE validity window (`executeBefore - executeAfter`), capped
108
+ * by the SHHH contract audit (M-2). This is the longest a proposal stays
109
+ * EXECUTABLE — distinct from how long its record lives in the coordination
110
+ * backend. NOTE: with `executeAfter` pinned to 0 the window would be the
111
+ * whole epoch and the contract rejects it, so `executeAfter` is set to ~now
112
+ * and persisted alongside the nonce + `executeBefore`.
113
+ */
114
+ declare const OE_WINDOW_SECONDS: number;
115
+ /**
116
+ * Signs an OE message hash for one owner → that owner's inner V2_SNIP12
117
+ * envelope (an array of felts). Implementations wrap a passkey / MetaMask /
118
+ * Phantom / STARK signer; the private key never leaves the implementation.
119
+ */
120
+ type OeSigner = (params: {
121
+ messageHash: bigint;
122
+ ownerIndex: bigint;
123
+ }) => Promise<bigint[]> | bigint[];
124
+ /** Serialize an inner envelope (felt[]) to the comma-joined 0x-hex string
125
+ * the coordination backend stores per signature. */
126
+ declare function serializeEnvelope(env: bigint[]): string;
127
+ declare function deserializeEnvelope(s: string): bigint[];
128
+ /**
129
+ * OE replay nonce: ms timestamp shifted left 24 bits, ORed with a 24-bit
130
+ * random suffix. `nowMs`/`rand` are injectable for deterministic tests.
131
+ */
132
+ declare function newOeNonce(nowMs: number, rand: number): bigint;
133
+ interface ActionProposal {
134
+ oeMessageHash: string;
135
+ oeNonce: string;
136
+ oeExecuteBefore: string;
137
+ /** The proposer's inner V2_SNIP12 envelope, comma-joined 0x-hex. */
138
+ proposerSignature: string;
139
+ }
140
+ /** Derive the OE's executeAfter from its persisted executeBefore. The
141
+ * window is a fixed constant (the contract cap), so the executor needs
142
+ * only executeBefore to reconstruct the exact signed OE — no separate
143
+ * executeAfter persistence (and no backend column). */
144
+ declare function deriveExecuteAfter(oeExecuteBefore: string): bigint;
145
+ /**
146
+ * Build an OE over `calls`, sign it as the proposer (owner 0 by default),
147
+ * and return everything a propose endpoint needs. The OE params (nonce +
148
+ * executeBefore) are returned; executeAfter is `executeBefore - OE_WINDOW`,
149
+ * so only executeBefore needs persisting. The window is the contract cap
150
+ * (the longest executable window M-2 allows).
151
+ */
152
+ declare function buildActionProposal(params: {
153
+ walletAddress: string;
154
+ calls: CallSpec[];
155
+ sign: OeSigner;
156
+ ownerIndex?: bigint;
157
+ chainId?: string;
158
+ nowMs?: number;
159
+ rand?: number;
160
+ }): Promise<ActionProposal>;
161
+ /** Sign an existing proposal's OE hash as an approver → inner envelope string. */
162
+ declare function signActionApproval(params: {
163
+ oeMessageHash: string;
164
+ ownerIndex: bigint;
165
+ sign: OeSigner;
166
+ }): Promise<string>;
167
+ /**
168
+ * Rebuild the exact OE from the persisted params + collected signatures and
169
+ * serialize the `execute` calldata. A 1-of-N wallet uses the single inner
170
+ * envelope; N≥2 wraps the inner envelopes in a V2_THRESHOLD envelope.
171
+ */
172
+ declare function assembleActionExecuteCalldata(params: {
173
+ calls: CallSpec[];
174
+ oeNonce: string;
175
+ oeExecuteBefore: string;
176
+ signatures: string[];
177
+ requiredApprovals: number;
178
+ }): string[];
179
+
180
+ /**
181
+ * Injectable boundaries for the multisig governance hooks. The package owns
182
+ * the OE crypto + template engine + orchestration; the host supplies the
183
+ * transport (an authed coordination backend) and the signer (a per-owner
184
+ * OE signer + owner-index resolution). This keeps the package auth- and
185
+ * chain-agnostic: the dashboard wires Clerk today; the owner-signature SDK
186
+ * client wires it for integrators at P1.
187
+ */
188
+
189
+ /** One owner's collected signature on a proposal. */
190
+ interface ProposalSignature {
191
+ ownerId: number;
192
+ signerKind: string;
193
+ /** The owner's serialized inner V2_SNIP12 envelope (comma-joined felts). */
194
+ signature: string;
195
+ }
196
+ /** A treasury proposal as returned by the coordination backend. */
197
+ interface TreasuryProposal {
198
+ id: string;
199
+ /** Set for generalized actions (vote / call any contract). */
200
+ calls?: {
201
+ to: string;
202
+ entrypoint: string;
203
+ calldata: string[];
204
+ }[] | null;
205
+ /** Human label for an action ("Vote YES on Proposal #5"). */
206
+ title?: string | null;
207
+ /** Arbitrary integrator context (e.g. `{ poolId }`). */
208
+ meta?: Record<string, string | number> | null;
209
+ oeMessageHash: string;
210
+ oeNonce: string | null;
211
+ oeExecuteBefore: string | null;
212
+ requiredApprovals: number;
213
+ status: "PROPOSED" | "APPROVED" | "EXECUTED" | "CANCELED" | "EXPIRED";
214
+ executedTxHash?: string | null;
215
+ signatures: ProposalSignature[];
216
+ }
217
+ /** The body the coordination backend's `propose` endpoint accepts. */
218
+ interface ProposeBody {
219
+ proposerOwnerId: number;
220
+ recipient: string;
221
+ tokenAddress: string;
222
+ amount: string;
223
+ title: string;
224
+ calls: {
225
+ to: string;
226
+ entrypoint: string;
227
+ calldata: string[];
228
+ }[];
229
+ meta?: Record<string, string | number>;
230
+ oeMessageHash: string;
231
+ oeNonce: string;
232
+ oeExecuteBefore: string;
233
+ requiredApprovals: number;
234
+ proposerSignature: string;
235
+ proposerSignerKind: string;
236
+ }
237
+ /** The coordination backend (propose / list / sign / execute), host-wired. */
238
+ interface MultisigTransport {
239
+ list(): Promise<{
240
+ items: TreasuryProposal[];
241
+ }>;
242
+ propose(body: ProposeBody): Promise<TreasuryProposal>;
243
+ sign(proposalId: string, body: {
244
+ ownerId: number;
245
+ signature: string;
246
+ signerKind: string;
247
+ }): Promise<unknown>;
248
+ execute(proposalId: string, calldata: string[]): Promise<{
249
+ executedTxHash?: string;
250
+ transactionHash?: string;
251
+ }>;
252
+ }
253
+ /**
254
+ * A per-owner OE signer. `sign` produces this device's inner envelope (key
255
+ * never leaves it). `resolveOwnerIndex` maps the device's credential to its
256
+ * position in the on-chain owner set (for approving as a non-proposer).
257
+ */
258
+ interface MultisigSigner {
259
+ /** ShhhSignerKind, e.g. "WEBAUTHN_P256" / "STARK" / "EIP191_SECP256K1". */
260
+ signerKind: string;
261
+ /** Owner index this device proposes as (the bootstrap owner; default 0). */
262
+ proposerOwnerIndex?: number;
263
+ sign: OeSigner;
264
+ resolveOwnerIndex(walletAddress: string): Promise<number>;
265
+ }
266
+
267
+ /**
268
+ * Pure orchestration for the multisig governance flow — build a propose
269
+ * body, build an approval, assemble execute calldata. No React, no network:
270
+ * the hooks (`use-hooks.ts`) wrap these in mutations/queries, and they're
271
+ * directly unit-testable with a mock signer + injected `nowMs`/`rand`.
272
+ */
273
+
274
+ /**
275
+ * Build a propose body for a template + its validated field values: derive
276
+ * the call(s) + title (+ meta), build & proposer-sign the OE, and shape the
277
+ * body the coordination backend expects. For an action the payment fields
278
+ * are placeholders (recipient/token = the first call's target, amount "0");
279
+ * the real intent rides in `calls` + `title`.
280
+ */
281
+ declare function createProposal<V>(params: {
282
+ template: ActionTemplate<V>;
283
+ values: V;
284
+ walletAddress: string;
285
+ requiredApprovals: number;
286
+ signer: MultisigSigner;
287
+ chainId?: string;
288
+ nowMs?: number;
289
+ rand?: number;
290
+ }): Promise<ProposeBody>;
291
+ /**
292
+ * Build an approver's signature on an existing proposal: resolve this
293
+ * device's owner index from chain, then sign the SAME OE hash.
294
+ */
295
+ declare function buildApproval(params: {
296
+ proposal: Pick<TreasuryProposal, "oeMessageHash">;
297
+ walletAddress: string;
298
+ signer: MultisigSigner;
299
+ }): Promise<{
300
+ ownerId: number;
301
+ signature: string;
302
+ signerKind: string;
303
+ }>;
304
+ /**
305
+ * Assemble the execute calldata from a proposal's persisted call(s) + its
306
+ * collected signatures (sorted by owner index). Requires `calls` — this is
307
+ * the generalized-action flow; a host with payment-only proposals supplies
308
+ * the transfer calls.
309
+ */
310
+ declare function buildExecuteCalldata(proposal: TreasuryProposal): string[];
311
+
312
+ interface ProposeInput {
313
+ template: ActionTemplate<any>;
314
+ values: any;
315
+ }
316
+ /**
317
+ * Propose a templated action: build the call(s) + title from the template,
318
+ * passkey-/key-sign the OE as the proposer, and submit it. `getRequiredApprovals`
319
+ * supplies the wallet's threshold (the host reads it from chain — the package
320
+ * stays chain-agnostic).
321
+ */
322
+ declare function useProposeAction(config: {
323
+ walletAddress: string;
324
+ transport: MultisigTransport;
325
+ signer: MultisigSigner;
326
+ getRequiredApprovals: () => Promise<number>;
327
+ chainId?: string;
328
+ }): _tanstack_react_query.UseMutationResult<TreasuryProposal, Error, ProposeInput, unknown>;
329
+ /**
330
+ * List a treasury's proposals and expose approve / execute mutations. An
331
+ * approver signs the same OE hash as their resolved owner index; once enough
332
+ * approvals are collected, execute rebuilds the OE from the persisted call(s)
333
+ * and relays it.
334
+ */
335
+ declare function useTreasuryProposals(config: {
336
+ walletAddress: string;
337
+ transport: MultisigTransport;
338
+ signer: MultisigSigner;
339
+ }): {
340
+ proposals: _tanstack_react_query.UseQueryResult<{
341
+ items: TreasuryProposal[];
342
+ }, Error>;
343
+ approve: _tanstack_react_query.UseMutationResult<unknown, Error, TreasuryProposal, unknown>;
344
+ execute: _tanstack_react_query.UseMutationResult<{
345
+ executedTxHash?: string;
346
+ transactionHash?: string;
347
+ }, Error, TreasuryProposal, unknown>;
348
+ };
349
+
350
+ export { type ActionProposal, type ActionTemplate, type CallSpec, FELT_PRIME, type FeltLike, type FieldSpec, type MultisigSigner, type MultisigTransport, OE_WINDOW_SECONDS, type OeSigner, type ProposalSignature, type ProposeBody, type ProposeInput, SN_MAIN_CHAIN_ID, type TreasuryProposal, type VoteValues, amountToBase, assembleActionExecuteCalldata, buildActionProposal, buildApproval, buildExecuteCalldata, createProposal, defineActions, deriveExecuteAfter, deserializeEnvelope, newOeNonce, serializeEnvelope, signActionApproval, toFelt, u256, useProposeAction, useTreasuryProposals, voteTemplate };
@@ -0,0 +1,278 @@
1
+ 'use strict';
2
+
3
+ var backend = require('@chipi-stack/backend');
4
+ var reactQuery = require('@tanstack/react-query');
5
+
6
+ // src/multisig/action-template.ts
7
+ var FELT_PRIME = BigInt(
8
+ "0x800000000000011000000000000000000000000000000000000000000000001"
9
+ );
10
+ var U128_MASK = (1n << 128n) - 1n;
11
+ function toFelt(v) {
12
+ let n;
13
+ try {
14
+ n = BigInt(typeof v === "string" ? v.trim() : v);
15
+ } catch {
16
+ throw new Error(`Not a felt: ${String(v)}`);
17
+ }
18
+ if (n < 0n || n >= FELT_PRIME) {
19
+ throw new Error(`Felt out of range: ${String(v)}`);
20
+ }
21
+ return "0x" + n.toString(16);
22
+ }
23
+ function u256(v) {
24
+ const n = BigInt(typeof v === "string" ? v.trim() : v);
25
+ if (n < 0n) throw new Error("u256 must be non-negative");
26
+ return ["0x" + (n & U128_MASK).toString(16), "0x" + (n >> 128n).toString(16)];
27
+ }
28
+ function amountToBase(amount, decimals) {
29
+ const t = amount.trim();
30
+ if (!/^\d+(\.\d+)?$/.test(t)) throw new Error(`Invalid amount: ${amount}`);
31
+ const [whole, frac = ""] = t.split(".");
32
+ if (frac.length > decimals) {
33
+ throw new Error(`Too many decimal places (max ${decimals})`);
34
+ }
35
+ const padded = (frac + "0".repeat(decimals)).slice(0, decimals);
36
+ return BigInt(whole) * 10n ** BigInt(decimals) + BigInt(padded || "0");
37
+ }
38
+ function defineActions(templates) {
39
+ const seen = /* @__PURE__ */ new Set();
40
+ for (const t of templates) {
41
+ if (!t.key) throw new Error("ActionTemplate.key is required");
42
+ if (seen.has(t.key)) throw new Error(`Duplicate ActionTemplate key: ${t.key}`);
43
+ seen.add(t.key);
44
+ }
45
+ return templates;
46
+ }
47
+ var VOTE_CHOICES = [
48
+ { label: "Yes", value: "0x1" },
49
+ { label: "No", value: "0x0" },
50
+ { label: "Abstain", value: "0x2" }
51
+ ];
52
+ function voteTemplate(opts) {
53
+ const fields = [];
54
+ if (!opts?.governanceContract) {
55
+ fields.push({ name: "contract", label: "Governance contract", type: "address" });
56
+ }
57
+ fields.push(
58
+ { name: "proposalId", label: "Proposal ID", type: "felt" },
59
+ { name: "choice", label: "Your vote", type: "select", options: VOTE_CHOICES }
60
+ );
61
+ const labelFor = (v) => VOTE_CHOICES.find((c) => c.value === v)?.label ?? v;
62
+ return {
63
+ key: "vote",
64
+ label: "Vote",
65
+ description: "Vote on a governance proposal.",
66
+ fields,
67
+ toCalls: (v) => [
68
+ {
69
+ to: opts?.governanceContract ?? v.contract,
70
+ entrypoint: opts?.entrypoint ?? "vote",
71
+ calldata: [toFelt(v.proposalId), toFelt(v.choice)]
72
+ }
73
+ ],
74
+ title: (v) => `Vote ${labelFor(v.choice)} on Proposal #${v.proposalId}`
75
+ };
76
+ }
77
+ var SN_MAIN_CHAIN_ID = "0x534e5f4d41494e";
78
+ var OE_WINDOW_SECONDS = Number(backend.MAX_OE_VALIDITY_WINDOW_SECONDS);
79
+ var OE_AFTER_SKEW_SECONDS = 60;
80
+ function toOeCalls(calls) {
81
+ return calls.map((c) => ({
82
+ contractAddress: c.to,
83
+ entrypoint: c.entrypoint,
84
+ calldata: c.calldata
85
+ }));
86
+ }
87
+ function serializeEnvelope(env) {
88
+ return env.map((f) => "0x" + f.toString(16)).join(",");
89
+ }
90
+ function deserializeEnvelope(s) {
91
+ return s.split(",").filter(Boolean).map((f) => BigInt(f));
92
+ }
93
+ function newOeNonce(nowMs, rand) {
94
+ return BigInt(nowMs) << 24n | BigInt(Math.floor(rand * 16777215));
95
+ }
96
+ function deriveExecuteAfter(oeExecuteBefore) {
97
+ return BigInt(oeExecuteBefore) - BigInt(OE_WINDOW_SECONDS);
98
+ }
99
+ async function buildActionProposal(params) {
100
+ const nowMs = params.nowMs ?? Date.now();
101
+ const nonce = newOeNonce(nowMs, params.rand ?? Math.random());
102
+ const executeAfter = BigInt(Math.floor(nowMs / 1e3) - OE_AFTER_SKEW_SECONDS);
103
+ const executeBefore = executeAfter + BigInt(OE_WINDOW_SECONDS);
104
+ const oe = backend.buildOutsideExecution({
105
+ nonce,
106
+ calls: toOeCalls(params.calls),
107
+ caller: backend.ANY_CALLER_FELT,
108
+ executeAfter,
109
+ executeBefore
110
+ });
111
+ const messageHash = backend.computeOeHash(oe, params.walletAddress, params.chainId ?? SN_MAIN_CHAIN_ID);
112
+ const inner = await params.sign({
113
+ messageHash,
114
+ ownerIndex: params.ownerIndex ?? 0n
115
+ });
116
+ return {
117
+ oeMessageHash: "0x" + messageHash.toString(16),
118
+ oeNonce: "0x" + nonce.toString(16),
119
+ oeExecuteBefore: executeBefore.toString(),
120
+ proposerSignature: serializeEnvelope(inner)
121
+ };
122
+ }
123
+ async function signActionApproval(params) {
124
+ const inner = await params.sign({
125
+ messageHash: BigInt(params.oeMessageHash),
126
+ ownerIndex: params.ownerIndex
127
+ });
128
+ return serializeEnvelope(inner);
129
+ }
130
+ function assembleActionExecuteCalldata(params) {
131
+ const oe = backend.buildOutsideExecution({
132
+ nonce: BigInt(params.oeNonce),
133
+ calls: toOeCalls(params.calls),
134
+ caller: backend.ANY_CALLER_FELT,
135
+ executeAfter: deriveExecuteAfter(params.oeExecuteBefore),
136
+ executeBefore: BigInt(params.oeExecuteBefore)
137
+ });
138
+ const inner = params.signatures.map(deserializeEnvelope);
139
+ if (inner.length < Math.max(1, params.requiredApprovals)) {
140
+ throw new Error(
141
+ `Not enough signatures: have ${inner.length}, need ${params.requiredApprovals}.`
142
+ );
143
+ }
144
+ const signature = params.requiredApprovals <= 1 ? inner[0] : backend.buildThresholdEnvelope({ innerEnvelopes: inner });
145
+ return backend.serializeExecuteFromOutsideV2Calldata({
146
+ outsideExecution: oe,
147
+ signature
148
+ });
149
+ }
150
+
151
+ // src/multisig/proposals.ts
152
+ async function createProposal(params) {
153
+ const calls = params.template.toCalls(params.values);
154
+ if (calls.length === 0) {
155
+ throw new Error("Template produced no calls");
156
+ }
157
+ const title = params.template.title(params.values);
158
+ const meta = params.template.meta?.(params.values);
159
+ const proposerOwnerId = params.signer.proposerOwnerIndex ?? 0;
160
+ const proposal = await buildActionProposal({
161
+ walletAddress: params.walletAddress,
162
+ calls,
163
+ sign: params.signer.sign,
164
+ ownerIndex: BigInt(proposerOwnerId),
165
+ chainId: params.chainId,
166
+ nowMs: params.nowMs,
167
+ rand: params.rand
168
+ });
169
+ return {
170
+ proposerOwnerId,
171
+ recipient: calls[0].to,
172
+ tokenAddress: calls[0].to,
173
+ amount: "0",
174
+ title,
175
+ calls,
176
+ ...meta ? { meta } : {},
177
+ oeMessageHash: proposal.oeMessageHash,
178
+ oeNonce: proposal.oeNonce,
179
+ oeExecuteBefore: proposal.oeExecuteBefore,
180
+ requiredApprovals: params.requiredApprovals,
181
+ proposerSignature: proposal.proposerSignature,
182
+ proposerSignerKind: params.signer.signerKind
183
+ };
184
+ }
185
+ async function buildApproval(params) {
186
+ const ownerId = await params.signer.resolveOwnerIndex(params.walletAddress);
187
+ const signature = await signActionApproval({
188
+ oeMessageHash: params.proposal.oeMessageHash,
189
+ ownerIndex: BigInt(ownerId),
190
+ sign: params.signer.sign
191
+ });
192
+ return { ownerId, signature, signerKind: params.signer.signerKind };
193
+ }
194
+ function buildExecuteCalldata(proposal) {
195
+ if (!proposal.calls || proposal.calls.length === 0) {
196
+ throw new Error("Proposal has no calls to execute");
197
+ }
198
+ if (!proposal.oeNonce || !proposal.oeExecuteBefore) {
199
+ throw new Error("Proposal is missing OE params (nonce / executeBefore)");
200
+ }
201
+ const signatures = [...proposal.signatures].sort((a, b) => a.ownerId - b.ownerId).map((s) => s.signature);
202
+ return assembleActionExecuteCalldata({
203
+ calls: proposal.calls,
204
+ oeNonce: proposal.oeNonce,
205
+ oeExecuteBefore: proposal.oeExecuteBefore,
206
+ signatures,
207
+ requiredApprovals: proposal.requiredApprovals
208
+ });
209
+ }
210
+ var proposalsKey = (walletAddress) => ["chipi-multisig-proposals", walletAddress];
211
+ function useProposeAction(config) {
212
+ const qc = reactQuery.useQueryClient();
213
+ return reactQuery.useMutation({
214
+ mutationFn: async (input) => {
215
+ const requiredApprovals = await config.getRequiredApprovals();
216
+ const body = await createProposal({
217
+ template: input.template,
218
+ values: input.values,
219
+ walletAddress: config.walletAddress,
220
+ requiredApprovals,
221
+ signer: config.signer,
222
+ chainId: config.chainId
223
+ });
224
+ return config.transport.propose(body);
225
+ },
226
+ onSuccess: () => qc.invalidateQueries({
227
+ queryKey: proposalsKey(config.walletAddress)
228
+ })
229
+ });
230
+ }
231
+ function useTreasuryProposals(config) {
232
+ const qc = reactQuery.useQueryClient();
233
+ const invalidate = () => qc.invalidateQueries({ queryKey: proposalsKey(config.walletAddress) });
234
+ const proposals = reactQuery.useQuery({
235
+ queryKey: proposalsKey(config.walletAddress),
236
+ staleTime: 30 * 1e3,
237
+ queryFn: () => config.transport.list()
238
+ });
239
+ const approve = reactQuery.useMutation({
240
+ mutationFn: async (proposal) => {
241
+ const body = await buildApproval({
242
+ proposal,
243
+ walletAddress: config.walletAddress,
244
+ signer: config.signer
245
+ });
246
+ return config.transport.sign(proposal.id, body);
247
+ },
248
+ onSuccess: invalidate
249
+ });
250
+ const execute = reactQuery.useMutation({
251
+ mutationFn: (proposal) => config.transport.execute(proposal.id, buildExecuteCalldata(proposal)),
252
+ onSuccess: invalidate
253
+ });
254
+ return { proposals, approve, execute };
255
+ }
256
+
257
+ exports.FELT_PRIME = FELT_PRIME;
258
+ exports.OE_WINDOW_SECONDS = OE_WINDOW_SECONDS;
259
+ exports.SN_MAIN_CHAIN_ID = SN_MAIN_CHAIN_ID;
260
+ exports.amountToBase = amountToBase;
261
+ exports.assembleActionExecuteCalldata = assembleActionExecuteCalldata;
262
+ exports.buildActionProposal = buildActionProposal;
263
+ exports.buildApproval = buildApproval;
264
+ exports.buildExecuteCalldata = buildExecuteCalldata;
265
+ exports.createProposal = createProposal;
266
+ exports.defineActions = defineActions;
267
+ exports.deriveExecuteAfter = deriveExecuteAfter;
268
+ exports.deserializeEnvelope = deserializeEnvelope;
269
+ exports.newOeNonce = newOeNonce;
270
+ exports.serializeEnvelope = serializeEnvelope;
271
+ exports.signActionApproval = signActionApproval;
272
+ exports.toFelt = toFelt;
273
+ exports.u256 = u256;
274
+ exports.useProposeAction = useProposeAction;
275
+ exports.useTreasuryProposals = useTreasuryProposals;
276
+ exports.voteTemplate = voteTemplate;
277
+ //# sourceMappingURL=multisig.js.map
278
+ //# sourceMappingURL=multisig.js.map