@@ -2,7 +2,10 @@ import { useEffect, useState } from 'react'
22import { formatEther , parseEther , type Address } from 'viem'
33import { useWaitForTransactionReceipt } from 'wagmi'
44
5+ import { ops } from '@intuition-fee-proxy/safe-tx'
56import { useSetFees } from '../hooks/useProxy'
7+ import { useSafeAdmin } from '../hooks/useSafeAdmin'
8+ import { useSafePropose } from '../hooks/useSafePropose'
69
710interface Props {
811 proxy : Address
@@ -19,6 +22,9 @@ export function SetFeesPanel({ proxy, currentFixed, currentPct, onDone }: Props)
1922 useSetFees ( proxy )
2023 const receipt = useWaitForTransactionReceipt ( { hash } )
2124
25+ const { safe } = useSafeAdmin ( proxy )
26+ const safePropose = useSafePropose ( { safeAddress : safe } )
27+
2228 useEffect ( ( ) => {
2329 if ( receipt . isSuccess ) onDone ( )
2430 } , [ hash , receipt . isSuccess ] )
@@ -47,12 +53,33 @@ export function SetFeesPanel({ proxy, currentFixed, currentPct, onDone }: Props)
4753 }
4854 }
4955
56+ async function onProposeFixed ( ) {
57+ if ( ! fixedValid || ! safe ) return
58+ safePropose . reset ( )
59+ try {
60+ await safePropose . propose ( ops . v2Admin . setDepositFixedFee ( proxy , parseEther ( fixedEth ) ) )
61+ } catch ( e ) {
62+ console . error ( e )
63+ }
64+ }
65+
66+ async function onProposePct ( ) {
67+ if ( ! pctValid || ! safe ) return
68+ safePropose . reset ( )
69+ try {
70+ await safePropose . propose ( ops . v2Admin . setDepositPercentageFee ( proxy , BigInt ( pctBps ) ) )
71+ } catch ( e ) {
72+ console . error ( e )
73+ }
74+ }
75+
5076 return (
5177 < section className = "card space-y-4" >
5278 < div >
5379 < h2 className = "font-semibold" > Update fees</ h2 >
5480 < p className = "text-xs text-subtle" >
55- Admin-only. Takes effect immediately.
81+ Admin-only. Direct write takes effect immediately. Safe propose
82+ opens a multisig transaction for owners to co-sign in Den.
5683 </ p >
5784 </ div >
5885
@@ -70,11 +97,21 @@ export function SetFeesPanel({ proxy, currentFixed, currentPct, onDone }: Props)
7097 < button
7198 type = "button"
7299 onClick = { onUpdateFixed }
73- disabled = { ! fixedValid || isPending }
100+ disabled = { ! fixedValid || isPending || safePropose . isProposing }
74101 className = "btn-primary w-full mt-1"
75102 >
76103 Update fixed
77104 </ button >
105+ { safe && (
106+ < button
107+ type = "button"
108+ onClick = { onProposeFixed }
109+ disabled = { ! fixedValid || isPending || safePropose . isProposing }
110+ className = "btn-secondary w-full mt-1 text-xs"
111+ >
112+ { safePropose . isProposing ? 'Proposing…' : 'Propose via Safe' }
113+ </ button >
114+ ) }
78115 </ label >
79116
80117 < label className = "block space-y-1" >
@@ -91,14 +128,51 @@ export function SetFeesPanel({ proxy, currentFixed, currentPct, onDone }: Props)
91128 < button
92129 type = "button"
93130 onClick = { onUpdatePct }
94- disabled = { ! pctValid || isPending }
131+ disabled = { ! pctValid || isPending || safePropose . isProposing }
95132 className = "btn-primary w-full mt-1"
96133 >
97134 Update percentage
98135 </ button >
136+ { safe && (
137+ < button
138+ type = "button"
139+ onClick = { onProposePct }
140+ disabled = { ! pctValid || isPending || safePropose . isProposing }
141+ className = "btn-secondary w-full mt-1 text-xs"
142+ >
143+ { safePropose . isProposing ? 'Proposing…' : 'Propose via Safe' }
144+ </ button >
145+ ) }
99146 </ label >
100147 </ div >
101148
149+ { safePropose . proposed && (
150+ < div className = "rounded-md border border-emerald-400/30 bg-emerald-400/5 px-3 py-2 text-xs text-emerald-300 space-y-1" >
151+ < div >
152+ < strong > Proposed.</ strong > safeTxHash:{ ' ' }
153+ < code className = "font-mono break-all" > { safePropose . proposed . safeTxHash } </ code >
154+ </ div >
155+ < div >
156+ Owners can co-sign and execute in{ ' ' }
157+ < a
158+ href = { safePropose . proposed . denUrl }
159+ target = "_blank"
160+ rel = "noreferrer"
161+ className = "underline decoration-emerald-400/60 hover:decoration-emerald-200"
162+ >
163+ Den
164+ </ a >
165+ .
166+ </ div >
167+ </ div >
168+ ) }
169+
170+ { safePropose . error && (
171+ < p className = "text-xs text-rose-400 font-mono" >
172+ Safe propose: { safePropose . error }
173+ </ p >
174+ ) }
175+
102176 { error && (
103177 < p className = "text-xs text-rose-400 font-mono" >
104178 { error . message . split ( '\n' ) [ 0 ] }
0 commit comments