on master help sign in
txns: EIP1559 fee data
4266690tomholford
src/components/L2/Dropdowns/FeeDropdown.tsx+20−7
@@ -8,13 +8,16 @@ import './FeeDropdown.scss';
8
8
9const PRICE_LABELS = ['Fast', 'Normal', 'Slow'];
9const PRICE_LABELS = ['Fast', 'Normal', 'Slow'];
10
10
11−export interface GasPrice {
11+export interface GasPriceData {
12 price: number;
12 price: number;
13 wait: string;
13 wait: string;
14+ maxFeePerGas: number;
15+ maxPriorityFeePerGas: number;
16+ suggestedBaseFeePerGas: number;
14}
17}
15
18
16export const formatWait = (wait: number) => Math.round(wait * 100) / 100;
19export const formatWait = (wait: number) => Math.round(wait * 100) / 100;
17−export const formatDisplay = ({ price, wait }: GasPrice) =>
20+export const formatDisplay = ({ price, wait }: GasPriceData) =>
18 `${price} gwei (${wait} min)`;
21 `${price} gwei (${wait} min)`;
19
22
20export default function FeeDropdown({
23export default function FeeDropdown({
@@ -22,12 +25,16 @@ export default function FeeDropdown({
22}: {
25}: {
23 setGasPrice: (g: number) => void;
26 setGasPrice: (g: number) => void;
24}) {
27}) {
28+ const { suggestedGasPrices }: { suggestedGasPrices: {
29+ fast: GasPriceData,
30+ average: GasPriceData,
31+ low: GasPriceData,
25− const { suggestedGasPrices } = useGasPrice(DEFAULT_GAS_PRICE_GWEI);
32+ }} = useGasPrice(DEFAULT_GAS_PRICE_GWEI);
26
33
27 const [open, setOpen] = useState(false);
34 const [open, setOpen] = useState(false);
28 const [useCustom, setUseCustom] = useState(false);
35 const [useCustom, setUseCustom] = useState(false);
29 const [custom, setCustom] = useState<string | undefined>();
36 const [custom, setCustom] = useState<string | undefined>();
30− const [selected, setSelected] = useState<GasPrice>(
37+ const [selected, setSelected] = useState<GasPriceData>(
31 suggestedGasPrices.average
38 suggestedGasPrices.average
32 );
39 );
33
40
@@ -51,7 +58,13 @@ export default function FeeDropdown({
51 customWait = `< ${fast.wait}`;
58 customWait = `< ${fast.wait}`;
52 }
59 }
53
60
61+ setSelected({
54− setSelected({ price: cleanedNum, wait: customWait });
62+ price: cleanedNum,
63+ wait: customWait,
64+ maxFeePerGas: cleanedNum,
65+ maxPriorityFeePerGas: cleanedNum,
66+ suggestedBaseFeePerGas: cleanedNum
67+ });
55 };
68 };
56
69
57 useEffect(() => {
70 useEffect(() => {
@@ -59,7 +72,7 @@ export default function FeeDropdown({
59 }, [suggestedGasPrices]);
72 }, [suggestedGasPrices]);
60
73
61 const selectPrice = useCallback(
74 const selectPrice = useCallback(
62− (value: GasPrice) => () => {
75+ (value: GasPriceData) => () => {
63 setSelected(value);
76 setSelected(value);
64 setGasPrice(value.price);
77 setGasPrice(value.price);
65 setOpen(false);
78 setOpen(false);
@@ -97,7 +110,7 @@ export default function FeeDropdown({
97 toggleOpen={() => setOpen(!open)}>
110 toggleOpen={() => setOpen(!open)}>
98 <Box className="prices">
111 <Box className="prices">
99 {Object.values(suggestedGasPrices).map(
112 {Object.values(suggestedGasPrices).map(
100− (value: GasPrice, ind: number) => (
113+ (value: GasPriceData, ind: number) => (
101 <Row
114 <Row
102 className="price"
115 className="price"
103 onClick={selectPrice(value)}
116 onClick={selectPrice(value)}
src/lib/getSuggestedGasPrice.js+36−20
@@ -31,44 +31,60 @@ export default async function getSuggestedGasPrice(networkType) {
31 case NETWORK_TYPES.LOCAL:
31 case NETWORK_TYPES.LOCAL:
32 default:
32 default:
33 try {
33 try {
34− const etherscanGas = await fetch(
34+ const [etherscanGas, ethgasstationGas] = await Promise.all([
35+ fetch(
35− 'https://api.etherscan.io/api' +
36+ 'https://api.etherscan.io/api' +
36− '?module=gastracker' +
37+ '?module=gastracker' +
37− '&action=gasoracle' +
38+ '&action=gasoracle' +
38− '&apikey=CG52E4R96W56GIKUI4IJ8CH9EZIXPUW1W8',
39+ '&apikey=CG52E4R96W56GIKUI4IJ8CH9EZIXPUW1W8',
40+ {
41+ method: 'GET',
42+ cache: 'no-cache',
43+ }
44+ ),
45+ fetch(
46+ 'https://ethgasstation.info/json/ethgasAPI.json',
39− {
47+ {
40− method: 'GET',
48+ method: 'GET',
41− cache: 'no-cache',
49+ cache: 'no-cache',
42− }
50+ }
51+ )
43− );
52+ ]);
44
53
45− const ethgasstationGas = await fetch(
54+ const [etherscanGasJson, ethgasstationGasJson] = await Promise.all([
46− 'https://ethgasstation.info/json/ethgasAPI.json',
55+ etherscanGas.json(),
47− {
56+ ethgasstationGas.json()
48− method: 'GET',
49− cache: 'no-cache',
50− }
51− );
57+ ])
52
58
53− const etherscanGasJson = await etherscanGas.json();
59+ const suggestedBaseFeePerGas = Number(etherscanGasJson.result.suggestBaseFee);
54−
55− const ethgasstationGasJson = await ethgasstationGas.json();
56
60
61+ // Calculations inspired by:
62+ // https://github.com/liquality/chainify/blob/6e8243e8daf4dc219dcfd7df144ead3ff6183b26/packages/evm/lib/fee/EIP1559FeeApiProvider/ethereum.ts#L5
57 return {
63 return {
58 fast: {
64 fast: {
59 price: minGas(etherscanGasJson.result.FastGasPrice),
65 price: minGas(etherscanGasJson.result.FastGasPrice),
60 wait: formatWait(ethgasstationGasJson.fastWait),
66 wait: formatWait(ethgasstationGasJson.fastWait),
67+ maxFeePerGas: minGas(etherscanGasJson.result.FastGasPrice),
68+ maxPriorityFeePerGas: (etherscanGasJson.result.FastGasPrice - suggestedBaseFeePerGas),
69+ suggestedBaseFeePerGas
61 },
70 },
62 average: {
71 average: {
63 price: minGas(etherscanGasJson.result.ProposeGasPrice),
72 price: minGas(etherscanGasJson.result.ProposeGasPrice),
64 wait: formatWait(ethgasstationGasJson.avgWait),
73 wait: formatWait(ethgasstationGasJson.avgWait),
74+ maxFeePerGas: minGas(etherscanGasJson.result.ProposeGasPrice),
75+ maxPriorityFeePerGas: (etherscanGasJson.result.ProposeGasPrice - suggestedBaseFeePerGas),
76+ suggestedBaseFeePerGas
65 },
77 },
66 low: {
78 low: {
67 price: minGas(etherscanGasJson.result.SafeGasPrice),
79 price: minGas(etherscanGasJson.result.SafeGasPrice),
68 wait: formatWait(ethgasstationGasJson.safeLowWait),
80 wait: formatWait(ethgasstationGasJson.safeLowWait),
81+ maxFeePerGas: minGas(etherscanGasJson.result.SafeGasPrice),
82+ maxPriorityFeePerGas: (etherscanGasJson.result.SafeGasPrice - suggestedBaseFeePerGas),
83+ suggestedBaseFeePerGas
69 },
84 },
70 };
85 };
71 } catch (e) {
86 } catch (e) {
87+ console.warn(e);
72 return defaultGasValues(DEFAULT_GAS_PRICE_GWEI);
88 return defaultGasValues(DEFAULT_GAS_PRICE_GWEI);
73 }
89 }
74 }
90 }
src/lib/useGasPrice.js+16−14
@@ -15,29 +15,31 @@ import { DEFAULT_GAS_PRICE_GWEI } from './constants';
15 * @param {Number} initialGasPrice the initial gas price available instantly
15 * @param {Number} initialGasPrice the initial gas price available instantly
16 */
16 */
17export default function useGasPrice(initialGasPrice = DEFAULT_GAS_PRICE_GWEI) {
17export default function useGasPrice(initialGasPrice = DEFAULT_GAS_PRICE_GWEI) {
18+ const [mounted, setMounted] = useState(false);
18 const { networkType } = useNetwork();
19 const { networkType } = useNetwork();
19 const [suggestedGasPrices, setSuggestedGasPrices] = useState(
20 const [suggestedGasPrices, setSuggestedGasPrices] = useState(
20 defaultGasValues(initialGasPrice)
21 defaultGasValues(initialGasPrice)
21 ); // fast, average, low. In gwei
22 ); // fast, average, low. In gwei
22 const [gasPrice, setGasPrice] = useState(initialGasPrice); // gwei
23 const [gasPrice, setGasPrice] = useState(initialGasPrice); // gwei
23
24
24− useEffect(() => {
25+ const fetchPrices = useCallback(async () => {
25− let mounted = true;
26+ if (!mounted) {
26−
27+ return;
27− (async () => {
28+ }
28− const suggestedGasPrices = await getSuggestedGasPrices(networkType);
29
29
30− if (!mounted) {
30+ const suggestedGasPrices = await getSuggestedGasPrices(networkType);
31− return;
31+ console.log(suggestedGasPrices);
32− }
33
32
34− // TODO: BN
33+ // TODO: BN
35− setSuggestedGasPrices(suggestedGasPrices);
34+ setSuggestedGasPrices(suggestedGasPrices);
36− setGasPrice(suggestedGasPrices.average.price);
35+ setGasPrice(suggestedGasPrices.average.price);
37− })();
36+ }, [mounted]);
38
37
39− return () => (mounted = true);
38+ useEffect(() => {
39+ setMounted(true);
40+ fetchPrices()
41+ return () => (setMounted(false));
40− }, [networkType]);
42+ }, [mounted, networkType]);
41
43
42 const resetGasPrice = useCallback(
44 const resetGasPrice = useCallback(
43 () => setGasPrice(suggestedGasPrices.average.price),
45 () => setGasPrice(suggestedGasPrices.average.price),
src/views/Points.tsx+7
@@ -67,6 +67,13 @@ export default function Points() {
67 const { wallet }: any = useWallet();
67 const { wallet }: any = useWallet();
68 const { pop, push, names }: any = useHistory();
68 const { pop, push, names }: any = useHistory();
69 const { setPointCursor }: any = usePointCursor();
69 const { setPointCursor }: any = usePointCursor();
70+ /**
71+ * TODO: there is a race condition here; sometimes the pointCache is not
72+ * loaded by the time this view renders, which then causes a crash when
73+ * attempting to destructure.
74+ *
75+ * Same is also true for isEclipticOwner.
76+ */
70 const { controlledPoints, getDetails }: any = usePointCache();
77 const { controlledPoints, getDetails }: any = usePointCache();
71 const { contracts }: any = useNetwork();
78 const { contracts }: any = useNetwork();
72 const isEclipticOwner = useIsEclipticOwner();
79 const isEclipticOwner = useIsEclipticOwner();