diff --git a/test/jest/mock-store.js b/test/jest/mock-store.js
index 0e93e04ee..f57ae13ae 100644
--- a/test/jest/mock-store.js
+++ b/test/jest/mock-store.js
@@ -234,6 +234,7 @@ export const createSwapsMockStore = () => {
           },
         },
       },
+      gasLoadingAnimationIsShowing: false,
     },
   };
 };
diff --git a/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js b/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js
index 66ced39b1..75281a2e0 100644
--- a/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js
+++ b/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js
@@ -7,6 +7,8 @@ import FormField from '../../ui/form-field';
 import { GAS_ESTIMATE_TYPES } from '../../../../shared/constants/gas';
 import { getGasFormErrorText } from '../../../helpers/constants/gas';
 import { checkNetworkAndAccountSupports1559 } from '../../../selectors';
+import { getIsGasEstimatesLoading } from '../../../ducks/metamask/metamask';
+import { getGasLoadingAnimationIsShowing } from '../../../ducks/app/app';
 
 export default function AdvancedGasControls({
   gasEstimateType,
@@ -28,6 +30,12 @@ export default function AdvancedGasControls({
   const networkAndAccountSupport1559 = useSelector(
     checkNetworkAndAccountSupports1559,
   );
+  const isGasEstimatesLoading = useSelector(getIsGasEstimatesLoading);
+  const isGasLoadingAnimationIsShowing = useSelector(
+    getGasLoadingAnimationIsShowing,
+  );
+  const disableFormFields =
+    isGasEstimatesLoading || isGasLoadingAnimationIsShowing;
 
   const showFeeMarketFields =
     networkAndAccountSupport1559 &&
@@ -71,6 +79,7 @@ export default function AdvancedGasControls({
                 ? getGasFormErrorText(gasErrors.maxPriorityFee, t)
                 : null
             }
+            disabled={disableFormFields}
           />
           <FormField
             titleText={t('maxFee')}
@@ -88,6 +97,7 @@ export default function AdvancedGasControls({
                 ? getGasFormErrorText(gasErrors.maxFee, t)
                 : null
             }
+            disabled={disableFormFields}
           />
         </>
       ) : (
@@ -107,6 +117,7 @@ export default function AdvancedGasControls({
                 ? getGasFormErrorText(gasErrors.gasPrice, t)
                 : null
             }
+            disabled={disableFormFields}
           />
         </>
       )}
diff --git a/ui/components/app/edit-gas-popover/edit-gas-popover.component.js b/ui/components/app/edit-gas-popover/edit-gas-popover.component.js
index c213feac3..432aee2c8 100644
--- a/ui/components/app/edit-gas-popover/edit-gas-popover.component.js
+++ b/ui/components/app/edit-gas-popover/edit-gas-popover.component.js
@@ -2,7 +2,7 @@ import React, { useCallback, useContext, useState } from 'react';
 import PropTypes from 'prop-types';
 import { useDispatch, useSelector } from 'react-redux';
 import { useGasFeeInputs } from '../../../hooks/useGasFeeInputs';
-import { useShouldAnimateGasEstimations } from '../../../hooks/useShouldAnimateGasEstimations';
+import { getGasLoadingAnimationIsShowing } from '../../../ducks/app/app';
 
 import { EDIT_GAS_MODES, GAS_LIMITS } from '../../../../shared/constants/gas';
 
@@ -45,8 +45,9 @@ export default function EditGasPopover({
   const networkAndAccountSupport1559 = useSelector(
     checkNetworkAndAccountSupports1559,
   );
-
-  const shouldAnimate = useShouldAnimateGasEstimations();
+  const gasLoadingAnimationIsShowing = useSelector(
+    getGasLoadingAnimationIsShowing,
+  );
 
   const showEducationButton =
     (mode === EDIT_GAS_MODES.MODIFY_IN_PLACE ||
@@ -192,7 +193,12 @@ export default function EditGasPopover({
             <Button
               type="primary"
               onClick={onSubmit}
-              disabled={hasGasErrors || isGasEstimatesLoading || balanceError}
+              disabled={
+                hasGasErrors ||
+                isGasEstimatesLoading ||
+                balanceError ||
+                gasLoadingAnimationIsShowing
+              }
             >
               {footerButtonText}
             </Button>
@@ -205,9 +211,7 @@ export default function EditGasPopover({
           <EditGasDisplayEducation />
         ) : (
           <>
-            {process.env.IN_TEST === 'true' ? null : (
-              <LoadingHeartBeat active={shouldAnimate} />
-            )}
+            {process.env.IN_TEST === 'true' ? null : <LoadingHeartBeat />}
             <EditGasDisplay
               showEducationButton={showEducationButton}
               warning={warning}
diff --git a/ui/components/app/gas-timing/gas-timing.component.js b/ui/components/app/gas-timing/gas-timing.component.js
index 7c94732e5..c00ddc5e2 100644
--- a/ui/components/app/gas-timing/gas-timing.component.js
+++ b/ui/components/app/gas-timing/gas-timing.component.js
@@ -1,14 +1,20 @@
 import React, { useContext, useEffect, useState } from 'react';
+import { useSelector } from 'react-redux';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
 import BigNumber from 'bignumber.js';
 
 import { GAS_ESTIMATE_TYPES } from '../../../../shared/constants/gas';
 
-import { useGasFeeEstimates } from '../../../hooks/useGasFeeEstimates';
 import { usePrevious } from '../../../hooks/usePrevious';
 import { I18nContext } from '../../../contexts/i18n';
 
+import {
+  getGasEstimateType,
+  getGasFeeEstimates,
+  getIsGasEstimatesLoading,
+} from '../../../ducks/metamask/metamask';
+
 import Typography from '../../ui/typography/typography';
 import {
   TYPOGRAPHY,
@@ -33,11 +39,9 @@ export default function GasTiming({
   maxFeePerGas = 0,
   maxPriorityFeePerGas = 0,
 }) {
-  const {
-    gasFeeEstimates,
-    isGasEstimatesLoading,
-    gasEstimateType,
-  } = useGasFeeEstimates();
+  const gasEstimateType = useSelector(getGasEstimateType);
+  const gasFeeEstimates = useSelector(getGasFeeEstimates);
+  const isGasEstimatesLoading = useSelector(getIsGasEstimatesLoading);
 
   const [customEstimatedTime, setCustomEstimatedTime] = useState(null);
 
diff --git a/ui/components/app/gas-timing/gas-timing.component.test.js b/ui/components/app/gas-timing/gas-timing.component.test.js
index c892fda66..bed11b08b 100644
--- a/ui/components/app/gas-timing/gas-timing.component.test.js
+++ b/ui/components/app/gas-timing/gas-timing.component.test.js
@@ -1,4 +1,5 @@
 import React from 'react';
+import { useSelector } from 'react-redux';
 import { shallow } from 'enzyme';
 import sinon from 'sinon';
 
@@ -9,7 +10,13 @@ import messages from '../../../../app/_locales/en/messages.json';
 import { getMessage } from '../../../helpers/utils/i18n-helper';
 
 import * as i18nhooks from '../../../hooks/useI18nContext';
-import * as useGasFeeEstimatesExport from '../../../hooks/useGasFeeEstimates';
+
+import { checkNetworkAndAccountSupports1559 } from '../../../selectors';
+import {
+  getGasEstimateType,
+  getGasFeeEstimates,
+  getIsGasEstimatesLoading,
+} from '../../../ducks/metamask/metamask';
 
 import GasTiming from '.';
 
@@ -35,58 +42,103 @@ const MOCK_FEE_ESTIMATE = {
   estimatedBaseFee: '50',
 };
 
+jest.mock('react-redux', () => {
+  const actual = jest.requireActual('react-redux');
+
+  return {
+    ...actual,
+    useSelector: jest.fn(),
+  };
+});
+
+const DEFAULT_OPTS = {
+  gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
+  gasFeeEstimates: {
+    low: '10',
+    medium: '20',
+    high: '30',
+  },
+  isGasEstimatesLoading: true,
+};
+
+const generateUseSelectorRouter = (opts = DEFAULT_OPTS) => (selector) => {
+  if (selector === checkNetworkAndAccountSupports1559) {
+    return true;
+  }
+  if (selector === getGasEstimateType) {
+    return opts.gasEstimateType ?? DEFAULT_OPTS.gasEstimateType;
+  }
+  if (selector === getGasFeeEstimates) {
+    return opts.gasFeeEstimates ?? DEFAULT_OPTS.gasFeeEstimates;
+  }
+  if (selector === getIsGasEstimatesLoading) {
+    return opts.isGasEstimatesLoading ?? DEFAULT_OPTS.isGasEstimatesLoading;
+  }
+  return undefined;
+};
+
 describe('Gas timing', () => {
   beforeEach(() => {
     const useI18nContext = sinon.stub(i18nhooks, 'useI18nContext');
     useI18nContext.returns((key, variables) =>
       getMessage('en', messages, key, variables),
     );
+    jest.clearAllMocks();
+    useSelector.mockImplementation(generateUseSelectorRouter());
   });
   afterEach(() => {
     sinon.restore();
   });
 
   it('renders nothing when gas is loading', () => {
-    sinon.stub(useGasFeeEstimatesExport, 'useGasFeeEstimates').returns({
-      isGasEstimatesLoading: true,
-      gasFeeEstimates: null,
-      gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
-    });
+    useSelector.mockImplementation(
+      generateUseSelectorRouter({
+        isGasEstimatesLoading: true,
+        gasFeeEstimates: null,
+        gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
+      }),
+    );
 
     const wrapper = shallow(<GasTiming />);
     expect(wrapper.html()).toBeNull();
   });
 
   it('renders "very likely" when high estimate is chosen', () => {
-    sinon.stub(useGasFeeEstimatesExport, 'useGasFeeEstimates').returns({
-      isGasEstimatesLoading: false,
-      gasFeeEstimates: MOCK_FEE_ESTIMATE,
-      gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
-    });
+    useSelector.mockImplementation(
+      generateUseSelectorRouter({
+        isGasEstimatesLoading: false,
+        gasFeeEstimates: MOCK_FEE_ESTIMATE,
+        gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
+      }),
+    );
 
-    const wrapper = shallow(<GasTiming maxPriorityFeePerGas={10} />);
+    const wrapper = shallow(<GasTiming maxPriorityFeePerGas="10" />);
     expect(wrapper.html()).toContain('gasTimingVeryPositive');
   });
 
   it('renders "likely" when medium estimate is chosen', () => {
-    sinon.stub(useGasFeeEstimatesExport, 'useGasFeeEstimates').returns({
-      isGasEstimatesLoading: false,
-      gasFeeEstimates: MOCK_FEE_ESTIMATE,
-      gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
-    });
+    useSelector.mockImplementation(
+      generateUseSelectorRouter({
+        isGasEstimatesLoading: false,
+        gasFeeEstimates: MOCK_FEE_ESTIMATE,
+        gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
+      }),
+    );
 
-    const wrapper = shallow(<GasTiming maxPriorityFeePerGas={8} />);
+    const wrapper = shallow(<GasTiming maxPriorityFeePerGas="8" />);
     expect(wrapper.html()).toContain('gasTimingPositive');
   });
 
   it('renders "maybe" when low estimate is chosen', () => {
-    sinon.stub(useGasFeeEstimatesExport, 'useGasFeeEstimates').returns({
-      isGasEstimatesLoading: false,
-      gasFeeEstimates: MOCK_FEE_ESTIMATE,
-      gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
-    });
+    useSelector.mockImplementation(
+      generateUseSelectorRouter({
+        isGasEstimatesLoading: false,
+        gasFeeEstimates: MOCK_FEE_ESTIMATE,
+        gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
+      }),
+    );
 
-    const wrapper = shallow(<GasTiming maxPriorityFeePerGas={3} />);
+    const wrapper = shallow(<GasTiming maxPriorityFeePerGas="3" />);
     expect(wrapper.html()).toContain('gasTimingNegative');
   });
 });
diff --git a/ui/components/app/transaction-detail/transaction-detail.component.js b/ui/components/app/transaction-detail/transaction-detail.component.js
index 0829df684..2f12d89da 100644
--- a/ui/components/app/transaction-detail/transaction-detail.component.js
+++ b/ui/components/app/transaction-detail/transaction-detail.component.js
@@ -1,18 +1,33 @@
 import React, { useContext } from 'react';
 import PropTypes from 'prop-types';
+import { useSelector } from 'react-redux';
+
+import { getIsGasEstimatesLoading } from '../../../ducks/metamask/metamask';
+import { getGasLoadingAnimationIsShowing } from '../../../ducks/app/app';
 
 import { I18nContext } from '../../../contexts/i18n';
 
 import TransactionDetailItem from '../transaction-detail-item/transaction-detail-item.component';
+import LoadingHeartBeat from '../../ui/loading-heartbeat';
 
 export default function TransactionDetail({ rows = [], onEdit }) {
   const t = useContext(I18nContext);
+  const isGasEstimatesLoading = useSelector(getIsGasEstimatesLoading);
+  const gasLoadingAnimationIsShowing = useSelector(
+    getGasLoadingAnimationIsShowing,
+  );
 
   return (
     <div className="transaction-detail">
+      {process.env.IN_TEST === 'true' ? null : <LoadingHeartBeat />}
       {onEdit && (
         <div className="transaction-detail-edit">
-          <button onClick={onEdit}>{t('edit')}</button>
+          <button
+            onClick={onEdit}
+            disabled={isGasEstimatesLoading || gasLoadingAnimationIsShowing}
+          >
+            {t('edit')}
+          </button>
         </div>
       )}
       <div className="transaction-detail-rows">{rows}</div>
diff --git a/ui/components/ui/form-field/form-field.js b/ui/components/ui/form-field/form-field.js
index 9152937a6..d735636ac 100644
--- a/ui/components/ui/form-field/form-field.js
+++ b/ui/components/ui/form-field/form-field.js
@@ -28,6 +28,7 @@ export default function FormField({
   autoFocus,
   password,
   allowDecimals,
+  disabled,
 }) {
   return (
     <div
@@ -81,6 +82,7 @@ export default function FormField({
             detailText={detailText}
             autoFocus={autoFocus}
             allowDecimals={allowDecimals}
+            disabled={disabled}
           />
         ) : (
           <input
@@ -91,6 +93,7 @@ export default function FormField({
             value={value}
             type={password ? 'password' : 'text'}
             autoFocus={autoFocus}
+            disabled={disabled}
           />
         )}
         {error && (
@@ -120,6 +123,7 @@ FormField.propTypes = {
   numeric: PropTypes.bool,
   password: PropTypes.bool,
   allowDecimals: PropTypes.bool,
+  disabled: PropTypes.bool,
 };
 
 FormField.defaultProps = {
@@ -135,4 +139,5 @@ FormField.defaultProps = {
   numeric: false,
   password: false,
   allowDecimals: true,
+  disabled: false,
 };
diff --git a/ui/components/ui/loading-heartbeat/index.js b/ui/components/ui/loading-heartbeat/index.js
index fae2e886d..2c8e491e8 100644
--- a/ui/components/ui/loading-heartbeat/index.js
+++ b/ui/components/ui/loading-heartbeat/index.js
@@ -1,36 +1,25 @@
 import classNames from 'classnames';
-import PropTypes from 'prop-types';
-import React, { useEffect, useRef } from 'react';
+import React from 'react';
+import { useSelector } from 'react-redux';
+import { getGasLoadingAnimationIsShowing } from '../../../ducks/app/app';
+import { useShouldAnimateGasEstimations } from '../../../hooks/useShouldAnimateGasEstimations';
 
-export default function LoadingHeartBeat({ active }) {
-  const heartNode = useRef(null);
+const BASE_CLASS = 'loading-heartbeat';
+const LOADING_CLASS = `${BASE_CLASS}--active`;
 
-  const LOADING_CLASS = 'loading-heartbeat--active';
-
-  // When the loading animation completes, remove the className to disappear again
-  useEffect(() => {
-    const eventName = 'animationend';
-    const node = heartNode?.current;
-    const eventHandler = () => {
-      node?.classList.remove(LOADING_CLASS);
-    };
-
-    node?.addEventListener(eventName, eventHandler);
-    return () => {
-      node?.removeEventListener(eventName, eventHandler);
-    };
-  }, [heartNode]);
+export default function LoadingHeartBeat() {
+  useShouldAnimateGasEstimations();
+  const active = useSelector(getGasLoadingAnimationIsShowing);
 
   return (
     <div
       className={classNames('loading-heartbeat', {
         [LOADING_CLASS]: active,
       })}
-      ref={heartNode}
+      onClick={(e) => {
+        e.preventDefault();
+        e.stopPropagation();
+      }}
     ></div>
   );
 }
-
-LoadingHeartBeat.propTypes = {
-  active: PropTypes.bool,
-};
diff --git a/ui/components/ui/loading-heartbeat/index.scss b/ui/components/ui/loading-heartbeat/index.scss
index 0b1b095f2..0e3c4d19d 100644
--- a/ui/components/ui/loading-heartbeat/index.scss
+++ b/ui/components/ui/loading-heartbeat/index.scss
@@ -7,10 +7,14 @@
   opacity: 0;
   background: #fff;
   display: none;
+  pointer-events: none;
 
   &--active {
     display: block;
-    animation: heartbeat 2s ease-in-out;
+    animation-name: heartbeat;
+    animation-duration: 2s;
+    animation-timing-function: ease-in-out;
+    animation-iteration-count: infinite;
   }
 }
 
diff --git a/ui/components/ui/numeric-input/numeric-input.component.js b/ui/components/ui/numeric-input/numeric-input.component.js
index 1fe9a18d2..0befdf4f6 100644
--- a/ui/components/ui/numeric-input/numeric-input.component.js
+++ b/ui/components/ui/numeric-input/numeric-input.component.js
@@ -11,6 +11,7 @@ export default function NumericInput({
   error = '',
   autoFocus = false,
   allowDecimals = true,
+  disabled = false,
 }) {
   return (
     <div
@@ -29,6 +30,7 @@ export default function NumericInput({
         }}
         min="0"
         autoFocus={autoFocus}
+        disabled={disabled}
       />
       {detailText && (
         <Typography color={COLORS.UI4} variant={TYPOGRAPHY.H7} tag="span">
@@ -46,4 +48,5 @@ NumericInput.propTypes = {
   error: PropTypes.string,
   autoFocus: PropTypes.bool,
   allowDecimals: PropTypes.bool,
+  disabled: PropTypes.bool,
 };
diff --git a/ui/ducks/app/app.js b/ui/ducks/app/app.js
index e3b3e275f..93a21a16f 100644
--- a/ui/ducks/app/app.js
+++ b/ui/ducks/app/app.js
@@ -53,6 +53,7 @@ export default function reduceApp(state = {}, action) {
     singleExceptions: {
       testKey: null,
     },
+    gasLoadingAnimationIsShowing: false,
     ...state,
   };
 
@@ -358,6 +359,12 @@ export default function reduceApp(state = {}, action) {
         },
       };
 
+    case actionConstants.TOGGLE_GAS_LOADING_ANIMATION:
+      return {
+        ...appState,
+        gasLoadingAnimationIsShowing: action.value,
+      };
+
     default:
       return appState;
   }
@@ -377,7 +384,15 @@ export function hideWhatsNewPopup() {
   };
 }
 
+export function toggleGasLoadingAnimation(value) {
+  return { type: actionConstants.TOGGLE_GAS_LOADING_ANIMATION, value };
+}
+
 // Selectors
 export function getQrCodeData(state) {
   return state.appState.qrCodeData;
 }
+
+export function getGasLoadingAnimationIsShowing(state) {
+  return state.appState.gasLoadingAnimationIsShowing;
+}
diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js
index 8d93677a1..b2bef9558 100644
--- a/ui/ducks/metamask/metamask.js
+++ b/ui/ducks/metamask/metamask.js
@@ -4,11 +4,13 @@ import { ALERT_TYPES } from '../../../shared/constants/alerts';
 import { NETWORK_TYPE_RPC } from '../../../shared/constants/network';
 import {
   accountsWithSendEtherInfoSelector,
+  checkNetworkAndAccountSupports1559,
   getAddressBook,
 } from '../../selectors';
 import { updateTransaction } from '../../store/actions';
 import { setCustomGasLimit, setCustomGasPrice } from '../gas/gas.duck';
 import { decGWEIToHexWEI } from '../../helpers/utils/conversions.util';
+import { GAS_ESTIMATE_TYPES } from '../../../shared/constants/gas';
 
 export default function reduceMetamask(state = {}, action) {
   const metamaskState = {
@@ -299,3 +301,24 @@ export function getGasFeeEstimates(state) {
 export function getEstimatedGasFeeTimeBounds(state) {
   return state.metamask.estimatedGasFeeTimeBounds;
 }
+
+export function getIsGasEstimatesLoading(state) {
+  const networkAndAccountSupports1559 = checkNetworkAndAccountSupports1559(
+    state,
+  );
+  const gasEstimateType = getGasEstimateType(state);
+
+  // We consider the gas estimate to be loading if the gasEstimateType is
+  // 'NONE' or if the current gasEstimateType cannot be supported by the current
+  // network
+  const isEIP1559TolerableEstimateType =
+    gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET ||
+    gasEstimateType === GAS_ESTIMATE_TYPES.ETH_GASPRICE;
+  const isGasEstimatesLoading =
+    gasEstimateType === GAS_ESTIMATE_TYPES.NONE ||
+    (networkAndAccountSupports1559 && !isEIP1559TolerableEstimateType) ||
+    (!networkAndAccountSupports1559 &&
+      gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET);
+
+  return isGasEstimatesLoading;
+}
diff --git a/ui/hooks/useGasFeeEstimates.js b/ui/hooks/useGasFeeEstimates.js
index 094e575f9..7bbdd4fc0 100644
--- a/ui/hooks/useGasFeeEstimates.js
+++ b/ui/hooks/useGasFeeEstimates.js
@@ -1,17 +1,12 @@
 import { useSelector } from 'react-redux';
-import { GAS_ESTIMATE_TYPES } from '../../shared/constants/gas';
 import {
   getEstimatedGasFeeTimeBounds,
   getGasEstimateType,
   getGasFeeEstimates,
+  getIsGasEstimatesLoading,
 } from '../ducks/metamask/metamask';
-import { checkNetworkAndAccountSupports1559 } from '../selectors';
 import { useSafeGasEstimatePolling } from './useSafeGasEstimatePolling';
 
-/**
- * @typedef {keyof typeof GAS_ESTIMATE_TYPES} GasEstimateTypes
- */
-
 /**
  * @typedef {object} GasEstimates
  * @property {GasEstimateTypes} gasEstimateType - The type of estimate provided
@@ -35,26 +30,12 @@ import { useSafeGasEstimatePolling } from './useSafeGasEstimatePolling';
  * @returns {GasFeeEstimates} - GasFeeEstimates object
  */
 export function useGasFeeEstimates() {
-  const networkAndAccountSupports1559 = useSelector(
-    checkNetworkAndAccountSupports1559,
-  );
   const gasEstimateType = useSelector(getGasEstimateType);
   const gasFeeEstimates = useSelector(getGasFeeEstimates);
   const estimatedGasFeeTimeBounds = useSelector(getEstimatedGasFeeTimeBounds);
+  const isGasEstimatesLoading = useSelector(getIsGasEstimatesLoading);
   useSafeGasEstimatePolling();
 
-  // We consider the gas estimate to be loading if the gasEstimateType is
-  // 'NONE' or if the current gasEstimateType cannot be supported by the current
-  // network
-  const isEIP1559TolerableEstimateType =
-    gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET ||
-    gasEstimateType === GAS_ESTIMATE_TYPES.ETH_GASPRICE;
-  const isGasEstimatesLoading =
-    gasEstimateType === GAS_ESTIMATE_TYPES.NONE ||
-    (networkAndAccountSupports1559 && !isEIP1559TolerableEstimateType) ||
-    (!networkAndAccountSupports1559 &&
-      gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET);
-
   return {
     gasFeeEstimates,
     gasEstimateType,
diff --git a/ui/hooks/useGasFeeEstimates.test.js b/ui/hooks/useGasFeeEstimates.test.js
index 0af584e1c..574bb7904 100644
--- a/ui/hooks/useGasFeeEstimates.test.js
+++ b/ui/hooks/useGasFeeEstimates.test.js
@@ -5,12 +5,14 @@ import createRandomId from '../../shared/modules/random-id';
 import {
   getGasEstimateType,
   getGasFeeEstimates,
+  getIsGasEstimatesLoading,
 } from '../ducks/metamask/metamask';
 import { checkNetworkAndAccountSupports1559 } from '../selectors';
 import {
   disconnectGasFeeEstimatePoller,
   getGasFeeEstimatesAndStartPolling,
 } from '../store/actions';
+
 import { useGasFeeEstimates } from './useGasFeeEstimates';
 
 jest.mock('../store/actions', () => ({
@@ -37,6 +39,7 @@ const DEFAULT_OPTS = {
     medium: '20',
     high: '30',
   },
+  isGasEstimatesLoading: true,
 };
 
 const generateUseSelectorRouter = (opts = DEFAULT_OPTS) => (selector) => {
@@ -52,6 +55,9 @@ const generateUseSelectorRouter = (opts = DEFAULT_OPTS) => (selector) => {
   if (selector === getGasFeeEstimates) {
     return opts.gasFeeEstimates ?? DEFAULT_OPTS.gasFeeEstimates;
   }
+  if (selector === getIsGasEstimatesLoading) {
+    return opts.isGasEstimatesLoading ?? DEFAULT_OPTS.isGasEstimatesLoading;
+  }
   return undefined;
 };
 
@@ -68,15 +74,16 @@ describe('useGasFeeEstimates', () => {
     disconnectGasFeeEstimatePoller.mockImplementation((token) => {
       tokens = tokens.filter((tkn) => tkn !== token);
     });
-    useSelector.mockImplementation(generateUseSelectorRouter());
   });
 
   it('registers with the controller', () => {
+    useSelector.mockImplementation(generateUseSelectorRouter());
     renderHook(() => useGasFeeEstimates());
     expect(tokens).toHaveLength(1);
   });
 
   it('clears token with the controller on unmount', async () => {
+    useSelector.mockImplementation(generateUseSelectorRouter());
     renderHook(() => useGasFeeEstimates());
     expect(tokens).toHaveLength(1);
     const expectedToken = tokens[0];
@@ -87,6 +94,11 @@ describe('useGasFeeEstimates', () => {
   });
 
   it('works with LEGACY gas prices', () => {
+    useSelector.mockImplementation(
+      generateUseSelectorRouter({
+        isGasEstimatesLoading: false,
+      }),
+    );
     const {
       result: { current },
     } = renderHook(() => useGasFeeEstimates());
@@ -104,6 +116,7 @@ describe('useGasFeeEstimates', () => {
       generateUseSelectorRouter({
         gasEstimateType: GAS_ESTIMATE_TYPES.ETH_GASPRICE,
         gasFeeEstimates,
+        isGasEstimatesLoading: false,
       }),
     );
 
@@ -145,6 +158,7 @@ describe('useGasFeeEstimates', () => {
         checkNetworkAndAccountSupports1559: true,
         gasEstimateType: GAS_ESTIMATE_TYPES.FEE_MARKET,
         gasFeeEstimates,
+        isGasEstimatesLoading: false,
       }),
     );
 
diff --git a/ui/hooks/useShouldAnimateGasEstimations.js b/ui/hooks/useShouldAnimateGasEstimations.js
index df588c0ec..cfd150c30 100644
--- a/ui/hooks/useShouldAnimateGasEstimations.js
+++ b/ui/hooks/useShouldAnimateGasEstimations.js
@@ -1,10 +1,20 @@
-import { useRef } from 'react';
+import { useRef, useEffect } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
 import { isEqual } from 'lodash';
 
+import {
+  getGasLoadingAnimationIsShowing,
+  toggleGasLoadingAnimation,
+} from '../ducks/app/app';
 import { useGasFeeEstimates } from './useGasFeeEstimates';
 
 export function useShouldAnimateGasEstimations() {
   const { isGasEstimatesLoading, gasFeeEstimates } = useGasFeeEstimates();
+  const dispatch = useDispatch();
+
+  const isGasLoadingAnimationActive = useSelector(
+    getGasLoadingAnimationIsShowing,
+  );
 
   // Do the animation only when gas prices have changed...
   const lastGasEstimates = useRef(gasFeeEstimates);
@@ -24,5 +34,17 @@ export function useShouldAnimateGasEstimations() {
   const showLoadingAnimation =
     isGasEstimatesLoading || (gasEstimatesChanged && !gasJustLoaded);
 
-  return showLoadingAnimation;
+  useEffect(() => {
+    if (
+      isGasLoadingAnimationActive === false &&
+      showLoadingAnimation === true
+    ) {
+      dispatch(toggleGasLoadingAnimation(true));
+
+      setTimeout(() => {
+        console.log('Killing the toggleGasLoadingAnimation to false');
+        dispatch(toggleGasLoadingAnimation(false));
+      }, 2000);
+    }
+  }, [dispatch, isGasLoadingAnimationActive, showLoadingAnimation]);
 }
diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js
index 164573169..f1bb14ba5 100644
--- a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js
+++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js
@@ -107,6 +107,7 @@ export default class ConfirmTransactionBase extends Component {
     setDefaultHomeActiveTabName: PropTypes.func,
     primaryTotalTextOverride: PropTypes.string,
     secondaryTotalTextOverride: PropTypes.string,
+    gasIsLoading: PropTypes.bool,
   };
 
   state = {
@@ -772,6 +773,7 @@ export default class ConfirmTransactionBase extends Component {
       hideSenderToRecipient,
       showAccountInHeader,
       txData,
+      gasIsLoading,
     } = this.props;
     const {
       submitting,
@@ -838,7 +840,7 @@ export default class ConfirmTransactionBase extends Component {
         lastTx={lastTx}
         ofText={ofText}
         requestsWaitingText={requestsWaitingText}
-        disabled={!valid || submitting}
+        disabled={!valid || submitting || gasIsLoading}
         onEdit={() => this.handleEdit()}
         onCancelAll={() => this.handleCancelAll()}
         onCancel={() => this.handleCancel()}
diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js
index 90d349ad8..561ee28ec 100644
--- a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js
+++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js
@@ -32,7 +32,11 @@ import {
 import { getMostRecentOverviewPage } from '../../ducks/history/history';
 import { transactionMatchesNetwork } from '../../../shared/modules/transaction.utils';
 import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils';
-import { updateTransactionGasFees } from '../../ducks/metamask/metamask';
+import {
+  updateTransactionGasFees,
+  getIsGasEstimatesLoading,
+} from '../../ducks/metamask/metamask';
+import { getGasLoadingAnimationIsShowing } from '../../ducks/app/app';
 import ConfirmTransactionBase from './confirm-transaction-base.component';
 
 const casedContractMap = Object.keys(contractMap).reduce((acc, base) => {
@@ -60,6 +64,10 @@ const mapStateToProps = (state, ownProps) => {
   const { id: paramsTransactionId } = params;
   const isMainnet = getIsMainnet(state);
   const supportsEIP1599 = checkNetworkAndAccountSupports1559(state);
+
+  const isGasEstimatesLoading = getIsGasEstimatesLoading(state);
+  const gasLoadingAnimationIsShowing = getGasLoadingAnimationIsShowing(state);
+
   const { confirmTransaction, metamask } = state;
   const {
     ensResolutionsByAddress,
@@ -185,6 +193,7 @@ const mapStateToProps = (state, ownProps) => {
     isEthGasPrice,
     noGasPrice,
     supportsEIP1599,
+    gasIsLoading: isGasEstimatesLoading || gasLoadingAnimationIsShowing,
   };
 };
 
diff --git a/ui/pages/swaps/fee-card/fee-card.test.js b/ui/pages/swaps/fee-card/fee-card.test.js
index b6183fcca..9327ad69e 100644
--- a/ui/pages/swaps/fee-card/fee-card.test.js
+++ b/ui/pages/swaps/fee-card/fee-card.test.js
@@ -1,6 +1,14 @@
 import React from 'react';
 import configureMockStore from 'redux-mock-store';
 import thunk from 'redux-thunk';
+import { useSelector } from 'react-redux';
+
+import { checkNetworkAndAccountSupports1559 } from '../../../selectors';
+import {
+  getGasEstimateType,
+  getGasFeeEstimates,
+  getIsGasEstimatesLoading,
+} from '../../../ducks/metamask/metamask';
 
 import {
   renderWithProvider,
@@ -13,21 +21,34 @@ import FeeCard from '.';
 
 const middleware = [thunk];
 
-jest.mock('../../../hooks/useGasFeeEstimates', () => {
+jest.mock('react-redux', () => {
+  const actual = jest.requireActual('react-redux');
+
   return {
-    useGasFeeEstimates: () => {
-      return {
-        gasFeeEstimates: MOCKS.createGasFeeEstimatesForFeeMarket(),
-        gasEstimateType: 'fee-market',
-        estimatedGasFeeTimeBounds: undefined,
-        isGasEstimatesLoading: false,
-      };
-    },
+    ...actual,
+    useSelector: jest.fn(),
   };
 });
 
+const generateUseSelectorRouter = () => (selector) => {
+  if (selector === checkNetworkAndAccountSupports1559) {
+    return true;
+  }
+  if (selector === getGasEstimateType) {
+    return 'fee-market';
+  }
+  if (selector === getGasFeeEstimates) {
+    return MOCKS.createGasFeeEstimatesForFeeMarket();
+  }
+  if (selector === getIsGasEstimatesLoading) {
+    return false;
+  }
+  return undefined;
+};
+
 setBackgroundConnection({
   getGasFeeTimeEstimate: jest.fn(),
+  getGasFeeEstimatesAndStartPolling: jest.fn(),
 });
 
 const createProps = (customProps = {}) => {
@@ -65,6 +86,7 @@ const createProps = (customProps = {}) => {
 
 describe('FeeCard', () => {
   it('renders the component with initial props', () => {
+    useSelector.mockImplementation(generateUseSelectorRouter());
     const props = createProps();
     const { getByText } = renderWithProvider(<FeeCard {...props} />);
     expect(getByText('Using the best quote')).toBeInTheDocument();
diff --git a/ui/store/actionConstants.js b/ui/store/actionConstants.js
index 8046ea05d..d62e3f5b1 100644
--- a/ui/store/actionConstants.js
+++ b/ui/store/actionConstants.js
@@ -102,3 +102,5 @@ export const SET_OPEN_METAMASK_TAB_IDS = 'SET_OPEN_METAMASK_TAB_IDS';
 
 // Home Screen
 export const HIDE_WHATS_NEW_POPUP = 'HIDE_WHATS_NEW_POPUP';
+
+export const TOGGLE_GAS_LOADING_ANIMATION = 'TOGGLE_GAS_LOADING_ANIMATION';