-
Notifications
You must be signed in to change notification settings - Fork 635
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* types improvements * useSwapsStore * number & currency formatter * gasss * dont keep previous data * use chainId from input token * hm * decimal separator * add gas fee to review panel * 😕 * save * fix (#5758) * consolidated verified assets fetches (#5759) * fix (#5761) * chore: i18n updates (#5762) * APP-1500 (#5763) * fix * optional chaining just in case * allow message signing tx w/o loaded balance/gas * aaaaaa * uhu * add border back to review gas button * remove color todo tags * gasPrice --------- Co-authored-by: Matthew Wall <[email protected]> Co-authored-by: Ben Goldberg <[email protected]> Co-authored-by: Daniel Sinclair <[email protected]>
- Loading branch information
1 parent
1817a43
commit 341c192
Showing
18 changed files
with
1,004 additions
and
778 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import store from '@/redux/store'; | ||
import { supportedNativeCurrencies } from '@/references'; | ||
|
||
const decimalSeparator = '.'; | ||
export const formatNumber = (value: string, options?: { decimals?: number }) => { | ||
if (!+value) return `0${decimalSeparator}00`; | ||
if (+value < 0.0001) return `<0${decimalSeparator}0001`; | ||
|
||
const [whole, fraction = ''] = value.split(decimalSeparator); | ||
const decimals = options?.decimals; | ||
const paddedFraction = `${fraction.padEnd(decimals || 4, '0')}`; | ||
|
||
if (decimals) { | ||
if (decimals === 0) return whole; | ||
return `${whole}${decimalSeparator}${paddedFraction.slice(0, decimals)}`; | ||
} | ||
|
||
if (+whole > 0) return `${whole}${decimalSeparator}${paddedFraction.slice(0, 2)}`; | ||
return `0${decimalSeparator}${paddedFraction.slice(0, 4)}`; | ||
}; | ||
|
||
const getUserPreferredCurrency = () => { | ||
const currency = store.getState().settings.nativeCurrency; | ||
return supportedNativeCurrencies[currency]; | ||
}; | ||
|
||
export const formatCurrency = (value: string, currency = getUserPreferredCurrency()) => { | ||
const formatted = formatNumber(value); | ||
if (currency.alignment === 'left') return `${currency.symbol}${formatted}`; | ||
return `${formatted} ${currency.symbol}`; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,141 +1,37 @@ | ||
import { useGas } from '@/hooks'; | ||
import { useCallback } from 'react'; | ||
import { runOnJS, useAnimatedReaction, useDerivedValue, useSharedValue } from 'react-native-reanimated'; | ||
import { gasUtils } from '@/utils'; | ||
import { greaterThan } from '@/__swaps__/utils/numbers'; | ||
import { gweiToWei, parseGasFeeParam } from '@/parsers'; | ||
import { GasSpeed } from '@/__swaps__/types/gas'; | ||
|
||
export enum CUSTOM_GAS_FIELDS { | ||
MAX_BASE_FEE = 'maxBaseFee', | ||
PRIORITY_FEE = 'priorityFee', | ||
} | ||
|
||
const { CUSTOM } = gasUtils; | ||
|
||
/** | ||
* TODO: Work left to do for custom gas | ||
* 1. Need to add in currentBaseFee for current network | ||
* 2. Show current gas trend on custom gas panel UI somewhere | ||
* 3. Allow user to type in both fields (make both animated textinput component) | ||
* - will have to figure out how to handle prompting keyboard and dismissing | ||
* 4. Handle long press on both fields | ||
* 5. Handle showing warnings (overpaying, might fail, etc.) | ||
*/ | ||
|
||
export function useCustomGas() { | ||
const { selectedGasFee, currentBlockParams, updateToCustomGasFee, updateGasFeeOption, gasFeeParamsBySpeed } = useGas(); | ||
|
||
const currentBaseFee = useSharedValue<string>(currentBlockParams?.baseFeePerGas?.gwei || 'Unknown'); | ||
const maxBaseFee = useSharedValue<string>(currentBlockParams?.baseFeePerGas?.amount || '1'); | ||
const priorityFee = useSharedValue<string>('1'); | ||
|
||
const maxTransactionFee = useDerivedValue(() => { | ||
const gasPrice = gasFeeParamsBySpeed?.[GasSpeed.CUSTOM]?.maxBaseFee.gwei || ''; | ||
if (gasPrice.trim() === '') return 'Unknown'; | ||
return gasPrice; | ||
import { ChainId } from '@/__swaps__/types/chains'; | ||
import { createRainbowStore } from '@/state/internal/createRainbowStore'; | ||
|
||
export type EIP1159GasSettings = { | ||
isEIP1559: true; | ||
maxBaseFee: string; | ||
maxPriorityFee: string; | ||
}; | ||
|
||
export type LegacyGasSettings = { | ||
isEIP1559: false; | ||
gasPrice: string; | ||
}; | ||
|
||
export type GasSettings = EIP1159GasSettings | LegacyGasSettings; | ||
|
||
export type CustomGasStoreState = { [c in ChainId]?: GasSettings }; | ||
export const useCustomGasStore = createRainbowStore<CustomGasStoreState>(() => ({})); | ||
|
||
export const useCustomGasSettings = (chainId: ChainId) => useCustomGasStore(s => s[chainId]); | ||
export const getCustomGasSettings = (chainId: ChainId) => useCustomGasStore.getState()[chainId]; | ||
|
||
export const setCustomGasSettings = (chainId: ChainId, update: Partial<GasSettings>) => { | ||
useCustomGasStore.setState(s => { | ||
const state = s[chainId] || { | ||
isEIP1559: !('gasPrice' in update && !!update.gasPrice), | ||
maxBaseFee: '0', | ||
maxPriorityFee: '0', | ||
gasPrice: '0', | ||
}; | ||
return { [chainId]: { ...state, ...update } as GasSettings }; | ||
}); | ||
}; | ||
|
||
useAnimatedReaction( | ||
() => currentBlockParams?.baseFeePerGas?.gwei, | ||
current => { | ||
currentBaseFee.value = current; | ||
} | ||
); | ||
|
||
const updateCustomFieldValue = useCallback( | ||
(field: CUSTOM_GAS_FIELDS, value: string) => { | ||
switch (field) { | ||
case CUSTOM_GAS_FIELDS.MAX_BASE_FEE: { | ||
const maxBaseFee = parseGasFeeParam(gweiToWei(value || 0)); | ||
const newGasParams = { | ||
...selectedGasFee.gasFeeParams, | ||
maxBaseFee, | ||
}; | ||
updateToCustomGasFee(newGasParams); | ||
break; | ||
} | ||
|
||
case CUSTOM_GAS_FIELDS.PRIORITY_FEE: { | ||
const priorityFee = parseGasFeeParam(gweiToWei(value || 0)); | ||
const newGasParams = { | ||
...selectedGasFee.gasFeeParams, | ||
maxPriorityFeePerGas: priorityFee, | ||
}; | ||
updateToCustomGasFee(newGasParams); | ||
break; | ||
} | ||
} | ||
}, | ||
[selectedGasFee.gasFeeParams, updateToCustomGasFee] | ||
); | ||
|
||
const onUpdateField = useCallback( | ||
(field: CUSTOM_GAS_FIELDS, operation: 'increment' | 'decrement', step = 1) => { | ||
'worklet'; | ||
|
||
switch (field) { | ||
case CUSTOM_GAS_FIELDS.MAX_BASE_FEE: { | ||
const text = maxBaseFee.value; | ||
|
||
if (operation === 'decrement' && greaterThan(1, Number(text) - step)) { | ||
maxBaseFee.value = String(1); | ||
runOnJS(updateCustomFieldValue)(CUSTOM_GAS_FIELDS.MAX_BASE_FEE, String(1)); | ||
return; | ||
} | ||
|
||
const maxBaseFeeNumber = Number(text); | ||
maxBaseFee.value = operation === 'increment' ? String(maxBaseFeeNumber + step) : String(maxBaseFeeNumber - step); | ||
runOnJS(updateCustomFieldValue)(CUSTOM_GAS_FIELDS.MAX_BASE_FEE, maxBaseFee.value); | ||
break; | ||
} | ||
|
||
case CUSTOM_GAS_FIELDS.PRIORITY_FEE: { | ||
const text = priorityFee.value; | ||
|
||
if (operation === 'decrement' && greaterThan(1, Number(text) - step)) { | ||
priorityFee.value = String(1); | ||
runOnJS(updateCustomFieldValue)(CUSTOM_GAS_FIELDS.PRIORITY_FEE, String(1)); | ||
return; | ||
} | ||
|
||
const priorityFeeNumber = Number(text); | ||
priorityFee.value = operation === 'increment' ? String(priorityFeeNumber + step) : String(priorityFeeNumber - step); | ||
runOnJS(updateCustomFieldValue)(CUSTOM_GAS_FIELDS.PRIORITY_FEE, priorityFee.value); | ||
break; | ||
} | ||
} | ||
}, | ||
[maxBaseFee, priorityFee, updateCustomFieldValue] | ||
); | ||
|
||
const updateCustomGas = ({ priorityFee, baseFee }: { priorityFee: string; baseFee: string }) => { | ||
updateGasFeeOption(CUSTOM); | ||
const maxPriorityFeePerGas = parseGasFeeParam(gweiToWei(priorityFee || 0)); | ||
const maxBaseFee = parseGasFeeParam(gweiToWei(baseFee || 0)); | ||
|
||
updateToCustomGasFee({ | ||
...selectedGasFee.gasFeeParams, | ||
maxPriorityFeePerGas, | ||
maxBaseFee, | ||
}); | ||
}; | ||
|
||
const onSaveCustomGas = () => { | ||
'worklet'; | ||
|
||
runOnJS(updateCustomGas)({ | ||
priorityFee: priorityFee.value, | ||
baseFee: maxBaseFee.value, | ||
}); | ||
}; | ||
|
||
return { | ||
currentBaseFee, | ||
maxBaseFee, | ||
priorityFee, | ||
maxTransactionFee, | ||
onUpdateField, | ||
onSaveCustomGas, | ||
}; | ||
} | ||
export const setCustomMaxBaseFee = (chainId: ChainId, maxBaseFee = '0') => setCustomGasSettings(chainId, { maxBaseFee }); | ||
export const setCustomMaxPriorityFee = (chainId: ChainId, maxPriorityFee = '0') => setCustomGasSettings(chainId, { maxPriorityFee }); | ||
export const setCustomGasPrice = (chainId: ChainId, gasPrice = '0') => setCustomGasSettings(chainId, { gasPrice }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { ChainId } from '@/__swaps__/types/chains'; | ||
import { weiToGwei } from '@/__swaps__/utils/ethereum'; | ||
import { add, multiply } from '@/__swaps__/utils/numbers'; | ||
import { useSwapsStore } from '@/state/swaps/swapsStore'; | ||
import ethereumUtils, { useNativeAssetForNetwork } from '@/utils/ethereumUtils'; | ||
import { formatUnits } from 'viem'; | ||
import { formatCurrency, formatNumber } from './formatNumber'; | ||
import { GasSettings } from './useCustomGas'; | ||
import { useSwapEstimatedGasLimit } from './useSwapEstimatedGasLimit'; | ||
|
||
export function useEstimatedGasFee({ | ||
chainId, | ||
gasLimit, | ||
gasSettings, | ||
}: { | ||
chainId: ChainId; | ||
gasLimit: string | undefined; | ||
gasSettings: GasSettings | undefined; | ||
}) { | ||
const network = ethereumUtils.getNetworkFromChainId(chainId); | ||
const nativeNetworkAsset = useNativeAssetForNetwork(network); | ||
|
||
if (!gasLimit || !gasSettings || !nativeNetworkAsset) return 'Loading...'; // TODO: loading state | ||
|
||
const amount = gasSettings.isEIP1559 ? add(gasSettings.maxBaseFee, gasSettings.maxPriorityFee) : gasSettings.gasPrice; | ||
|
||
const totalWei = multiply(gasLimit, amount); | ||
const nativePrice = nativeNetworkAsset.price.value?.toString(); | ||
|
||
if (!nativePrice) return `${formatNumber(weiToGwei(totalWei))} Gwei`; | ||
|
||
const gasAmount = formatUnits(BigInt(totalWei), nativeNetworkAsset.decimals).toString(); | ||
const feeInUserCurrency = multiply(nativePrice, gasAmount); | ||
|
||
return formatCurrency(feeInUserCurrency); | ||
} | ||
|
||
export function useSwapEstimatedGasFee(gasSettings: GasSettings | undefined) { | ||
const chainId = useSwapsStore(s => s.inputAsset?.chainId || ChainId.mainnet); | ||
|
||
const assetToSell = useSwapsStore(s => s.inputAsset); | ||
const quote = useSwapsStore(s => s.quote); | ||
|
||
const { data: gasLimit } = useSwapEstimatedGasLimit({ chainId, quote, assetToSell }, { enabled: !!quote }); | ||
|
||
return useEstimatedGasFee({ chainId, gasLimit, gasSettings }); | ||
} |
Oops, something went wrong.