@chipi-stack/chipi-react 14.7.0 → 14.9.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 +41 -0
- package/dist/hooks.d.mts +6 -2619
- package/dist/hooks.d.ts +6 -2619
- package/dist/hooks.js +18553 -211
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.mjs +18400 -80
- package/dist/hooks.mjs.map +1 -1
- package/dist/index-B8e6TdyG.d.mts +2743 -0
- package/dist/index-B8e6TdyG.d.ts +2743 -0
- package/dist/index.d.mts +60 -2
- package/dist/index.d.ts +60 -2
- package/dist/index.js +18668 -178
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +18651 -185
- package/dist/index.mjs.map +1 -1
- package/dist/multisig.d.mts +482 -0
- package/dist/multisig.d.ts +482 -0
- package/dist/multisig.js +744 -0
- package/dist/multisig.js.map +1 -0
- package/dist/multisig.mjs +714 -0
- package/dist/multisig.mjs.map +1 -0
- package/package.json +16 -4
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
import { MAX_OE_VALIDITY_WINDOW_SECONDS, buildOutsideExecution, ANY_CALLER_FELT, computeOeHash, buildThresholdEnvelope, serializeExecuteFromOutsideV2Calldata } from '@chipi-stack/backend';
|
|
2
|
+
import { useQueryClient, useMutation, useQuery } from '@tanstack/react-query';
|
|
3
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import { useState, useEffect, useMemo } from 'react';
|
|
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(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 = buildOutsideExecution({
|
|
105
|
+
nonce,
|
|
106
|
+
calls: toOeCalls(params.calls),
|
|
107
|
+
caller: ANY_CALLER_FELT,
|
|
108
|
+
executeAfter,
|
|
109
|
+
executeBefore
|
|
110
|
+
});
|
|
111
|
+
const messageHash = 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 = buildOutsideExecution({
|
|
132
|
+
nonce: BigInt(params.oeNonce),
|
|
133
|
+
calls: toOeCalls(params.calls),
|
|
134
|
+
caller: 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] : buildThresholdEnvelope({ innerEnvelopes: inner });
|
|
145
|
+
return 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
|
+
...params.template.risk ? { risk: params.template.risk } : {},
|
|
178
|
+
oeMessageHash: proposal.oeMessageHash,
|
|
179
|
+
oeNonce: proposal.oeNonce,
|
|
180
|
+
oeExecuteBefore: proposal.oeExecuteBefore,
|
|
181
|
+
requiredApprovals: params.requiredApprovals,
|
|
182
|
+
proposerSignature: proposal.proposerSignature,
|
|
183
|
+
proposerSignerKind: params.signer.signerKind
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
async function buildApproval(params) {
|
|
187
|
+
const ownerId = await params.signer.resolveOwnerIndex(params.walletAddress);
|
|
188
|
+
const signature = await signActionApproval({
|
|
189
|
+
oeMessageHash: params.proposal.oeMessageHash,
|
|
190
|
+
ownerIndex: BigInt(ownerId),
|
|
191
|
+
sign: params.signer.sign
|
|
192
|
+
});
|
|
193
|
+
return { ownerId, signature, signerKind: params.signer.signerKind };
|
|
194
|
+
}
|
|
195
|
+
function buildExecuteCalldata(proposal) {
|
|
196
|
+
if (!proposal.calls || proposal.calls.length === 0) {
|
|
197
|
+
throw new Error("Proposal has no calls to execute");
|
|
198
|
+
}
|
|
199
|
+
if (!proposal.oeNonce || !proposal.oeExecuteBefore) {
|
|
200
|
+
throw new Error("Proposal is missing OE params (nonce / executeBefore)");
|
|
201
|
+
}
|
|
202
|
+
const need = Math.max(1, proposal.requiredApprovals);
|
|
203
|
+
const signatures = [...proposal.signatures].sort((a, b) => a.ownerId - b.ownerId).slice(0, need).map((s) => s.signature);
|
|
204
|
+
return assembleActionExecuteCalldata({
|
|
205
|
+
calls: proposal.calls,
|
|
206
|
+
oeNonce: proposal.oeNonce,
|
|
207
|
+
oeExecuteBefore: proposal.oeExecuteBefore,
|
|
208
|
+
signatures,
|
|
209
|
+
requiredApprovals: proposal.requiredApprovals
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
var proposalsKey = (walletAddress) => ["chipi-multisig-proposals", walletAddress];
|
|
213
|
+
function useProposeAction(config) {
|
|
214
|
+
const qc = useQueryClient();
|
|
215
|
+
return useMutation({
|
|
216
|
+
mutationFn: async (input) => {
|
|
217
|
+
const requiredApprovals = await config.getRequiredApprovals();
|
|
218
|
+
const body = await createProposal({
|
|
219
|
+
template: input.template,
|
|
220
|
+
values: input.values,
|
|
221
|
+
walletAddress: config.walletAddress,
|
|
222
|
+
requiredApprovals,
|
|
223
|
+
signer: config.signer,
|
|
224
|
+
chainId: config.chainId
|
|
225
|
+
});
|
|
226
|
+
return config.transport.propose(body);
|
|
227
|
+
},
|
|
228
|
+
onSuccess: () => qc.invalidateQueries({
|
|
229
|
+
queryKey: proposalsKey(config.walletAddress)
|
|
230
|
+
})
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
function useTreasuryProposals(config) {
|
|
234
|
+
const qc = useQueryClient();
|
|
235
|
+
const invalidate = () => qc.invalidateQueries({ queryKey: proposalsKey(config.walletAddress) });
|
|
236
|
+
const proposals = useQuery({
|
|
237
|
+
queryKey: proposalsKey(config.walletAddress),
|
|
238
|
+
staleTime: 30 * 1e3,
|
|
239
|
+
queryFn: () => config.transport.list()
|
|
240
|
+
});
|
|
241
|
+
const approve = useMutation({
|
|
242
|
+
mutationFn: async (proposal) => {
|
|
243
|
+
const body = await buildApproval({
|
|
244
|
+
proposal,
|
|
245
|
+
walletAddress: config.walletAddress,
|
|
246
|
+
signer: config.signer
|
|
247
|
+
});
|
|
248
|
+
return config.transport.sign(proposal.id, body);
|
|
249
|
+
},
|
|
250
|
+
onSuccess: invalidate
|
|
251
|
+
});
|
|
252
|
+
const execute = useMutation({
|
|
253
|
+
mutationFn: (proposal) => config.transport.execute(proposal.id, buildExecuteCalldata(proposal)),
|
|
254
|
+
onSuccess: invalidate
|
|
255
|
+
});
|
|
256
|
+
return { proposals, approve, execute };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/multisig/components/theme.ts
|
|
260
|
+
var DEFAULT_THEME = {
|
|
261
|
+
accent: "#4f46e5",
|
|
262
|
+
accentText: "#ffffff",
|
|
263
|
+
surface: "#fffdf8",
|
|
264
|
+
surfaceMuted: "#f4f1ea",
|
|
265
|
+
text: "#111111",
|
|
266
|
+
textMuted: "#6b7280",
|
|
267
|
+
danger: "#dc2626",
|
|
268
|
+
success: "#16a34a",
|
|
269
|
+
border: "#111111",
|
|
270
|
+
radius: "12px",
|
|
271
|
+
shadow: "4px 4px 0 0 #111111",
|
|
272
|
+
font: "ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif"
|
|
273
|
+
};
|
|
274
|
+
function themeVars(theme) {
|
|
275
|
+
const t = { ...DEFAULT_THEME, ...theme };
|
|
276
|
+
return {
|
|
277
|
+
"--cgov-accent": t.accent,
|
|
278
|
+
"--cgov-accent-text": t.accentText,
|
|
279
|
+
"--cgov-surface": t.surface,
|
|
280
|
+
"--cgov-surface-muted": t.surfaceMuted,
|
|
281
|
+
"--cgov-text": t.text,
|
|
282
|
+
"--cgov-text-muted": t.textMuted,
|
|
283
|
+
"--cgov-danger": t.danger,
|
|
284
|
+
"--cgov-success": t.success,
|
|
285
|
+
"--cgov-border": t.border,
|
|
286
|
+
"--cgov-radius": t.radius,
|
|
287
|
+
"--cgov-shadow": t.shadow,
|
|
288
|
+
"--cgov-font": t.font
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
var STYLE_ID = "chipi-gov-styles";
|
|
292
|
+
var STYLE_TEXT = `
|
|
293
|
+
.cgov-root{font-family:var(--cgov-font);color:var(--cgov-text);box-sizing:border-box}
|
|
294
|
+
.cgov-root *,.cgov-root *::before,.cgov-root *::after{box-sizing:inherit}
|
|
295
|
+
.cgov-card{background:var(--cgov-surface);border:2px solid var(--cgov-border);border-radius:var(--cgov-radius);box-shadow:var(--cgov-shadow)}
|
|
296
|
+
.cgov-btn{display:inline-flex;align-items:center;gap:.5em;font:inherit;font-weight:600;cursor:pointer;border:2px solid var(--cgov-border);border-radius:calc(var(--cgov-radius) * .75);padding:.5em 1em;background:var(--cgov-surface);color:var(--cgov-text);transition:transform .06s ease}
|
|
297
|
+
.cgov-btn:hover:not(:disabled){transform:translate(-1px,-1px)}
|
|
298
|
+
.cgov-btn:active:not(:disabled){transform:translate(1px,1px)}
|
|
299
|
+
.cgov-btn:disabled{opacity:.5;cursor:not-allowed}
|
|
300
|
+
.cgov-btn-primary{background:var(--cgov-accent);color:var(--cgov-accent-text)}
|
|
301
|
+
.cgov-btn-sm{font-size:.8125rem;padding:.35em .8em}
|
|
302
|
+
.cgov-input,.cgov-select{font:inherit;width:100%;padding:.5em .75em;border:2px solid var(--cgov-border);border-radius:calc(var(--cgov-radius) * .6);background:var(--cgov-surface-muted);color:var(--cgov-text)}
|
|
303
|
+
.cgov-input:focus,.cgov-select:focus{outline:3px solid color-mix(in srgb, var(--cgov-accent) 40%, transparent);outline-offset:1px}
|
|
304
|
+
.cgov-label{display:block;font-size:.8125rem;font-weight:600;margin:0 0 .3em}
|
|
305
|
+
.cgov-help{font-size:.75rem;color:var(--cgov-text-muted);margin:.25em 0 0}
|
|
306
|
+
.cgov-field{margin-bottom:.9rem}
|
|
307
|
+
.cgov-field-error{font-size:.75rem;color:var(--cgov-danger);margin:.25em 0 0}
|
|
308
|
+
.cgov-overlay{position:fixed;inset:0;background:rgba(0,0,0,.45);display:flex;align-items:flex-end;justify-content:center;z-index:2147483000;padding:1rem}
|
|
309
|
+
@media (min-width:640px){.cgov-overlay{align-items:center}}
|
|
310
|
+
.cgov-dialog{width:100%;max-width:28rem;max-height:calc(100vh - 2rem);overflow-y:auto;padding:1.25rem}
|
|
311
|
+
.cgov-dialog-title{font-size:1.05rem;font-weight:700;margin:0 0 .25rem}
|
|
312
|
+
.cgov-dialog-desc{font-size:.8125rem;color:var(--cgov-text-muted);margin:0 0 1rem}
|
|
313
|
+
.cgov-preview{background:var(--cgov-surface-muted);border:2px dashed var(--cgov-border);border-radius:calc(var(--cgov-radius) * .6);padding:.75rem;margin:.25rem 0 1rem}
|
|
314
|
+
.cgov-preview-title{font-weight:700;font-size:.9375rem;margin:0}
|
|
315
|
+
.cgov-preview-rule{font-size:.75rem;color:var(--cgov-text-muted);margin:.35em 0 0}
|
|
316
|
+
.cgov-preview-call{font-family:ui-monospace,monospace;font-size:.6875rem;color:var(--cgov-text-muted);margin:.35em 0 0;word-break:break-all}
|
|
317
|
+
.cgov-tabs{display:flex;gap:.4rem;flex-wrap:wrap;margin:0 0 1rem}
|
|
318
|
+
.cgov-tab{font:inherit;font-size:.8125rem;font-weight:600;padding:.35em .8em;cursor:pointer;border:2px solid var(--cgov-border);border-radius:999px;background:var(--cgov-surface)}
|
|
319
|
+
.cgov-tab[aria-selected="true"]{background:var(--cgov-accent);color:var(--cgov-accent-text)}
|
|
320
|
+
.cgov-row{display:flex;align-items:center;gap:.75rem;padding:.75rem;border-bottom:2px solid color-mix(in srgb, var(--cgov-border) 15%, transparent)}
|
|
321
|
+
.cgov-row:last-child{border-bottom:none}
|
|
322
|
+
.cgov-row-main{flex:1;min-width:0}
|
|
323
|
+
.cgov-row-title{font-weight:600;font-size:.9375rem;margin:0;overflow:hidden;text-overflow:ellipsis}
|
|
324
|
+
.cgov-row-sub{font-size:.75rem;color:var(--cgov-text-muted);margin:.15em 0 0;display:flex;gap:.5em;align-items:center;flex-wrap:wrap}
|
|
325
|
+
.cgov-chip{display:inline-block;font-size:.6875rem;font-weight:700;padding:.15em .6em;border:1.5px solid var(--cgov-border);border-radius:999px;background:var(--cgov-surface-muted)}
|
|
326
|
+
.cgov-chip-success{background:color-mix(in srgb, var(--cgov-success) 18%, transparent)}
|
|
327
|
+
.cgov-chip-accent{background:color-mix(in srgb, var(--cgov-accent) 18%, transparent)}
|
|
328
|
+
.cgov-empty{padding:1.5rem;text-align:center;color:var(--cgov-text-muted);font-size:.875rem}
|
|
329
|
+
.cgov-error{padding:.6rem .75rem;border:2px solid var(--cgov-danger);border-radius:calc(var(--cgov-radius) * .6);background:color-mix(in srgb, var(--cgov-danger) 8%, transparent);color:var(--cgov-danger);font-size:.8125rem;margin:.5rem 0}
|
|
330
|
+
.cgov-group-label{font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--cgov-text-muted);margin:1rem 0 .35rem;padding:0 .25rem}
|
|
331
|
+
.cgov-group-label:first-child{margin-top:0}
|
|
332
|
+
.cgov-spinner{display:inline-block;width:.9em;height:.9em;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:cgov-spin .7s linear infinite}
|
|
333
|
+
@keyframes cgov-spin{to{transform:rotate(360deg)}}
|
|
334
|
+
`;
|
|
335
|
+
function injectGovStyles() {
|
|
336
|
+
const doc = globalThis.document;
|
|
337
|
+
if (!doc) return;
|
|
338
|
+
if (doc.getElementById(STYLE_ID)) return;
|
|
339
|
+
const el = doc.createElement("style");
|
|
340
|
+
el.id = STYLE_ID;
|
|
341
|
+
el.textContent = STYLE_TEXT;
|
|
342
|
+
doc.head.appendChild(el);
|
|
343
|
+
}
|
|
344
|
+
function fieldSyntaxError(field, raw) {
|
|
345
|
+
if (raw.trim() === "") return `${field.label} is required`;
|
|
346
|
+
const v = raw.trim();
|
|
347
|
+
switch (field.type) {
|
|
348
|
+
case "address":
|
|
349
|
+
return /^0x[0-9a-fA-F]{1,64}$/.test(v) ? null : `${field.label} must be a 0x address`;
|
|
350
|
+
case "felt":
|
|
351
|
+
return /^(0x[0-9a-fA-F]+|\d+)$/.test(v) ? null : `${field.label} must be a felt (0x-hex or decimal)`;
|
|
352
|
+
case "amount":
|
|
353
|
+
return /^\d+(\.\d+)?$/.test(v) ? null : `${field.label} must be a positive amount`;
|
|
354
|
+
case "number":
|
|
355
|
+
case "bps":
|
|
356
|
+
case "days":
|
|
357
|
+
return /^\d+$/.test(v) ? null : `${field.label} must be a whole number`;
|
|
358
|
+
default:
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function FieldInput(props) {
|
|
363
|
+
const { field, value, onChange, error, disabled } = props;
|
|
364
|
+
const id = `cgov-field-${field.name}`;
|
|
365
|
+
return /* @__PURE__ */ jsxs("div", { className: "cgov-field", children: [
|
|
366
|
+
/* @__PURE__ */ jsx("label", { className: "cgov-label", htmlFor: id, children: field.label }),
|
|
367
|
+
field.type === "select" ? /* @__PURE__ */ jsxs(
|
|
368
|
+
"select",
|
|
369
|
+
{
|
|
370
|
+
id,
|
|
371
|
+
className: "cgov-select",
|
|
372
|
+
value,
|
|
373
|
+
disabled,
|
|
374
|
+
onChange: (e) => onChange(e.target.value),
|
|
375
|
+
children: [
|
|
376
|
+
/* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "Choose\u2026" }),
|
|
377
|
+
field.options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
|
|
378
|
+
]
|
|
379
|
+
}
|
|
380
|
+
) : /* @__PURE__ */ jsx(
|
|
381
|
+
"input",
|
|
382
|
+
{
|
|
383
|
+
id,
|
|
384
|
+
className: "cgov-input",
|
|
385
|
+
value,
|
|
386
|
+
disabled,
|
|
387
|
+
inputMode: field.type === "amount" || field.type === "number" || field.type === "bps" || field.type === "days" ? "decimal" : "text",
|
|
388
|
+
placeholder: field.type === "address" ? "0x\u2026" : field.type === "amount" ? "0.00" : void 0,
|
|
389
|
+
onChange: (e) => onChange(e.target.value)
|
|
390
|
+
}
|
|
391
|
+
),
|
|
392
|
+
"help" in field && field.help ? /* @__PURE__ */ jsx("p", { className: "cgov-help", children: field.help }) : null,
|
|
393
|
+
error ? /* @__PURE__ */ jsx("p", { className: "cgov-field-error", children: error }) : null
|
|
394
|
+
] });
|
|
395
|
+
}
|
|
396
|
+
function buildPreview(template, values) {
|
|
397
|
+
for (const f of template.fields) {
|
|
398
|
+
const err = fieldSyntaxError(f, values[f.name] ?? "");
|
|
399
|
+
if (err) return { error: err };
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
return { title: template.title(values), calls: template.toCalls(values) };
|
|
403
|
+
} catch (e) {
|
|
404
|
+
return { error: e instanceof Error ? e.message : "Invalid values" };
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function ProposeAction(props) {
|
|
408
|
+
const [open, setOpen] = useState(false);
|
|
409
|
+
const [templateKey, setTemplateKey] = useState(props.preselect ?? props.actions[0]?.key ?? "");
|
|
410
|
+
const [values, setValues] = useState({});
|
|
411
|
+
const [touched, setTouched] = useState({});
|
|
412
|
+
const [requiredApprovals, setRequiredApprovals] = useState(null);
|
|
413
|
+
const [done, setDone] = useState(null);
|
|
414
|
+
useEffect(injectGovStyles, []);
|
|
415
|
+
const template = props.actions.find((t) => t.key === templateKey) ?? props.actions[0];
|
|
416
|
+
const propose = useProposeAction({
|
|
417
|
+
walletAddress: props.walletAddress,
|
|
418
|
+
transport: props.transport,
|
|
419
|
+
signer: props.signer,
|
|
420
|
+
getRequiredApprovals: props.getRequiredApprovals,
|
|
421
|
+
chainId: props.chainId
|
|
422
|
+
});
|
|
423
|
+
useEffect(() => {
|
|
424
|
+
if (!open) return;
|
|
425
|
+
let on = true;
|
|
426
|
+
props.getRequiredApprovals().then(
|
|
427
|
+
(n) => on && setRequiredApprovals(n),
|
|
428
|
+
() => on && setRequiredApprovals(null)
|
|
429
|
+
);
|
|
430
|
+
return () => {
|
|
431
|
+
on = false;
|
|
432
|
+
};
|
|
433
|
+
}, [open]);
|
|
434
|
+
const preview = useMemo(
|
|
435
|
+
() => template ? buildPreview(template, values) : { error: "No action templates" },
|
|
436
|
+
[template, values]
|
|
437
|
+
);
|
|
438
|
+
const reset = () => {
|
|
439
|
+
setValues({});
|
|
440
|
+
setTouched({});
|
|
441
|
+
setDone(null);
|
|
442
|
+
propose.reset();
|
|
443
|
+
};
|
|
444
|
+
const close = () => {
|
|
445
|
+
setOpen(false);
|
|
446
|
+
reset();
|
|
447
|
+
};
|
|
448
|
+
const submit = async () => {
|
|
449
|
+
if (!template || "error" in preview) return;
|
|
450
|
+
try {
|
|
451
|
+
const proposal = await propose.mutateAsync({ template, values });
|
|
452
|
+
setDone(proposal);
|
|
453
|
+
props.onProposed?.(proposal);
|
|
454
|
+
} catch {
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
return /* @__PURE__ */ jsxs("div", { className: "cgov-root", style: themeVars(props.theme), children: [
|
|
458
|
+
props.trigger ? props.trigger(() => setOpen(true)) : /* @__PURE__ */ jsx("button", { type: "button", className: "cgov-btn cgov-btn-primary", onClick: () => setOpen(true), children: "Propose action" }),
|
|
459
|
+
open ? /* @__PURE__ */ jsx("div", { className: "cgov-overlay", role: "presentation", onClick: close, children: /* @__PURE__ */ jsx(
|
|
460
|
+
"div",
|
|
461
|
+
{
|
|
462
|
+
className: "cgov-card cgov-dialog cgov-root",
|
|
463
|
+
style: themeVars(props.theme),
|
|
464
|
+
role: "dialog",
|
|
465
|
+
"aria-modal": "true",
|
|
466
|
+
"aria-label": done ? "Proposal created" : "Propose an action",
|
|
467
|
+
onClick: (e) => e.stopPropagation(),
|
|
468
|
+
children: done ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
469
|
+
/* @__PURE__ */ jsx("h2", { className: "cgov-dialog-title", children: "Proposed \u2713" }),
|
|
470
|
+
/* @__PURE__ */ jsxs("p", { className: "cgov-dialog-desc", children: [
|
|
471
|
+
done.title ?? "Your action",
|
|
472
|
+
" \u2014",
|
|
473
|
+
" ",
|
|
474
|
+
done.status === "APPROVED" ? "approved and ready to execute." : `needs ${done.requiredApprovals} approval${done.requiredApprovals === 1 ? "" : "s"}.`
|
|
475
|
+
] }),
|
|
476
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "cgov-btn cgov-btn-primary", onClick: close, children: "Done" })
|
|
477
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
478
|
+
/* @__PURE__ */ jsx("h2", { className: "cgov-dialog-title", children: "Propose an action" }),
|
|
479
|
+
/* @__PURE__ */ jsx("p", { className: "cgov-dialog-desc", children: "Your team approves before anything moves on chain." }),
|
|
480
|
+
props.actions.length > 1 ? /* @__PURE__ */ jsx("div", { className: "cgov-tabs", role: "tablist", "aria-label": "Action type", children: props.actions.map((t) => /* @__PURE__ */ jsx(
|
|
481
|
+
"button",
|
|
482
|
+
{
|
|
483
|
+
type: "button",
|
|
484
|
+
role: "tab",
|
|
485
|
+
"aria-selected": t.key === template?.key,
|
|
486
|
+
className: "cgov-tab",
|
|
487
|
+
onClick: () => {
|
|
488
|
+
setTemplateKey(t.key);
|
|
489
|
+
reset();
|
|
490
|
+
},
|
|
491
|
+
children: t.label
|
|
492
|
+
},
|
|
493
|
+
t.key
|
|
494
|
+
)) }) : null,
|
|
495
|
+
template?.description ? /* @__PURE__ */ jsx("p", { className: "cgov-help", style: { marginBottom: "0.9rem" }, children: template.description }) : null,
|
|
496
|
+
template?.fields.map((f) => /* @__PURE__ */ jsx(
|
|
497
|
+
FieldInput,
|
|
498
|
+
{
|
|
499
|
+
field: f,
|
|
500
|
+
value: values[f.name] ?? "",
|
|
501
|
+
disabled: propose.isPending,
|
|
502
|
+
error: touched[f.name] ? fieldSyntaxError(f, values[f.name] ?? "") : null,
|
|
503
|
+
onChange: (raw) => {
|
|
504
|
+
setValues((v) => ({ ...v, [f.name]: raw }));
|
|
505
|
+
setTouched((t) => ({ ...t, [f.name]: true }));
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
f.name
|
|
509
|
+
)),
|
|
510
|
+
/* @__PURE__ */ jsx("div", { className: "cgov-preview", "aria-live": "polite", children: "error" in preview ? /* @__PURE__ */ jsx("p", { className: "cgov-preview-rule", children: "What this does \u2014 fill in the fields above." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
511
|
+
/* @__PURE__ */ jsx("p", { className: "cgov-preview-title", children: preview.title }),
|
|
512
|
+
preview.calls.map((c, i) => /* @__PURE__ */ jsxs("p", { className: "cgov-preview-call", children: [
|
|
513
|
+
c.entrypoint,
|
|
514
|
+
"(",
|
|
515
|
+
c.calldata.join(", "),
|
|
516
|
+
") \u2192 ",
|
|
517
|
+
c.to.slice(0, 10),
|
|
518
|
+
"\u2026"
|
|
519
|
+
] }, i)),
|
|
520
|
+
/* @__PURE__ */ jsx("p", { className: "cgov-preview-rule", children: requiredApprovals != null ? `Needs ${requiredApprovals} approval${requiredApprovals === 1 ? "" : "s"} before it executes.` : "Approval rule loads from your wallet." })
|
|
521
|
+
] }) }),
|
|
522
|
+
propose.error ? /* @__PURE__ */ jsx("div", { className: "cgov-error", role: "alert", children: propose.error instanceof Error ? propose.error.message : "Could not create the proposal. Try again." }) : null,
|
|
523
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.5rem", justifyContent: "flex-end" }, children: [
|
|
524
|
+
/* @__PURE__ */ jsx(
|
|
525
|
+
"button",
|
|
526
|
+
{
|
|
527
|
+
type: "button",
|
|
528
|
+
className: "cgov-btn",
|
|
529
|
+
onClick: close,
|
|
530
|
+
disabled: propose.isPending,
|
|
531
|
+
children: "Cancel"
|
|
532
|
+
}
|
|
533
|
+
),
|
|
534
|
+
/* @__PURE__ */ jsx(
|
|
535
|
+
"button",
|
|
536
|
+
{
|
|
537
|
+
type: "button",
|
|
538
|
+
className: "cgov-btn cgov-btn-primary",
|
|
539
|
+
disabled: "error" in preview || propose.isPending,
|
|
540
|
+
onClick: submit,
|
|
541
|
+
children: propose.isPending ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
542
|
+
/* @__PURE__ */ jsx("span", { className: "cgov-spinner", "aria-hidden": true }),
|
|
543
|
+
" Signing\u2026"
|
|
544
|
+
] }) : "Sign & propose"
|
|
545
|
+
}
|
|
546
|
+
)
|
|
547
|
+
] })
|
|
548
|
+
] })
|
|
549
|
+
}
|
|
550
|
+
) }) : null
|
|
551
|
+
] });
|
|
552
|
+
}
|
|
553
|
+
var STATUS_LABEL = {
|
|
554
|
+
PROPOSED: "Needs approvals",
|
|
555
|
+
APPROVED: "Ready to execute",
|
|
556
|
+
EXECUTED: "Executed",
|
|
557
|
+
CANCELED: "Canceled",
|
|
558
|
+
EXPIRED: "Expired"
|
|
559
|
+
};
|
|
560
|
+
function proposalTitle(p) {
|
|
561
|
+
return p.title?.trim() || "Treasury action";
|
|
562
|
+
}
|
|
563
|
+
function ProposalRow(props) {
|
|
564
|
+
const p = props.proposal;
|
|
565
|
+
const signed = props.myOwnerIndex != null && p.signatures.some((s) => s.ownerId === props.myOwnerIndex);
|
|
566
|
+
const canApprove = p.status === "PROPOSED" && props.myOwnerIndex != null && !signed;
|
|
567
|
+
const canExecute = p.status === "APPROVED";
|
|
568
|
+
const label = props.agentLabel ?? "Agent";
|
|
569
|
+
const title = props.isAgent ? `${label} wants: ${proposalTitle(p)}` : proposalTitle(p);
|
|
570
|
+
return /* @__PURE__ */ jsxs("div", { className: "cgov-row", children: [
|
|
571
|
+
/* @__PURE__ */ jsxs("div", { className: "cgov-row-main", children: [
|
|
572
|
+
/* @__PURE__ */ jsx("p", { className: "cgov-row-title", children: title }),
|
|
573
|
+
/* @__PURE__ */ jsxs("div", { className: "cgov-row-sub", children: [
|
|
574
|
+
props.isAgent ? /* @__PURE__ */ jsx("span", { className: "cgov-chip cgov-chip-accent", children: label }) : null,
|
|
575
|
+
/* @__PURE__ */ jsx(
|
|
576
|
+
"span",
|
|
577
|
+
{
|
|
578
|
+
className: `cgov-chip${p.status === "EXECUTED" ? " cgov-chip-success" : p.status === "APPROVED" ? " cgov-chip-accent" : ""}`,
|
|
579
|
+
children: STATUS_LABEL[p.status]
|
|
580
|
+
}
|
|
581
|
+
),
|
|
582
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
583
|
+
p.signatures.length,
|
|
584
|
+
" of ",
|
|
585
|
+
p.requiredApprovals,
|
|
586
|
+
" approvals"
|
|
587
|
+
] }),
|
|
588
|
+
p.risk === "SENSITIVE" ? /* @__PURE__ */ jsx("span", { className: "cgov-chip", children: "Sensitive" }) : null,
|
|
589
|
+
signed && p.status === "PROPOSED" ? /* @__PURE__ */ jsx("span", { children: "\xB7 you approved" }) : null,
|
|
590
|
+
p.status === "EXECUTED" && p.executedTxHash && props.explorerTxUrl ? /* @__PURE__ */ jsx(
|
|
591
|
+
"a",
|
|
592
|
+
{
|
|
593
|
+
href: props.explorerTxUrl(p.executedTxHash),
|
|
594
|
+
target: "_blank",
|
|
595
|
+
rel: "noopener noreferrer",
|
|
596
|
+
children: "receipt \u2197"
|
|
597
|
+
}
|
|
598
|
+
) : null,
|
|
599
|
+
props.renderContext ? /* @__PURE__ */ jsx("span", { children: props.renderContext(p) }) : null
|
|
600
|
+
] })
|
|
601
|
+
] }),
|
|
602
|
+
canApprove ? /* @__PURE__ */ jsx(
|
|
603
|
+
"button",
|
|
604
|
+
{
|
|
605
|
+
type: "button",
|
|
606
|
+
className: "cgov-btn cgov-btn-primary cgov-btn-sm",
|
|
607
|
+
disabled: props.busy,
|
|
608
|
+
onClick: () => props.onApprove(p),
|
|
609
|
+
children: "Approve"
|
|
610
|
+
}
|
|
611
|
+
) : canExecute ? /* @__PURE__ */ jsx(
|
|
612
|
+
"button",
|
|
613
|
+
{
|
|
614
|
+
type: "button",
|
|
615
|
+
className: "cgov-btn cgov-btn-primary cgov-btn-sm",
|
|
616
|
+
disabled: props.busy,
|
|
617
|
+
onClick: () => props.onExecute(p),
|
|
618
|
+
children: "Execute"
|
|
619
|
+
}
|
|
620
|
+
) : null
|
|
621
|
+
] });
|
|
622
|
+
}
|
|
623
|
+
function Approvals(props) {
|
|
624
|
+
const filter = props.filter ?? "actionable";
|
|
625
|
+
const [myOwnerIndex, setMyOwnerIndex] = useState(null);
|
|
626
|
+
const [actionError, setActionError] = useState(null);
|
|
627
|
+
useEffect(injectGovStyles, []);
|
|
628
|
+
useEffect(() => {
|
|
629
|
+
let on = true;
|
|
630
|
+
props.signer.resolveOwnerIndex(props.walletAddress).then(
|
|
631
|
+
(i) => on && setMyOwnerIndex(i),
|
|
632
|
+
() => on && setMyOwnerIndex(null)
|
|
633
|
+
// not an owner on this device → read-only
|
|
634
|
+
);
|
|
635
|
+
return () => {
|
|
636
|
+
on = false;
|
|
637
|
+
};
|
|
638
|
+
}, [props.walletAddress]);
|
|
639
|
+
const { proposals, approve, execute } = useTreasuryProposals({
|
|
640
|
+
walletAddress: props.walletAddress,
|
|
641
|
+
transport: props.transport,
|
|
642
|
+
signer: props.signer
|
|
643
|
+
});
|
|
644
|
+
const busy = approve.isPending || execute.isPending;
|
|
645
|
+
const onApprove = async (p) => {
|
|
646
|
+
setActionError(null);
|
|
647
|
+
try {
|
|
648
|
+
await approve.mutateAsync(p);
|
|
649
|
+
} catch (e) {
|
|
650
|
+
setActionError(e instanceof Error ? e.message : "Could not approve. Try again.");
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
const onExecute = async (p) => {
|
|
654
|
+
setActionError(null);
|
|
655
|
+
try {
|
|
656
|
+
const res = await execute.mutateAsync(p);
|
|
657
|
+
props.onExecuted?.(p, res.executedTxHash ?? res.transactionHash);
|
|
658
|
+
} catch (e) {
|
|
659
|
+
setActionError(e instanceof Error ? e.message : "Could not execute. Try again.");
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
const items = (proposals.data?.items ?? []).filter((p) => {
|
|
663
|
+
if (filter === "all") return true;
|
|
664
|
+
if (filter === "pending") return p.status === "PROPOSED" || p.status === "APPROVED";
|
|
665
|
+
return p.status === "APPROVED" || p.status === "PROPOSED" && (myOwnerIndex == null || !p.signatures.some((s) => s.ownerId === myOwnerIndex));
|
|
666
|
+
});
|
|
667
|
+
return /* @__PURE__ */ jsxs("div", { className: "cgov-root", style: themeVars(props.theme), children: [
|
|
668
|
+
/* @__PURE__ */ jsx("div", { className: "cgov-card", children: proposals.isLoading ? /* @__PURE__ */ jsxs("div", { className: "cgov-empty", children: [
|
|
669
|
+
/* @__PURE__ */ jsx("span", { className: "cgov-spinner", "aria-hidden": true }),
|
|
670
|
+
" Loading\u2026"
|
|
671
|
+
] }) : proposals.error ? /* @__PURE__ */ jsx("div", { className: "cgov-empty", children: "Could not load proposals." }) : items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "cgov-empty", children: props.empty ?? "You're all caught up." }) : items.map((p) => /* @__PURE__ */ jsx(
|
|
672
|
+
ProposalRow,
|
|
673
|
+
{
|
|
674
|
+
proposal: p,
|
|
675
|
+
myOwnerIndex,
|
|
676
|
+
busy,
|
|
677
|
+
onApprove,
|
|
678
|
+
onExecute,
|
|
679
|
+
renderContext: props.renderContext,
|
|
680
|
+
explorerTxUrl: props.explorerTxUrl,
|
|
681
|
+
isAgent: props.isAgentProposal?.(p) ?? false,
|
|
682
|
+
agentLabel: props.agentLabel
|
|
683
|
+
},
|
|
684
|
+
p.id
|
|
685
|
+
)) }),
|
|
686
|
+
actionError ? /* @__PURE__ */ jsx("div", { className: "cgov-error", role: "alert", children: actionError }) : null
|
|
687
|
+
] });
|
|
688
|
+
}
|
|
689
|
+
function ApprovalInbox(props) {
|
|
690
|
+
useEffect(injectGovStyles, []);
|
|
691
|
+
return /* @__PURE__ */ jsx("div", { className: "cgov-root", style: themeVars(props.theme), children: props.treasuries.map((t) => /* @__PURE__ */ jsxs("section", { "aria-label": t.label, children: [
|
|
692
|
+
/* @__PURE__ */ jsx("p", { className: "cgov-group-label", children: t.label }),
|
|
693
|
+
/* @__PURE__ */ jsx(
|
|
694
|
+
Approvals,
|
|
695
|
+
{
|
|
696
|
+
walletAddress: t.walletAddress,
|
|
697
|
+
transport: t.transport,
|
|
698
|
+
signer: t.signer,
|
|
699
|
+
renderContext: t.renderContext,
|
|
700
|
+
explorerTxUrl: t.explorerTxUrl,
|
|
701
|
+
isAgentProposal: t.isAgentProposal,
|
|
702
|
+
agentLabel: t.agentLabel,
|
|
703
|
+
filter: "actionable",
|
|
704
|
+
theme: props.theme,
|
|
705
|
+
empty: props.onEmpty ?? "All caught up.",
|
|
706
|
+
onExecuted: (p, tx) => props.onExecuted?.(t, p, tx)
|
|
707
|
+
}
|
|
708
|
+
)
|
|
709
|
+
] }, t.walletAddress)) });
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
export { ApprovalInbox, Approvals, DEFAULT_THEME, FELT_PRIME, FieldInput, OE_WINDOW_SECONDS, ProposeAction, SN_MAIN_CHAIN_ID, amountToBase, assembleActionExecuteCalldata, buildActionProposal, buildApproval, buildExecuteCalldata, createProposal, defineActions, deriveExecuteAfter, deserializeEnvelope, fieldSyntaxError, injectGovStyles, newOeNonce, proposalTitle, serializeEnvelope, signActionApproval, themeVars, toFelt, u256, useProposeAction, useTreasuryProposals, voteTemplate };
|
|
713
|
+
//# sourceMappingURL=multisig.mjs.map
|
|
714
|
+
//# sourceMappingURL=multisig.mjs.map
|