Skip to content

Commit

Permalink
CP-9586: Fix not able to stake on mainnet and testnet (#2137)
Browse files Browse the repository at this point in the history
  • Loading branch information
atn4z7 authored Nov 27, 2024
1 parent fb41be0 commit edc3afd
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 55 deletions.
69 changes: 46 additions & 23 deletions packages/core-mobile/app/hooks/earn/useClaimFees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import {
calculatePChainFee
} from 'services/earn/calculateCrossChainFees'
import { useSelector } from 'react-redux'
import { selectIsDeveloperMode } from 'store/settings/advanced'
import { selectIsDeveloperMode } from 'store/settings/advanced/slice'
import { selectPFeeAdjustmentThreshold } from 'store/posthog/slice'
import NetworkService from 'services/network/NetworkService'
import { selectActiveAccount } from 'store/account'
import { selectActiveAccount } from 'store/account/slice'
import WalletService from 'services/wallet/WalletService'
import Logger from 'utils/Logger'
import { useCChainBaseFee } from 'hooks/useCChainBaseFee'
import { TokenUnit } from '@avalabs/core-utils-sdk'
import { selectActiveNetwork } from 'store/network'
import { selectActiveNetwork } from 'store/network/slice'
import { isDevnet } from 'utils/isDevnet'
import { weiToNano } from 'utils/units/converter'
import { CorePrimaryAccount } from '@avalabs/types'
Expand Down Expand Up @@ -46,6 +47,7 @@ export const useClaimFees = (
const isDevMode = useSelector(selectIsDeveloperMode)
const activeAccount = useSelector(selectActiveAccount)
const activeNetwork = useSelector(selectActiveNetwork)
const pFeeAdjustmentThreshold = useSelector(selectPFeeAdjustmentThreshold)
const [totalFees, setTotalFees] = useState<TokenUnit>()
const [exportFee, setExportFee] = useState<TokenUnit>()
const [defaultTxFee, setDefaultTxFee] = useState<TokenUnit>()
Expand Down Expand Up @@ -92,7 +94,8 @@ export const useClaimFees = (
activeAccount,
avaxXPNetwork,
provider: xpProvider,
feeState: defaultFeeState
feeState: defaultFeeState,
pFeeAdjustmentThreshold
})
setDefaultTxFee(txFee)
}
Expand All @@ -102,7 +105,8 @@ export const useClaimFees = (
avaxXPNetwork,
xpProvider,
totalClaimable,
defaultFeeState
defaultFeeState,
pFeeAdjustmentThreshold
])

useEffect(() => {
Expand Down Expand Up @@ -136,7 +140,8 @@ export const useClaimFees = (
activeAccount,
avaxXPNetwork,
provider: xpProvider,
feeState
feeState,
pFeeAdjustmentThreshold
})

Logger.info('importCFee', importCFee.toDisplay())
Expand Down Expand Up @@ -175,7 +180,8 @@ export const useClaimFees = (
avaxXPNetwork,
totalClaimable,
xpProvider,
feeState
feeState,
pFeeAdjustmentThreshold
])

