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