Skip to content

Commit

Permalink
feat(Send): refactor max button's behavior. (#2439)
Browse files Browse the repository at this point in the history
  • Loading branch information
richardo2016x committed Jul 26, 2024
1 parent 8629a58 commit c4dfa84
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 85 deletions.
2 changes: 2 additions & 0 deletions src/background/service/preference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export interface PreferenceStore {
themeMode?: DARK_MODE_TYPE;
addressSortStore: AddressSortStore;

/** @deprecated */
reserveGasOnSendToken?: boolean;
isHideEcologyNoticeDict?: Record<string | number, boolean>;
}
Expand Down Expand Up @@ -578,6 +579,7 @@ class PreferenceService {
this.store.themeMode = themeMode;
};

/** @deprecated */
isReserveGasOnSendToken = () => {
return this.store.reserveGasOnSendToken;
};
Expand Down
1 change: 1 addition & 0 deletions src/ui/models/preference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const preference = createModel<RootModel>()({

selectors: (slice) => {
return {
/** @deprecated */
isReserveGasOnSendToken() {
return slice((preference) => preference.reserveGasOnSendToken);
},
Expand Down
2 changes: 1 addition & 1 deletion src/ui/views/SendToken/components/GasReserved.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const TokenAmount = styled.span`
interface GasReservedProps {
amount: string;
token: TokenItem;
onClickAmount(): void;
onClickAmount?(): void;
}

const GasReserved = ({ amount, token, onClickAmount }: GasReservedProps) => {
Expand Down
155 changes: 81 additions & 74 deletions src/ui/views/SendToken/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import BigNumber from 'bignumber.js';
import { Trans, useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom';
import { matomoRequestEvent } from '@/utils/matomo-request';
import { useDebounce } from 'react-use';
import { useAsyncFn, useDebounce } from 'react-use';
import { Input, Form, Skeleton, message, Button, InputProps } from 'antd';
import abiCoderInst, { AbiCoder } from 'web3-eth-abi';
import { isValidAddress, intToHex, zeroAddress } from 'ethereumjs-util';

import styled from 'styled-components';
import {
CHAINS,
CHAINS_ENUM,
Expand Down Expand Up @@ -80,8 +79,11 @@ import { formatTxInputDataOnERC20 } from '@/ui/utils/transaction';
import ThemeIcon from '@/ui/component/ThemeMode/ThemeIcon';
import { customTestnetTokenToTokenItem } from '@/ui/utils/token';
import { copyAddress } from '@/ui/utils/clipboard';
import SwitchReserveGas from './components/SwitchReserveGas';
import { MaxButton } from './components/MaxButton';
import {
GasLevelType,
ReserveGasPopup,
} from '../Swap/Component/ReserveGasPopup';

const abiCoder = (abiCoderInst as unknown) as AbiCoder;

Expand Down Expand Up @@ -273,6 +275,12 @@ const SendTokenMessageForContract = React.forwardRef<
// raw_amount_hex_str?: string;
// }

function findInstanceLevel(gasList: GasLevel[]) {
return gasList.reduce((prev, current) =>
prev.price >= current.price ? prev : current
);
}

type FormSendToken = {
to: string;
amount: string;
Expand Down Expand Up @@ -345,7 +353,7 @@ const SendToken = () => {
[wallet, history, form, currentToken, safeInfo]
);
const [inited, setInited] = useState(false);
const [gasList, setGasList] = useState<GasLevel[]>([]);
// const [gasList, setGasList] = useState<GasLevel[]>([]);
const [sendAlianName, setSendAlianName] = useState<string | null>(null);
const [showEditContactModal, setShowEditContactModal] = useState(false);
const [showListContactModal, setShowListContactModal] = useState(false);
Expand All @@ -360,6 +368,7 @@ const SendToken = () => {
{ showGasReserved, clickedMax, isEstimatingGas },
setSendMaxInfo,
] = useState({
/** @deprecated */
showGasReserved: false,
clickedMax: false,
isEstimatingGas: false,
Expand All @@ -375,7 +384,12 @@ const SendToken = () => {
}, []);
const [showContactInfo, setShowContactInfo] = useState(false);
const [showWhitelistAlert, setShowWhitelistAlert] = useState(false);
const [gasSelectorVisible, setGasSelectorVisible] = useState(false);

const [reserveGasOpen, setReserveGasOpen] = useState(false);
const handleReserveGasClose = useCallback(() => {
setReserveGasOpen(false);
}, []);

const [selectedGasLevel, setSelectedGasLevel] = useState<GasLevel | null>(
null
);
Expand Down Expand Up @@ -459,6 +473,16 @@ const SendToken = () => {
return list;
}, [wallet, chainItem]);

const [{ value: gasList }, loadGasList] = useAsyncFn(() => {
// gasPriceRef.current = undefined;
// setGasLevel('normal');
return fetchGasList();
}, [fetchGasList]);

useEffect(() => {
loadGasList();
}, [loadGasList]);

useDebounce(
async () => {
const targetChain = findChainByEnum(chain)!;
Expand Down Expand Up @@ -699,20 +723,7 @@ const SendToken = () => {
if (amount !== cacheAmount) {
if (showGasReserved && Number(resultAmount) > 0) {
setShowGasReserved(false);
} /* else if (isNativeToken && !isGnosisSafe) {
const gasCostTokenAmount = await calcGasCost();
if (
new BigNumber(targetToken.raw_amount_hex_str || 0)
.div(10 ** targetToken.decimals)
.minus(amount)
.minus(gasCostTokenAmount)
.lt(0)
) {
setBalanceWarn(t('page.sendToken.balanceWarn.gasFeeReservation'));
} else {
setBalanceWarn(null);
}
} */
}
}

if (
Expand Down Expand Up @@ -873,9 +884,21 @@ const SendToken = () => {
]);

const handleGasChange = useCallback(
(gas: GasLevel, updateTokenAmount = true, gasLimit = MINIMUM_GAS_LIMIT) => {
setSelectedGasLevel(gas);
const gasTokenAmount = new BigNumber(gas.price).times(gasLimit).div(1e18);
(input: {
gasLevel: GasLevel;
updateTokenAmount?: boolean;
gasLimit?: number;
}) => {
const {
gasLevel,
updateTokenAmount = true,
gasLimit = MINIMUM_GAS_LIMIT,
} = input;
setSelectedGasLevel(gasLevel);

const gasTokenAmount = new BigNumber(gasLevel.price)
.times(gasLimit)
.div(1e18);
setTokenAmountForGas(gasTokenAmount.toFixed());
if (updateTokenAmount) {
const values = form.getFieldsValue();
Expand All @@ -901,20 +924,13 @@ const SendToken = () => {
]
);

const isReserveGasOnSendToken = useRabbyGetter(
(s) => s.preference.isReserveGasOnSendToken
);

const couldReserveGas = isNativeToken && !isGnosisSafe;

const handleMaxInfoChanged = useCallback(
async (needReserveGasOnSendToken?: boolean) => {
async (input?: { gasLevel: GasLevel }) => {
if (!currentAccount) return;
setSendMaxInfo((prev) => ({ ...prev, clickedMax: true }));

if (isLoading) return;
if (showGasReserved && typeof needReserveGasOnSendToken !== 'boolean')
return;
if (isEstimatingGas) return;

const tokenBalance = new BigNumber(
Expand All @@ -923,22 +939,24 @@ const SendToken = () => {
let amount = tokenBalance.toFixed();
const to = form.getFieldValue('to');

const {
gasLevel = selectedGasLevel ||
(await loadGasList().then(findInstanceLevel)),
} = input || {};
const needReserveGasOnSendToken = gasLevel.price > 0;

if (couldReserveGas && needReserveGasOnSendToken) {
setShowGasReserved(true);
setSendMaxInfo((prev) => ({ ...prev, isEstimatingGas: true }));
try {
const list = await fetchGasList();
setGasList(list);
let instant = list[0];
for (let i = 1; i < list.length; i++) {
if (list[i].price > instant.price) {
instant = list[i];
}
}
const { gasNumber } = await ethEstimateGas();
setEstimateGas(gasNumber);

let gasTokenAmount = handleGasChange(instant, false, gasNumber);
let gasTokenAmount = handleGasChange({
gasLevel: gasLevel,
updateTokenAmount: false,
gasLimit: gasNumber,
});
if (CAN_ESTIMATE_L1_FEE_CHAINS.includes(chain)) {
const l1GasFee = await wallet.fetchEstimatedL1Fee(
{
Expand All @@ -948,7 +966,7 @@ const SendToken = () => {
to: to && isValidAddress(to) ? to : zeroAddress(),
value: currentToken.raw_amount_hex_str,
gas: intToHex(21000),
gasPrice: `0x${new BigNumber(instant.price).toString(16)}`,
gasPrice: `0x${new BigNumber(gasLevel.price).toString(16)}`,
data: '0x',
},
},
Expand Down Expand Up @@ -989,32 +1007,29 @@ const SendToken = () => {
currentToken.decimals,
currentToken.raw_amount_hex_str,
ethEstimateGas,
fetchGasList,
selectedGasLevel,
loadGasList,
form,
handleFormValuesChange,
handleGasChange,
couldReserveGas,
isGnosisSafe,
isLoading,
setShowGasReserved,
showGasReserved,
isEstimatingGas,
wallet,
]
);

const handleClickMaxButton = useCallback(() => {
handleMaxInfoChanged(isReserveGasOnSendToken);
}, [isReserveGasOnSendToken, handleMaxInfoChanged]);
const handleClickMaxButton = useCallback(async () => {
setSendMaxInfo((prev) => ({ ...prev, clickedMax: true }));

const onSwitchReserveGas = useCallback(
async (isReserveGasOnSendToken: boolean) => {
if (clickedMax) {
handleMaxInfoChanged(isReserveGasOnSendToken);
}
},
[clickedMax, handleMaxInfoChanged]
);
if (couldReserveGas) {
setReserveGasOpen(true);
} else {
handleMaxInfoChanged();
}
}, [couldReserveGas, handleMaxInfoChanged]);

const handleChainChanged = useCallback(
async (val: CHAINS_ENUM) => {
Expand Down Expand Up @@ -1204,10 +1219,6 @@ const SendToken = () => {
setSendAlianName(alianName || '');
};

const handleGasSelectorClose = () => {
setGasSelectorVisible(false);
};

const handleClickAllowTransferTo = () => {
if (!whitelistEnabled || temporaryGrant || toAddressInWhitelist) return;

Expand Down Expand Up @@ -1446,7 +1457,7 @@ const SendToken = () => {
<GasReserved
token={currentToken}
amount={tokenAmountForGas}
onClickAmount={handleClickGasReserved}
// onClickAmount={handleClickGasReserved}
/>
) : (
<Skeleton.Input active style={{ width: 180 }} />
Expand All @@ -1459,13 +1470,6 @@ const SendToken = () => {
{balanceError || balanceWarn}
</div>
) : null}
{clickedMax && couldReserveGas && (
<SwitchReserveGas
loading={isEstimatingGas}
disabled={isEstimatingGas || !couldReserveGas}
onChange={onSwitchReserveGas}
/>
)}
</div>
<Form.Item name="amount">
{currentAccount && chainItem && (
Expand Down Expand Up @@ -1585,17 +1589,20 @@ const SendToken = () => {
onOk={handleConfirmContact}
/>

<GasSelector
visible={gasSelectorVisible}
onClose={handleGasSelectorClose}
chainId={chainItem?.id || CHAINS.ETH.id}
onChange={(val) => {
setGasSelectorVisible(false);
handleGasChange(val);
<ReserveGasPopup
selectedItem={selectedGasLevel?.level as GasLevelType}
chain={chain}
limit={MINIMUM_GAS_LIMIT}
onGasChange={(gasLevel) => {
handleReserveGasClose();
setSelectedGasLevel(gasLevel);
handleMaxInfoChanged({ gasLevel });
// handleGasChange({ gasLevel, updateTokenAmount: true });
}}
gasList={gasList}
gas={selectedGasLevel}
token={currentToken}
visible={reserveGasOpen}
onCancel={handleReserveGasClose}
onClose={handleReserveGasClose}
/>
</div>
);
Expand Down
3 changes: 2 additions & 1 deletion src/ui/views/Swap/Component/ReserveGasPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import { ReactComponent as RcIconCheckedCC } from '@/ui/assets/icon-checked-cc.s
import { ReactComponent as RcIconUnCheckedCC } from '@/ui/assets/icon-unchecked-cc.svg';
import { PopupProps } from '@/ui/component/Popup';

export type GasLevelType = keyof typeof SORT_SCORE;
interface ReserveGasContentProps {
chain: CHAINS_ENUM;
gasList?: GasLevel[];
limit: number;
selectedItem?: string;
selectedItem?: GasLevelType | string;
onGasChange: (gasLevel: GasLevel) => void;
}

Expand Down
16 changes: 7 additions & 9 deletions src/ui/views/Swap/hooks/token.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import stats from '@/stats';
import { useAsyncInitializeChainList } from '@/ui/hooks/useChain';
import { SWAP_SUPPORT_CHAINS } from '@/constant';
import { findChain } from '@/utils/chain';
import { GasLevelType } from '../Component/ReserveGasPopup';

const useTokenInfo = ({
userAddress,
Expand Down Expand Up @@ -227,7 +228,7 @@ export const useTokenPair = (userAddress: string) => {
[]
);

const [gasLevel, setGasLevel] = useState('normal');
const [gasLevel, setGasLevel] = useState<GasLevelType>('normal');
const gasPriceRef = useRef<number>();

const { value: gasList } = useAsync(() => {
Expand Down Expand Up @@ -269,14 +270,11 @@ export const useTokenPair = (userAddress: string) => {
}
}, [payToken, chain, nativeTokenDecimals, gasLimit]);

const changeGasPrice = useCallback(
(gasLevel: GasLevel) => {
gasPriceRef.current = gasLevel.level === 'custom' ? 0 : gasLevel.price;
setGasLevel(gasLevel.level);
closeReserveGasOpen();
},
[closeReserveGasOpen]
);
const changeGasPrice = useCallback((gasLevel: GasLevel) => {
gasPriceRef.current = gasLevel.level === 'custom' ? 0 : gasLevel.price;
setGasLevel(gasLevel.level as GasLevelType);
closeReserveGasOpen();
}, []);

const handleBalance = useCallback(() => {
if (payTokenIsNativeToken) {
Expand Down

0 comments on commit c4dfa84

Please sign in to comment.