return {
Expand All @@ -192,14 +198,16 @@ const getExportPFee = async ({
activeAccount,
avaxXPNetwork,
provider,
feeState
feeState,
pFeeAdjustmentThreshold
}: {
amountInNAvax: TokenUnit
activeAccount: CorePrimaryAccount
avaxXPNetwork: Network
provider: Avalanche.JsonRpcProvider
feeState?: pvm.FeeState
missingAvax?: bigint
pFeeAdjustmentThreshold: number
}): Promise<TokenUnit> => {
if (provider.isEtnaEnabled()) {
let unsignedTxP
Expand All @@ -220,26 +228,41 @@ const getExportPFee = async ({
getAssetId(avaxXPNetwork)
)

if (missingAmount) {
const amountAvailableToClaim = amountInNAvax.toSubUnit() - missingAmount
if (!missingAmount) {
// rethrow error if it's not an insufficient funds error
throw error
}

if (amountAvailableToClaim <= 0) {
// rethrow insufficient funds error when balance is not enough to cover fee
throw error
}
const amountAvailable = amountInNAvax.toSubUnit()
const ratio = Number(missingAmount) / Number(amountAvailable)

unsignedTxP = await WalletService.createExportPTx({
amountInNAvax: amountAvailableToClaim,
accountIndex: activeAccount.index,
avaxXPNetwork,
destinationAddress: activeAccount.addressPVM,
destinationChain: 'C',
feeState
if (ratio > pFeeAdjustmentThreshold) {
// rethrow insufficient funds error when missing fee is too much compared to total token amount
Logger.error('Failed to simulate export p due to excessive fees', {
missingAmount,
ratio
})
} else {
// rethrow error if it's not an insufficient funds error
throw error
}

const amountAvailableToClaim = amountAvailable - missingAmount

if (amountAvailableToClaim <= 0) {
Logger.error('Failed to simulate export p due to excessive fees', {
missingAmount
})
// rethrow insufficient funds error when balance is not enough to cover fee
throw error
}

unsignedTxP = await WalletService.createExportPTx({
amountInNAvax: amountAvailableToClaim,
accountIndex: activeAccount.index,
avaxXPNetwork,
destinationAddress: activeAccount.addressPVM,
destinationChain: 'C',
feeState
})
}

const tx = await Avalanche.parseAvalancheTx(
Expand Down
4 changes: 2 additions & 2 deletions packages/core-mobile/app/hooks/earn/useEstimateStakingFees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ const getStakingFeeFromDummyTx = async ({
feeState?: pvm.FeeState
}): Promise<TokenUnit> => {
if (provider.isEtnaEnabled() && feeState) {
const unsignedImportTx = await WalletService.createDummyImportPTx({
const unsignedImportTx = await WalletService.simulateImportPTx({
stakingAmount: stakingAmount.toSubUnit(),
accountIndex: activeAccount.index,
sourceChain: 'C',
Expand All @@ -188,7 +188,7 @@ const getStakingFeeFromDummyTx = async ({
activeAccount.addressPVM
)
const unsignedAddPermissionlessDelegatorTx =
await WalletService.createDummyAddPermissionlessDelegatorTx({
await WalletService.simulateAddPermissionlessDelegatorTx({
amountInNAvax: stakingAmount.toSubUnit(),
accountIndex: activeAccount.index,
destinationChain: 'C',
Expand Down
13 changes: 8 additions & 5 deletions packages/core-mobile/app/hooks/earn/useIssueDelegation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import {
} from '@tanstack/react-query'
import { useSelector } from 'react-redux'
import EarnService from 'services/earn/EarnService'
import { selectIsDeveloperMode } from 'store/settings/advanced'
import { selectActiveAccount } from 'store/account'
import { selectSelectedCurrency } from 'store/settings/currency'
import { selectIsDeveloperMode } from 'store/settings/advanced/slice'
import { selectActiveAccount } from 'store/account/slice'
import { selectSelectedCurrency } from 'store/settings/currency/slice'
import { selectPFeeAdjustmentThreshold } from 'store/posthog/slice'
import { calculateAmountForCrossChainTransferBigint } from 'hooks/earn/useGetAmountForCrossChainTransfer'
import Logger from 'utils/Logger'
import { FundsStuckError } from 'hooks/earn/errors'
Expand All @@ -19,7 +20,7 @@ import { coingeckoInMemoryCache } from 'utils/coingeckoInMemoryCache'
import { isTokenWithBalancePVM } from '@avalabs/avalanche-module'
import { TokenUnit } from '@avalabs/core-utils-sdk'
import { isDevnet } from 'utils/isDevnet'
import { selectActiveNetwork } from 'store/network'
import { selectActiveNetwork } from 'store/network/slice'
import { nanoToWei } from 'utils/units/converter'
import { useCChainBalance } from './useCChainBalance'
import { useGetFeeState } from './useGetFeeState'
Expand Down Expand Up @@ -56,6 +57,7 @@ export const useIssueDelegation = (
isDeveloperMode,
isDevnet(activeNetwork)
)
const pFeeAdjustmentThreshold = useSelector(selectPFeeAdjustmentThreshold)

const pAddress = activeAccount?.addressPVM ?? ''
const cAddress = activeAccount?.addressC ?? ''
Expand Down Expand Up @@ -147,7 +149,8 @@ export const useIssueDelegation = (
stakeAmountNanoAvax: data.stakingAmountNanoAvax,
startDate: data.startDate,
isDevnet: isDevnet(activeNetwork),
feeState: getFeeState(data.gasPrice)
feeState: getFeeState(data.gasPrice),
pFeeAdjustmentThreshold
})
},
onSuccess: txId => {
Expand Down
6 changes: 4 additions & 2 deletions packages/core-mobile/app/screens/earn/components/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ export const Balance = (): JSX.Element | null => {
<BalanceItem
balanceType={StakeTypeEnum.Claimable}
iconColor={getStakePrimaryColor(StakeTypeEnum.Claimable, theme)}
balance={claimableInAvax?.toDisplay() ?? UNKNOWN_AMOUNT}
balance={
claimableInAvax?.toDisplay({ fixedDp: 4 }) ?? UNKNOWN_AMOUNT
}
poppableItem={
[
RecoveryEvents.ImportPStart,
Expand All @@ -232,7 +234,7 @@ export const Balance = (): JSX.Element | null => {
</Row>
</View>
<View>
{claimableInAvax?.gt(0)
{claimableInAvax?.gt(0.05)
? renderStakeAndClaimButton()
: renderStakeButton()}
</View>
Expand Down
6 changes: 4 additions & 2 deletions packages/core-mobile/app/services/earn/EarnService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ class EarnService {
endDate,
isDevMode,
isDevnet,
feeState
feeState,
pFeeAdjustmentThreshold
}: AddDelegatorTransactionProps): Promise<string> {
const startDateUnix = getUnixTime(startDate)
const endDateUnix = getUnixTime(endDate)
Expand All @@ -277,7 +278,8 @@ class EarnService {
endDate: endDateUnix,
stakeAmountInNAvax: stakeAmountNanoAvax,
isDevMode,
feeState
feeState,
pFeeAdjustmentThreshold
} as AddDelegatorProps)

const signedTxJson = await WalletService.sign({
Expand Down
2 changes: 1 addition & 1 deletion packages/core-mobile/app/services/earn/exportC.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ describe('earn/exportC', () => {
isDevnet: false
})
expect(WalletService.createExportCTx).toHaveBeenCalledWith({
amountInNAvax: 1001000000n,
amountInNAvax: 1000000000n,
baseFeeInNAvax: 0n,
accountIndex: undefined,
avaxXPNetwork: NetworkService.getAvalancheNetworkP(false, false),
Expand Down
9 changes: 3 additions & 6 deletions packages/core-mobile/app/services/earn/exportC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ChainId } from '@avalabs/core-chains-sdk'
import { assertNotUndefined } from 'utils/assertions'
import { retry } from 'utils/js/retry'
import Logger from 'utils/Logger'
import { calculatePChainFee } from 'services/earn/calculateCrossChainFees'
import WalletService from 'services/wallet/WalletService'
import { Account } from 'store/account/types'
import { AvalancheTransactionRequest } from 'services/wallet/types'
Expand All @@ -15,7 +14,7 @@ import { maxTransactionStatusCheckRetries } from './utils'

export type ExportCParams = {
cChainBalanceWei: bigint
requiredAmountWei: bigint
requiredAmountWei: bigint // this amount should already include the fee to export
activeAccount: Account
isDevMode: boolean
isDevnet: boolean
Expand Down Expand Up @@ -53,15 +52,13 @@ export async function exportC({

const cChainBalanceAvax = AvaxC.fromWei(cChainBalanceWei)
const requiredAmountAvax = AvaxC.fromWei(requiredAmountWei)
const pChainFeeAvax = await calculatePChainFee(avaxXPNetwork)
const amountAvax = requiredAmountAvax.add(pChainFeeAvax)

if (cChainBalanceAvax.lt(amountAvax)) {
if (cChainBalanceAvax.lt(requiredAmountAvax)) {
throw Error('Not enough balance on C chain')
}

const unsignedTxWithFee = await WalletService.createExportCTx({
amountInNAvax: weiToNano(amountAvax.toSubUnit()),
amountInNAvax: weiToNano(requiredAmountAvax.toSubUnit()),
baseFeeInNAvax: weiToNano(instantBaseFeeAvax.toSubUnit()),
accountIndex: activeAccount.index,
avaxXPNetwork,
Expand Down
1 change: 1 addition & 0 deletions packages/core-mobile/app/services/earn/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type AddDelegatorTransactionProps = {
isDevMode: boolean
isDevnet: boolean
feeState?: pvm.FeeState
pFeeAdjustmentThreshold: number
}

export type UnixTimeMs = number
Expand Down
3 changes: 2 additions & 1 deletion packages/core-mobile/app/services/posthog/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export enum FeatureGates {
}

export enum FeatureVars {
SENTRY_SAMPLE_RATE = 'sentry-sample-rate'
SENTRY_SAMPLE_RATE = 'sentry-sample-rate',
P_FEE_ADJUSTMENT_THRESHOLD = 'p-fee-adjustment-threshold'
}

// posthog response can be an empty object when all features are disabled
Expand Down
Loading

0 comments on commit edc3afd

Please sign in to comment.