Skip to content

Commit

Permalink
CP-8503: p-dynamic fee support (#2072)
Browse files Browse the repository at this point in the history
  • Loading branch information
ruijialin-avalabs authored Nov 22, 2024
1 parent 271ce9a commit fcceca8
Show file tree
Hide file tree
Showing 91 changed files with 1,834 additions and 668 deletions.
24 changes: 12 additions & 12 deletions packages/core-mobile/app/components/EditFees.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type EditFeesProps = {
onClose?: () => void
lowMaxFeePerGas: bigint
isGasLimitEditable?: boolean
isBtcNetwork: boolean
isBaseUnitRate: boolean
noGasLimitError?: string
} & Eip1559Fees

Expand Down Expand Up @@ -62,7 +62,7 @@ const EditFees = ({
onSave,
onClose,
isGasLimitEditable,
isBtcNetwork,
isBaseUnitRate,
noGasLimitError
}: EditFeesProps): JSX.Element => {
const _gasLimitError = noGasLimitError ?? 'Please enter a valid gas limit'
Expand Down Expand Up @@ -91,7 +91,7 @@ const EditFees = ({
* EVM - gWei
*/
const [newMaxFeePerGas, setNewMaxFeePerGas] = useState<string>(
bigIntToFeeDenomination(initMaxFeePerGas, isBtcNetwork)
bigIntToFeeDenomination(initMaxFeePerGas, isBaseUnitRate)
)
/**
* Denominated depending of network:
Expand All @@ -101,7 +101,7 @@ const EditFees = ({
*/
const [newMaxPriorityFeePerGas, setNewMaxPriorityFeePerGas] =
useState<string>(
bigIntToFeeDenomination(initMaxPriorityFeePerGas, isBtcNetwork)
bigIntToFeeDenomination(initMaxPriorityFeePerGas, isBaseUnitRate)
)
const tokenPrice = useNativeTokenPriceForNetwork(network).nativeTokenPrice
const [feeError, setFeeError] = useState('')
Expand Down Expand Up @@ -133,10 +133,10 @@ const EditFees = ({
try {
const fees = calculateGasAndFees({
tokenPrice,
maxFeePerGas: feeDenominationToBigint(newMaxFeePerGas, isBtcNetwork),
maxFeePerGas: feeDenominationToBigint(newMaxFeePerGas, isBaseUnitRate),
maxPriorityFeePerGas: feeDenominationToBigint(
newMaxPriorityFeePerGas,
isBtcNetwork
isBaseUnitRate
),
gasLimit: isNaN(parseInt(newGasLimit)) ? 0 : parseInt(newGasLimit),
networkToken: network.networkToken
Expand All @@ -160,7 +160,7 @@ const EditFees = ({
typeCreator,
lowMaxFeePerGas,
_gasLimitError,
isBtcNetwork,
isBaseUnitRate,
network.networkToken
])

Expand All @@ -175,7 +175,7 @@ const EditFees = ({
}
}

const saveDisabled = !!feeError || (newFees.gasLimit === 0 && !isBtcNetwork)
const saveDisabled = !!feeError || (newFees.gasLimit === 0 && !isBaseUnitRate)

const sanitized = (text: string): string => text.replace(/[^0-9]/g, '')

Expand All @@ -189,15 +189,15 @@ const EditFees = ({
</Text>
<Space y={24} />
<InputText
label={isBtcNetwork ? 'Network Fee' : 'Max Base Fee'}
label={isBaseUnitRate ? 'Network Fee' : 'Max Base Fee'}
mode={'amount'}
text={newMaxFeePerGas}
keyboardType="numeric"
popOverInfoText={isBtcNetwork ? undefined : maxBaseFeeInfoMessage}
popOverInfoText={isBaseUnitRate ? undefined : maxBaseFeeInfoMessage}
onChangeText={text => setNewMaxFeePerGas(sanitized(text))}
errorText={feeError}
/>
{!isBtcNetwork && (
{!isBaseUnitRate && (
<>
<InputText
label={'Max Priority Fee'}
Expand Down Expand Up @@ -229,7 +229,7 @@ const EditFees = ({
<DividerLine />
</View>
<Row style={{ marginHorizontal: 12, alignItems: 'baseline' }}>
{isBtcNetwork ? (
{isBaseUnitRate ? (
<TotalNetworkFeeText />
) : (
<Tooltip
Expand Down
140 changes: 84 additions & 56 deletions packages/core-mobile/app/components/NetworkFeeSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,17 @@ const NetworkFeeSelector = ({
gasLimit,
onFeesChange,
isGasLimitEditable = true,
noGasLimitError
noGasLimitError,
supportsAvalancheDynamicFee = false,
showOnlyFeeSelection = false
}: {
chainId?: number
gasLimit: number
onFeesChange?(fees: Eip1559Fees, feePreset: FeePreset): void
isGasLimitEditable?: boolean
noGasLimitError?: string
supportsAvalancheDynamicFee?: boolean
showOnlyFeeSelection?: boolean
}): JSX.Element => {
const {
appHook: { currencyFormatter }
Expand All @@ -84,6 +88,7 @@ const NetworkFeeSelector = ({
)

const isBtcNetwork = network ? isBitcoinNetwork(network) : false
const isBaseUnitRate = isBtcNetwork || supportsAvalancheDynamicFee
const isPVM = isPvmNetwork(network)
const isAVM = isAvmNetwork(network)
const [selectedPreset, setSelectedPreset] = useState(FeePreset.Normal)
Expand All @@ -105,11 +110,21 @@ const NetworkFeeSelector = ({
maxFeePerGas: fee.low.maxFeePerGas,
maxPriorityFeePerGas: fee.low.maxPriorityFeePerGas ?? 0n,
tokenPrice: nativeTokenPrice,
gasLimit: isPVM || isAVM ? GAS_LIMIT_FOR_XP_CHAIN : gasLimit,
gasLimit:
(isPVM && !supportsAvalancheDynamicFee) || isAVM
? GAS_LIMIT_FOR_XP_CHAIN
: gasLimit,
networkToken
})
},
[nativeTokenPrice, isPVM, isAVM, gasLimit, networkToken]
[
nativeTokenPrice,
isPVM,
supportsAvalancheDynamicFee,
isAVM,
gasLimit,
networkToken
]
)

// customFees init value.
Expand Down Expand Up @@ -166,19 +181,19 @@ const NetworkFeeSelector = ({
return {
[FeePreset.Normal]: bigIntToFeeDenomination(
networkFee.low.maxFeePerGas,
isBtcNetwork
isBaseUnitRate
),
[FeePreset.Fast]: bigIntToFeeDenomination(
networkFee.medium.maxFeePerGas,
isBtcNetwork
isBaseUnitRate
),
[FeePreset.Instant]: bigIntToFeeDenomination(
networkFee.high.maxFeePerGas,
isBtcNetwork
isBaseUnitRate
),
[FeePreset.Custom]: bigIntToFeeDenomination(customFee, isBtcNetwork)
[FeePreset.Custom]: bigIntToFeeDenomination(customFee, isBaseUnitRate)
}
}, [customFees?.maxFeePerGas, isBtcNetwork, networkFee])
}, [customFees?.maxFeePerGas, networkFee, isBaseUnitRate])

const goToEditGasLimit = (n?: Network): void => {
if (networkFee === undefined || n === undefined) return
Expand All @@ -193,46 +208,52 @@ const NetworkFeeSelector = ({
0n,
gasLimit,
isGasLimitEditable,
isBtcNetwork,
isBaseUnitRate,
noGasLimitError
})
}

return (
<>
<Row style={{ justifyContent: 'space-between', alignItems: 'center' }}>
{isBtcNetwork || isPVM || isAVM ? (
<View sx={{ paddingVertical: 12 }}>
<Text variant="body2" sx={{ color: '$neutral50' }}>
Network Fee
</Text>
</View>
) : (
<Tooltip
content={
'Core estimates the maximum gas (maxFeePerGas) a transaction could consume based on network conditions. This transaction will likely consume less gas than estimated.'
}
position={'right'}
style={{ width: 200 }}>
<Text variant="buttonMedium">Maximum Network Fee</Text>
</Tooltip>
)}
{!isPVM && !isAVM && (
<TouchableOpacity
sx={{ marginTop: 8 }}
onPress={() => goToEditGasLimit(network)}>
<Settings />
</TouchableOpacity>
)}
</Row>
{!showOnlyFeeSelection && (
<>
<Row
style={{ justifyContent: 'space-between', alignItems: 'center' }}>
{isBtcNetwork || isPVM || isAVM ? (
<View sx={{ paddingVertical: 12 }}>
<Text variant="body2" sx={{ color: '$neutral50' }}>
Network Fee
</Text>
</View>
) : (
<Tooltip
content={
'Core estimates the maximum gas (maxFeePerGas) a transaction could consume based on network conditions. This transaction will likely consume less gas than estimated.'
}
position={'right'}
style={{ width: 200 }}>
<Text variant="buttonMedium">Maximum Network Fee</Text>
</Tooltip>
)}
{(!isPVM && supportsAvalancheDynamicFee) ||
(!isAVM && (
<TouchableOpacity
sx={{ marginTop: 8 }}
onPress={() => goToEditGasLimit(network)}>
<Settings />
</TouchableOpacity>
))}
</Row>
</>
)}
<Space y={4} />

<View
sx={{
backgroundColor: '$neutral900',
padding: 16,
borderRadius: 8,
marginBottom: 16
marginBottom: showOnlyFeeSelection ? 0 : 16
}}>
{!networkFee?.isFixedFee && (
<>
Expand Down Expand Up @@ -275,29 +296,36 @@ const NetworkFeeSelector = ({
testID="custom_base_fee"
/>
</Row>
<Space y={20} />
{!showOnlyFeeSelection && <Space y={20} />}
</>
)}
{!showOnlyFeeSelection && (
<>
<Row
style={{ justifyContent: 'space-between', alignItems: 'center' }}>
<Text variant="body2" sx={{ color: '$neutral400' }}>
Fee Amount
</Text>
<View sx={{ flexDirection: 'row' }}>
<Text testID="token_gas_fee" sx={{ color: '$neutral50' }}>
{`${calculatedMaxTotalFeeDisplayed} `}
</Text>
<Text variant="body1" sx={{ color: '$neutral400' }}>
{network?.networkToken?.symbol}
</Text>
</View>
</Row>
<Row style={{ justifyContent: 'flex-end' }}>
<Text
variant="caption"
sx={{ color: '$neutral400', lineHeight: 15 }}>
{calculatedFees?.maxTotalFeeInCurrency
? currencyFormatter(calculatedFees.maxTotalFeeInCurrency)
: UNKNOWN_AMOUNT + ' ' + selectedCurrency}
</Text>
</Row>
</>
)}
<Row style={{ justifyContent: 'space-between', alignItems: 'center' }}>
<Text variant="body2" sx={{ color: '$neutral400' }}>
Fee Amount
</Text>
<View sx={{ flexDirection: 'row' }}>
<Text testID="token_gas_fee" sx={{ color: '$neutral50' }}>
{`${calculatedMaxTotalFeeDisplayed} `}
</Text>
<Text variant="body1" sx={{ color: '$neutral400' }}>
{network?.networkToken?.symbol}
</Text>
</View>
</Row>
<Row style={{ justifyContent: 'flex-end' }}>
<Text variant="caption" sx={{ color: '$neutral400', lineHeight: 15 }}>
{calculatedFees?.maxTotalFeeInCurrency
? currencyFormatter(calculatedFees.maxTotalFeeInCurrency)
: UNKNOWN_AMOUNT + ' ' + selectedCurrency}
</Text>
</Row>
</View>
</>
)
Expand Down
23 changes: 20 additions & 3 deletions packages/core-mobile/app/hooks/earn/useAdvancedSearchNodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { selectIsDeveloperMode } from 'store/settings/advanced'
import { AdvancedSortFilter, NodeValidators } from 'types/earn'
import Logger from 'utils/Logger'
import { TokenUnit } from '@avalabs/core-utils-sdk'
import { isDevnet } from 'utils/isDevnet'
import { selectActiveNetwork } from 'store/network'
import { usePeers } from './usePeers'

export type useAdvancedSearchNodesProps = {
Expand Down Expand Up @@ -40,16 +42,30 @@ export const useAdvancedSearchNodes = ({
validators,
sortFilter,
searchText
}: useAdvancedSearchNodesProps) => {
}: useAdvancedSearchNodesProps):
| {
validators: NodeValidators | undefined
error: undefined
}
| {
validators: never[]
error: Error
} => {
const { data: peers } = usePeers()

const activeNetwork = useSelector(selectActiveNetwork)
const isDeveloperMode = useSelector(selectIsDeveloperMode)
const isEndTimeOverOneYear = isOverOneYear(stakingEndTime)
const noMatchError = new Error(
`no node matches filter criteria: stakingAmount: ${stakingAmount}, stakingEndTime: ${stakingEndTime}, minUpTime: ${minUpTime}`
)
const noValidatorsError = new Error(`no validators found.`)

// TODO: https://ava-labs.atlassian.net/browse/CP-9539
// simply return all nodes for devnet
if (isDevnet(activeNetwork)) {
return { validators, error: undefined }
}

if (validators && validators.length > 0) {
const filteredValidators = getFilteredValidators({
isDeveloperMode,
Expand All @@ -59,7 +75,8 @@ export const useAdvancedSearchNodes = ({
minUpTime,
maxFee,
searchText,
isEndTimeOverOneYear
isEndTimeOverOneYear,
isDevnet: isDevnet(activeNetwork)
})
if (filteredValidators.length === 0) {
Logger.info(noMatchError.message)
Expand Down
8 changes: 7 additions & 1 deletion packages/core-mobile/app/hooks/earn/useCChainNetwork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import { Network } from '@avalabs/core-chains-sdk'
import { useNetworks } from 'hooks/networks/useNetworks'
import { useMemo } from 'react'
import { getAvalancheNetwork } from 'services/network/utils/providerUtils'
import { isDevnet } from 'utils/isDevnet'

const useCChainNetwork = (): Network | undefined => {
const { activeNetwork, networks } = useNetworks()

return useMemo(
() => getAvalancheNetwork(networks, activeNetwork.isTestnet),
() =>
getAvalancheNetwork(
networks,
activeNetwork.isTestnet,
isDevnet(activeNetwork)
),
[activeNetwork, networks]
)
}
Expand Down
Loading

0 comments on commit fcceca8

Please sign in to comment.