Skip to content

Commit f89c92d

Browse files
committed
Fix token delegation, improve transaction states
1 parent e11f790 commit f89c92d

File tree

1 file changed

+84
-57
lines changed

1 file changed

+84
-57
lines changed

apps/web/src/screens/Manage.tsx

Lines changed: 84 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Heading,
66
PlusSVG,
77
Spinner,
8+
Toast,
89
Typography,
910
} from '@ensdomains/thorin'
1011
import { useEffect, useState } from 'react'
@@ -40,6 +41,9 @@ export function Manage() {
4041
const delegationInfo = useDelegationInfo(address)
4142
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false)
4243
const [isConfirmationModalOpen, setIsConfirmationModalOpen] = useState(false)
44+
const [delegationType, setDelegationType] = useState<'native' | 'multi'>(
45+
'multi'
46+
)
4347

4448
const [delegates, setDelegates] = useState<DelegateSelection>(new Map())
4549
const delegatesArr = Array.from(delegates)
@@ -123,7 +127,8 @@ export function Manage() {
123127
useEffect(() => {
124128
// Refetch the delegateInfo 1s after a transaction (to let the indexer catch up)
125129
if (receipt.status) {
126-
setTimeout(() => delegationInfo.refetch(), 1000)
130+
setIsConfirmationModalOpen(false)
131+
delegationInfo.refetch()
127132
}
128133
// eslint-disable-next-line react-hooks/exhaustive-deps
129134
}, [receipt.status])
@@ -133,11 +138,24 @@ export function Manage() {
133138
navigate('/strategy')
134139
}
135140

141+
function handleNativeDelegate() {
142+
if (!address) return
143+
144+
// We will only be here if allocatedDelegates.length === 1, so it's safe to use the first
145+
write.writeContract({
146+
...ensTokenContract,
147+
functionName: 'delegate',
148+
args: [allocatedDelegates[0][0]],
149+
})
150+
}
151+
136152
function handleMultiDelegate() {
137153
if (!address) return
138154

139155
if (allocatedDelegates.map((del) => del[0]).includes(address)) {
140-
return alert('You cannot delegate to yourself')
156+
return alert(
157+
'You cannot delegate to yourself via the multi-delegate contract.'
158+
)
141159
}
142160

143161
const positiveChangingDelegates = changingDelegates
@@ -283,19 +301,15 @@ export function Manage() {
283301

284302
console.log({ sources, targets, amounts })
285303

286-
write
287-
.writeContractAsync({
288-
...erc20MultiDelegateContract,
289-
functionName: 'delegateMulti',
290-
args: [
291-
sources.map((address) => BigInt(address)), // sources[]
292-
targets.map((address) => BigInt(address)), // targets[]
293-
amounts, // amounts[]
294-
],
295-
})
296-
.catch((e) => {
297-
console.error(e)
298-
})
304+
write.writeContract({
305+
...erc20MultiDelegateContract,
306+
functionName: 'delegateMulti',
307+
args: [
308+
sources.map((address) => BigInt(address)), // sources[]
309+
targets.map((address) => BigInt(address)), // targets[]
310+
amounts, // amounts[]
311+
],
312+
})
299313
}
300314

301315
return (
@@ -364,50 +378,53 @@ export function Manage() {
364378
prefix={<PlusSVG />}
365379
onClick={() => setIsSearchModalOpen(true)}
366380
>
367-
Add delegate
381+
{multiDelegates?.length === 0 && allocatedDelegates.length === 0
382+
? 'Add or change delegate'
383+
: 'Add delegate'}
368384
</Button>
369-
370-
{/* <Button
371-
prefix={<PlusSVG />}
372-
onClick={() => {
373-
write.writeContract({
374-
...ensTokenContract,
375-
functionName: 'delegate',
376-
args: [address!],
377-
})
378-
}}
379-
>
380-
Delegate all tokens natively
381-
</Button> */}
382385
</ButtonWrapper>
383386

384-
{receipt.isSuccess && (
385-
<Helper type="success" className="mx-auto">
386-
Transaction success!
387-
</Helper>
388-
)}
387+
{/* receipt.isSuccess */}
388+
<Toast
389+
open={receipt.isSuccess}
390+
title="Transaction success!"
391+
description="Your transaction has been confirmed."
392+
variant="desktop"
393+
onClose={() => write.reset()}
394+
msToShow={7000}
395+
>
396+
<Button
397+
as="a"
398+
target="_blank"
399+
href={`https://etherscan.io/tx/${write.data}`}
400+
colorStyle="bluePrimary"
401+
>
402+
View on Etherscan
403+
</Button>
404+
</Toast>
389405

390406
{receipt.isLoading && (
391407
<Spinner size="medium" color="blue" className="mx-auto" />
392408
)}
393409

394-
{receipt.isError && (
395-
<Helper type="error">
396-
<div>
397-
Transaction failed. It will likely work if you try again a few
398-
times. Tenderly sends a different gas estimate to the wallet each
399-
time for some reason.{' '}
400-
<a
401-
href="https://dashboard.tenderly.co/explorer/vnet/78d3d569-cb63-45a9-8b8c-9d152d90c3ed/transactions"
402-
target="_blank"
403-
className="text-ens-red-primary font-bold underline"
404-
>
405-
See more here
406-
</a>
407-
.
408-
</div>
409-
</Helper>
410-
)}
410+
{/* receipt.isError */}
411+
<Toast
412+
open={receipt.isError}
413+
title="Transaction failed!"
414+
description="Your transaction has failed."
415+
variant="desktop"
416+
onClose={() => write.reset()}
417+
msToShow={7000}
418+
>
419+
<Button
420+
as="a"
421+
target="_blank"
422+
href={`https://etherscan.io/tx/${write.data}`}
423+
colorStyle="redPrimary"
424+
>
425+
View on Etherscan
426+
</Button>
427+
</Toast>
411428

412429
<ButtonWrapper>
413430
{(() => {
@@ -472,6 +489,8 @@ export function Manage() {
472489

473490
// If there's exactly one delegate AND the allocated amount is moast of the balance, present the option of native delegation
474491
if (
492+
// We can only show this if there are no existing multi-delegates, otherwise we'd need a multi-step process to reclaim tokens first
493+
(multiDelegates ?? []).length === 0 &&
475494
allocatedDelegates.length === 1 &&
476495
allocatedDelegates[0][1].newBalance > almostFullBalance
477496
) {
@@ -481,7 +500,7 @@ export function Manage() {
481500
// Radio options to select native or multi-delegate
482501
return (
483502
<div className="flex w-[28rem] max-w-full flex-col gap-2">
484-
<label htmlFor="native" className={optionsClassName}>
503+
<label htmlFor="multi" className={optionsClassName}>
485504
<Typography asProp="p">
486505
Delegate a portion, swapping your $ENS for NFTs that
487506
represent each delegate. You can undelegate anytime to swap
@@ -492,12 +511,13 @@ export function Manage() {
492511
type="radio"
493512
className="appearance-auto"
494513
name="delegation-type"
495-
id="native"
514+
id="multi"
496515
defaultChecked
516+
onChange={() => setDelegationType('multi')}
497517
/>
498518
</label>
499519

500-
<label htmlFor="multi" className={optionsClassName}>
520+
<label htmlFor="native" className={optionsClassName}>
501521
<Typography asProp="p">
502522
Delegate all your $ENS to one person, including any new $ENS
503523
you receive, for less gas.
@@ -507,7 +527,8 @@ export function Manage() {
507527
type="radio"
508528
className="appearance-auto"
509529
name="delegation-type"
510-
id="multi"
530+
id="native"
531+
onChange={() => setDelegationType('native')}
511532
/>
512533
</label>
513534
</div>
@@ -537,8 +558,14 @@ export function Manage() {
537558
trailing={
538559
<Button
539560
colorStyle="bluePrimary"
540-
onClick={handleMultiDelegate}
541-
loading={receipt.isLoading}
561+
onClick={() => {
562+
if (delegationType === 'native') {
563+
handleNativeDelegate()
564+
} else {
565+
handleMultiDelegate()
566+
}
567+
}}
568+
loading={receipt.isLoading || write.isPending}
542569
disabled={toBeAllocated < 0n || changingDelegates.length === 0}
543570
>
544571
Open Wallet

0 commit comments

Comments
 (0)