Skip to content

Commit b0e6cd0

Browse files
authored
Bugfix/modal insufficient funds (#1013)
* fix: wire up insufficient SOL balance warning in governance modals Compare estimated SOL fee from prepare() against wallet SOL balance so users see a warning before submitting instead of a server error. * docs: add governance modal fixes design * fix: simplify ClaimingRewardsModal, remove dead progress tracking * fix: hide Change/Renew Delegation actions on decayed positions * fix modal and fully decayed options * fix: remove accidental compiled JS artifacts
1 parent 259b4ed commit b0e6cd0

File tree

3 files changed

+46
-42
lines changed

3 files changed

+46
-42
lines changed

src/features/governance/ClaimingRewardsModal.tsx

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,12 @@ import { Edge } from 'react-native-safe-area-context'
99
import AccountIcon from '@components/AccountIcon'
1010
import { useTranslation } from 'react-i18next'
1111
import { useAccountStorage } from '@storage/AccountStorageProvider'
12-
import { Status } from '@helium/spl-utils'
13-
import ProgressBar from '@components/ProgressBar'
1412
import { Platform } from 'react-native'
1513

16-
export const ClaimingRewardsModal = ({ status }: { status?: Status }) => {
14+
export const ClaimingRewardsModal = () => {
1715
const { t } = useTranslation()
1816
const { currentAccount } = useAccountStorage()
1917
const edges = useMemo(() => ['bottom'] as Edge[], [])
20-
const { helpText, percent } = useMemo(() => {
21-
if (!status) return { helpText: 'Preparing Transactions...', percent: 0 }
22-
const { totalTxs, totalProgress, currentBatchSize } = status
23-
24-
const remainingTxs = totalTxs - totalProgress
25-
const actualBatchSize =
26-
totalTxs < currentBatchSize ? totalTxs : currentBatchSize
27-
28-
return {
29-
helpText: `Sending batch of ${actualBatchSize} transactions.\n${remainingTxs} total transaction${
30-
remainingTxs > 1 ? 's' : ''
31-
} remaining.`,
32-
percent: (totalProgress * 100) / totalTxs,
33-
}
34-
}, [status])
3518

3619
return (
3720
<Portal hostName="GovernancePortalHost">
@@ -95,20 +78,6 @@ export const ClaimingRewardsModal = ({ status }: { status?: Status }) => {
9578
{t('gov.claiming.multiple')}
9679
</Text>
9780
</Box>
98-
99-
<Box alignItems="center" marginTop="m">
100-
<Box flexDirection="row">
101-
<ProgressBar progress={percent} />
102-
</Box>
103-
<Text
104-
variant="body2"
105-
color="secondaryText"
106-
marginTop="s"
107-
textAlign="center"
108-
>
109-
{helpText}
110-
</Text>
111-
</Box>
11281
</Box>
11382
</SafeAreaBox>
11483
</ReAnimatedBlurBox>

src/features/governance/PositionCard.tsx

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-shadow */
2+
import type { TokenAmountOutput } from '@helium/blockchain-api'
23
import { ReAnimatedBox } from '@components/AnimatedBox'
34
import BlurActionSheet from '@components/BlurActionSheet'
45
import Box from '@components/Box'
@@ -9,7 +10,11 @@ import Text from '@components/Text'
910
import TokenIcon from '@components/TokenIcon'
1011
import TouchableOpacityBox from '@components/TouchableOpacityBox'
1112
import { TASK_QUEUE, useDelegationClaimBot } from '@helium/automation-hooks'
12-
import { useMint, useSolanaUnixNow } from '@helium/helium-react-hooks'
13+
import {
14+
useMint,
15+
useOwnedAmount,
16+
useSolanaUnixNow,
17+
} from '@helium/helium-react-hooks'
1318
import { EPOCH_LENGTH, delegatedPositionKey } from '@helium/helium-sub-daos-sdk'
1419
import { delegationClaimBotKey } from '@helium/hpl-crons-sdk'
1520
import { organizationKey } from '@helium/organization-sdk'
@@ -22,9 +27,11 @@ import {
2227
useRegistrar,
2328
} from '@helium/voter-stake-registry-hooks'
2429
import useAlert from '@hooks/useAlert'
30+
import { useCurrentWallet } from '@hooks/useCurrentWallet'
2531
import { useMetaplexMetadata } from '@hooks/useMetaplexMetadata'
2632
import { useNavigation } from '@react-navigation/native'
2733
import { BoxProps } from '@shopify/restyle'
34+
import { NATIVE_MINT } from '@solana/spl-token'
2835
import { PublicKey } from '@solana/web3.js'
2936
import { useGovernance } from '@storage/GovernanceProvider'
3037
import { Theme } from '@theme/theme'
@@ -69,7 +76,9 @@ export const PositionCard = ({
6976
...boxProps
7077
}: IPositionCardProps) => {
7178
const { t } = useTranslation()
79+
const wallet = useCurrentWallet()
7280
const unixNow = useSolanaUnixNow(60 * 5 * 1000) || 0
81+
const { amount: solBalance } = useOwnedAmount(wallet, NATIVE_MINT)
7382
const { showOKAlert } = useAlert()
7483
const extendMutation = useExtendPositionMutation()
7584
const splitMutation = useSplitPositionMutation()
@@ -232,6 +241,13 @@ export const PositionCard = ({
232241
const maxActionableAmount = mintAcc
233242
? toNumber(position.amountDepositedNative, mintAcc)
234243
: 0
244+
const isInsufficientSol = useCallback(
245+
(fee: TokenAmountOutput | null) => {
246+
if (!fee || typeof solBalance === 'undefined') return false
247+
return BigInt(fee.amount) > solBalance
248+
},
249+
[solBalance],
250+
)
235251
const canDelegate = votingMint.mint.equals(HNT_MINT)
236252

237253
const { info: registrar = null } = useRegistrar(position.registrar)
@@ -542,7 +558,7 @@ export const PositionCard = ({
542558
selected={false}
543559
hasPressedState={false}
544560
/>
545-
{canDelegate && (
561+
{canDelegate && !isDecayed && (
546562
<>
547563
{(showDelegationExpiringWarning ||
548564
showDelegationExpiredWarning) && (
@@ -1019,7 +1035,9 @@ export const PositionCard = ({
10191035
</BlurActionSheet>
10201036
{isExtendModalOpen && (
10211037
<LockTokensModal
1022-
insufficientBalance={false}
1038+
insufficientBalance={isInsufficientSol(
1039+
extendMutation.estimatedSolFee,
1040+
)}
10231041
mint={mint}
10241042
mode="extend"
10251043
minLockupTimeInDays={
@@ -1052,7 +1070,9 @@ export const PositionCard = ({
10521070
)}
10531071
{isSplitModalOpen && (
10541072
<LockTokensModal
1055-
insufficientBalance={false}
1073+
insufficientBalance={isInsufficientSol(
1074+
splitMutation.estimatedSolFee,
1075+
)}
10561076
mint={mint}
10571077
mode="split"
10581078
minLockupTimeInDays={
@@ -1099,7 +1119,9 @@ export const PositionCard = ({
10991119
onClose={() => setIsDelegateModalOpen(false)}
11001120
onSubmit={handleDelegateTokens}
11011121
estimatedSolFee={delegateMutation.estimatedSolFee?.uiAmountString}
1102-
insufficientBalance={false}
1122+
insufficientBalance={isInsufficientSol(
1123+
delegateMutation.estimatedSolFee,
1124+
)}
11031125
subDao={subDao}
11041126
setSubDao={setSubDao}
11051127
/>

src/features/governance/PositionsScreen.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import ButtonPressable from '@components/ButtonPressable'
44
import Dot from '@components/Dot'
55
import ListItem from '@components/ListItem'
66
import Text from '@components/Text'
7+
import type { TokenAmountOutput } from '@helium/blockchain-api'
78
import { useOwnedAmount, useSolanaUnixNow } from '@helium/helium-react-hooks'
89
import { HNT_MINT, humanReadable, toBN, toNumber } from '@helium/spl-utils'
10+
import { NATIVE_MINT } from '@solana/spl-token'
911
import {
1012
SubDaoWithMeta,
1113
calcLockupMultiplier,
@@ -47,6 +49,7 @@ export const PositionsScreen = () => {
4749
} = useGovernance()
4850
const { symbol } = useMetaplexMetadata(mint)
4951
const { amount: ownedAmount, decimals } = useOwnedAmount(wallet, mint)
52+
const { amount: solBalance } = useOwnedAmount(wallet, NATIVE_MINT)
5053
const createPositionMutation = useCreatePositionMutation()
5154
const claimRewardsMutation = useClaimRewardsMutation()
5255
const delegateAllMutation = useDelegatePositionMutation()
@@ -72,6 +75,14 @@ export const PositionsScreen = () => {
7275
if (transactionError) return transactionError
7376
}, [transactionError])
7477

78+
const isInsufficientSol = useCallback(
79+
(fee: TokenAmountOutput | null) => {
80+
if (!fee || typeof solBalance === 'undefined') return false
81+
return BigInt(fee.amount) > solBalance
82+
},
83+
[solBalance],
84+
)
85+
7586
const maxLockupAmount =
7687
ownedAmount && decimals
7788
? toNumber(new BN(ownedAmount.toString()), decimals)
@@ -420,12 +431,12 @@ export const PositionsScreen = () => {
420431
</Box>
421432
)}
422433
</Box>
423-
{claimRewardsMutation.isPending && (
424-
<ClaimingRewardsModal status={undefined} />
425-
)}
434+
{claimRewardsMutation.isPending && <ClaimingRewardsModal />}
426435
{isLockModalOpen && (
427436
<LockTokensModal
428-
insufficientBalance={false}
437+
insufficientBalance={isInsufficientSol(
438+
createPositionMutation.estimatedSolFee,
439+
)}
429440
mint={mint}
430441
maxLockupAmount={maxLockupAmount}
431442
calcMultiplierFn={handleCalcLockupMultiplier}
@@ -448,7 +459,9 @@ export const PositionsScreen = () => {
448459
estimatedSolFee={
449460
delegateAllMutation.estimatedSolFee?.uiAmountString
450461
}
451-
insufficientBalance={false}
462+
insufficientBalance={isInsufficientSol(
463+
delegateAllMutation.estimatedSolFee,
464+
)}
452465
subDao={delegateAllSubDao}
453466
setSubDao={setDelegateAllSubDao}
454467
/>

0 commit comments

Comments
 (0)