@chipi-stack/chipi-react 14.8.0 → 14.10.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 +33 -0
- package/dist/hooks.d.mts +7 -2619
- package/dist/hooks.d.ts +7 -2619
- package/dist/hooks.js +19581 -211
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.mjs +19424 -81
- package/dist/hooks.mjs.map +1 -1
- package/dist/index-D9-uVlda.d.mts +2861 -0
- package/dist/index-D9-uVlda.d.ts +2861 -0
- package/dist/index.d.mts +61 -2
- package/dist/index.d.ts +61 -2
- package/dist/index.js +19696 -178
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +19675 -186
- package/dist/index.mjs.map +1 -1
- package/dist/multisig.d.mts +133 -1
- package/dist/multisig.d.ts +133 -1
- package/dist/multisig.js +467 -1
- package/dist/multisig.js.map +1 -1
- package/dist/multisig.mjs +459 -2
- package/dist/multisig.mjs.map +1 -1
- package/package.json +7 -5
package/dist/multisig.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { MAX_OE_VALIDITY_WINDOW_SECONDS, buildOutsideExecution, ANY_CALLER_FELT, computeOeHash, buildThresholdEnvelope, serializeExecuteFromOutsideV2Calldata } from '@chipi-stack/backend';
|
|
2
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';
|
|
3
5
|
|
|
4
6
|
// src/multisig/action-template.ts
|
|
5
7
|
var FELT_PRIME = BigInt(
|
|
@@ -172,6 +174,7 @@ async function createProposal(params) {
|
|
|
172
174
|
title,
|
|
173
175
|
calls,
|
|
174
176
|
...meta ? { meta } : {},
|
|
177
|
+
...params.template.risk ? { risk: params.template.risk } : {},
|
|
175
178
|
oeMessageHash: proposal.oeMessageHash,
|
|
176
179
|
oeNonce: proposal.oeNonce,
|
|
177
180
|
oeExecuteBefore: proposal.oeExecuteBefore,
|
|
@@ -196,7 +199,8 @@ function buildExecuteCalldata(proposal) {
|
|
|
196
199
|
if (!proposal.oeNonce || !proposal.oeExecuteBefore) {
|
|
197
200
|
throw new Error("Proposal is missing OE params (nonce / executeBefore)");
|
|
198
201
|
}
|
|
199
|
-
const
|
|
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);
|
|
200
204
|
return assembleActionExecuteCalldata({
|
|
201
205
|
calls: proposal.calls,
|
|
202
206
|
oeNonce: proposal.oeNonce,
|
|
@@ -252,6 +256,459 @@ function useTreasuryProposals(config) {
|
|
|
252
256
|
return { proposals, approve, execute };
|
|
253
257
|
}
|
|
254
258
|
|
|
255
|
-
|
|
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 };
|
|
256
713
|
//# sourceMappingURL=multisig.mjs.map
|
|
257
714
|
//# sourceMappingURL=multisig.mjs.map
|