on b40e5c6 help sign in
package.json+1−1
since splitsnapshots
unifiedsplit
@@ -1,6 +1,6 @@
1{
1{
2 "name": "bridge",
2 "name": "bridge",
3− "version": "3.3.1",
3+ "version": "3.3.0",
4 "description": "An application for interacting with Azimuth",
4 "description": "An application for interacting with Azimuth",
5 "repository": {
5 "repository": {
6 "type": "git",
6 "type": "git",
src/Bridge.tsx+5−12
@@ -20,9 +20,6 @@ import light from '@tlon/indigo-light';
20
20
21import WithErrorBoundary from 'components/WithErrorBoundary';
21import WithErrorBoundary from 'components/WithErrorBoundary';
22import GlobalErrorBoundary from 'components/GlobalErrorBoundary';
22import GlobalErrorBoundary from 'components/GlobalErrorBoundary';
23−import { useBrowser } from 'lib/useBrowser';
24−import { BrowserWarning } from 'components/BrowserWarning';
25−
26import Modal from 'components/L2/Modal';
23import Modal from 'components/L2/Modal';
27import { useRollerStore } from 'store/rollerStore';
24import { useRollerStore } from 'store/rollerStore';
28import { Box } from '@tlon/indigo-react';
25import { Box } from '@tlon/indigo-react';
@@ -32,8 +29,8 @@ import { useRollerPoller } from 'lib/useRollerPoller';
32const INITIAL_NETWORK_TYPE = isGoerli
29const INITIAL_NETWORK_TYPE = isGoerli
33 ? NETWORK_TYPES.GOERLI
30 ? NETWORK_TYPES.GOERLI
34 : isDevelopment && !isMainnet
31 : isDevelopment && !isMainnet
35− ? NETWORK_TYPES.LOCAL
32+ ? NETWORK_TYPES.LOCAL
36− : NETWORK_TYPES.MAINNET;
33+ : NETWORK_TYPES.MAINNET;
37
34
38// NB(shrugs): modify these variables to change the default local state.
35// NB(shrugs): modify these variables to change the default local state.
39const SHOULD_STUB_LOCAL = import.meta.env.VITE_STUB_LOCAL === 'true';
36const SHOULD_STUB_LOCAL = import.meta.env.VITE_STUB_LOCAL === 'true';
@@ -41,9 +38,9 @@ const IS_STUBBED = isDevelopment && SHOULD_STUB_LOCAL;
41
38
42const INITIAL_WALLET = IS_STUBBED
39const INITIAL_WALLET = IS_STUBBED
43 ? walletFromMnemonic(
40 ? walletFromMnemonic(
44− import.meta.env.VITE_DEV_MNEMONIC as string,
41+ import.meta.env.VITE_DEV_MNEMONIC as string,
45− import.meta.env.VITE_HD_PATH as string
42+ import.meta.env.VITE_HD_PATH as string
46− )
43+ )
47 : undefined;
44 : undefined;
48const INITIAL_MNEMONIC = IS_STUBBED
45const INITIAL_MNEMONIC = IS_STUBBED
49 ? Just(import.meta.env.VITE_DEV_MNEMONIC)
46 ? Just(import.meta.env.VITE_DEV_MNEMONIC)
@@ -85,9 +82,6 @@ function Bridge() {
85 const initialRoutes = useInitialRoutes();
82 const initialRoutes = useInitialRoutes();
86 const { loading, modalText, setModalText } = useRollerStore();
83 const { loading, modalText, setModalText } = useRollerStore();
87
84
88− const browser = useBrowser();
89− const showBrowserWarning = browser && !browser.isChromium;
90−
91 // full reload if the user changes their selected network in Metamask
85 // full reload if the user changes their selected network in Metamask
92 //
86 //
93 useEffect(() => {
87 useEffect(() => {
@@ -109,7 +103,6 @@ function Bridge() {
109 initialWallet={INITIAL_WALLET}
103 initialWallet={INITIAL_WALLET}
110 initialMnemonic={INITIAL_MNEMONIC}
104 initialMnemonic={INITIAL_MNEMONIC}
111 initialPointCursor={INITIAL_POINT_CURSOR}>
105 initialPointCursor={INITIAL_POINT_CURSOR}>
112− <BrowserWarning show={!!showBrowserWarning} />
113 <IndigoApp>
106 <IndigoApp>
114 <ThemeProvider theme={light}>
107 <ThemeProvider theme={light}>
115 <Router />
108 <Router />
src/components/BrowserWarning.tsxdeleted−27
@@ -1,27 +0,0 @@
1−import React from 'react';
2−import { Box } from '@tlon/indigo-react';
3−import styled from 'styled-components';
4−
5−const WarningBox = styled(Box)`
6− background: #fff4e5;
7− color: #663c00;
8− border: 1px solid #ffb74d;
9− padding: 0.75rem 1rem;
10− text-align: center;
11− font-weight: 600;
12− margin-bottom: 1rem;
13−`;
14−
15−interface Props {
16− show: boolean;
17−}
18−export const BrowserWarning: React.FC<Props> = ({ show }) => {
19− if (!show) return null;
20− return (
21− <WarningBox role="alert">
22− For the best experience we recommend using a Chromium‑based browser
23− (Chrome, Brave, etc.).
24− </WarningBox>
25− );
26−};
27−
src/components/InlineEthereumTransaction.jsx+7−4
@@ -13,7 +13,7 @@ import { toBN } from 'web3-utils';
13
13
14import { useExploreTxUrls } from 'lib/explorer';
14import { useExploreTxUrls } from 'lib/explorer';
15import { hexify } from 'lib/txn';
15import { hexify } from 'lib/txn';
16−import { safeFromWei, gweiToWei } from 'lib/lib';
16+import { safeFromWei, safeToWei } from 'lib/lib';
17
17
18import { composeValidator, buildCheckboxValidator } from 'form/validators';
18import { composeValidator, buildCheckboxValidator } from 'form/validators';
19import BridgeForm from 'form/BridgeForm';
19import BridgeForm from 'form/BridgeForm';
@@ -107,9 +107,12 @@ export default function InlineEthereumTransaction({
107 const maxCost = useMemo(
107 const maxCost = useMemo(
108 () =>
108 () =>
109 safeFromWei(
109 safeFromWei(
110+ safeToWei(
110− toBN(gasLimit)
111+ toBN(gasLimit)
111− .mul(gweiToWei(gasPrice.price))
112+ .mul(toBN(gasPrice.price))
112− .mul(toBN(numTxs)),
113+ .mul(toBN(numTxs)),
114+ 'gwei'
115+ ),
113 'ether'
116 'ether'
114 ),
117 ),
115 [gasLimit, gasPrice, numTxs]
118 [gasLimit, gasPrice, numTxs]
src/components/L2/Dropdowns/FeeDropdown.tsx+1−4
@@ -43,10 +43,7 @@ export default function FeeDropdown({
43 );
43 );
44
44
45 const handleCustom = (e: React.ChangeEvent<HTMLInputElement>) => {
45 const handleCustom = (e: React.ChangeEvent<HTMLInputElement>) => {
46− // Allow digits and a single decimal point
47− const cleanedValue = e.target.value
46+ const cleanedValue = e.target.value.replace(/[^0-9]/g, '');
48− .replace(/[^0-9.]/g, '')
49− .replace(/(\..*)\./g, '$1');
50 const cleanedNum = Number(cleanedValue);
47 const cleanedNum = Number(cleanedValue);
51 setCustom(cleanedValue);
48 setCustom(cleanedValue);
52 setGasPrice(defaultGasValues(cleanedNum).average);
49 setGasPrice(defaultGasValues(cleanedNum).average);
src/components/L2/Headers/L2PointHeader.tsx+3
@@ -92,6 +92,9 @@ const L2PointHeader = ({
92 <Row>
92 <Row>
93 <Row className="info">
93 <Row className="info">
94 {renderInviteButton()}
94 {renderInviteButton()}
95+ <Box className="history" onClick={goToHistory}>
96+ History
97+ </Box>
95 {points && <InviteConverter points={points} />}
98 {points && <InviteConverter points={points} />}
96 </Row>
99 </Row>
97 </Row>
100 </Row>
src/lib/authToken.ts+3−4
@@ -1,7 +1,7 @@
1import { crypto } from 'bitcoinjs-lib';
1import { crypto } from 'bitcoinjs-lib';
2import { ecdsaSign } from 'secp256k1';
2import { ecdsaSign } from 'secp256k1';
3import Web3 from 'web3';
3import Web3 from 'web3';
4−import { hexToBytes, utf8ToHex } from 'web3-utils';
4+import { hexToBytes } from 'web3-utils';
5import { hashPersonalMessage } from '@ethereumjs/util';
5import { hashPersonalMessage } from '@ethereumjs/util';
6import { WALLET_TYPES } from './constants';
6import { WALLET_TYPES } from './constants';
7import BridgeWallet from './types/BridgeWallet';
7import BridgeWallet from './types/BridgeWallet';
@@ -76,11 +76,10 @@ const getMetamaskAuthToken = ({ address, web3 }: MetamaskAuthTokenArgs) => {
76 // but web3.eth.personal.sign hits it semi-reliably?
76 // but web3.eth.personal.sign hits it semi-reliably?
77 // no idea what's going on, we should figure it out,
77 // no idea what's going on, we should figure it out,
78 // but we apply this bandaid to hopefully stop the bleeding.
78 // but we apply this bandaid to hopefully stop the bleeding.
79− //NOTE personal_sign expects hex-encoded data; signing the hex of
80− // MESSAGE yields the same signature as the other wallet types
81 return window.ethereum.request({
79 return window.ethereum.request({
82 method: 'personal_sign',
80 method: 'personal_sign',
83− params: [utf8ToHex(MESSAGE), address],
81+ params: [MESSAGE, address],
82+ from: address,
84 });
83 });
85 } else {
84 } else {
86 return web3.eth.personal.sign(MESSAGE, address, '');
85 return web3.eth.personal.sign(MESSAGE, address, '');
src/lib/getSuggestedGasPrice.js+71−61
@@ -5,14 +5,13 @@ import Web3 from 'web3';
5// ethgasstation returns values in floating point, one order of magitude
5// ethgasstation returns values in floating point, one order of magitude
6// more than gwei. see: https://docs.ethgasstation.info
6// more than gwei. see: https://docs.ethgasstation.info
7// we don't want to charge users more than the gas tank funds
7// we don't want to charge users more than the gas tank funds
8−const minGas = gas => Math.min(gas, MAX_GAS_PRICE_GWEI);
8+const minGas = gas => Math.min(Math.ceil(gas), MAX_GAS_PRICE_GWEI);
9
9
10−const feeToWei = fee => Web3.utils.toHex(Web3.utils.toWei(String(fee), 'gwei'));
10+const feeToInt = f => (f < 1 ? 1 : Math.round(f));
11
11
12−// Gwei with milligwei precision, rounded up so we never underpay
12+const feeToWei = fee => Web3.utils.toHex(Web3.utils.toWei(String(fee), 'gwei'));
13−const roundGwei = gwei => Math.ceil(gwei * 1000) / 1000;
14
13
15−const weiToGwei = wei => roundGwei(wei / 1_000_000_000);
14+const weiToGwei = wei => Math.ceil(wei / 1_000_000_000);
16
15
17const calculateMaxFee = (baseFee, maxPriorityFee) =>
16const calculateMaxFee = (baseFee, maxPriorityFee) =>
18 feeToWei(Math.round(2 * baseFee + maxPriorityFee));
17 feeToWei(Math.round(2 * baseFee + maxPriorityFee));
@@ -25,75 +24,82 @@ export const defaultGasValues = value => ({
25 price: value,
24 price: value,
26 wait: '1',
25 wait: '1',
27 maxFeePerGas: value,
26 maxFeePerGas: value,
28− maxPriorityFeePerGas: Math.min(1, value),
27+ maxPriorityFeePerGas: 1,
29 suggestedBaseFeePerGas: value > 2 ? value - 1 : 1,
28 suggestedBaseFeePerGas: value > 2 ? value - 1 : 1,
30 },
29 },
31 average: {
30 average: {
32 price: value,
31 price: value,
33 wait: '1',
32 wait: '1',
34 maxFeePerGas: value,
33 maxFeePerGas: value,
35− maxPriorityFeePerGas: Math.min(1, value),
34+ maxPriorityFeePerGas: 1,
36 suggestedBaseFeePerGas: value > 2 ? value - 1 : 1,
35 suggestedBaseFeePerGas: value > 2 ? value - 1 : 1,
37 },
36 },
38 low: {
37 low: {
39 price: value,
38 price: value,
40 wait: '1',
39 wait: '1',
41 maxFeePerGas: value,
40 maxFeePerGas: value,
42− maxPriorityFeePerGas: Math.min(1, value),
41+ maxPriorityFeePerGas: 1,
43 suggestedBaseFeePerGas: value > 2 ? value - 1 : 1,
42 suggestedBaseFeePerGas: value > 2 ? value - 1 : 1,
44 },
43 },
45});
44});
46
45
47−const median = values => {
48− const sorted = [...values].sort((a, b) => a - b);
49− const mid = Math.floor(sorted.length / 2);
50− return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
51−};
52−
53−// Number of recent blocks to sample, and the priority fee percentiles
54−// used for the low, average and fast tiers respectively
55−const FEE_HISTORY_BLOCKS = 20;
56−const REWARD_PERCENTILES = [10, 50, 90];
57−// Floor for the priority fee, since zero tip transactions may never be mined
58−const MIN_PRIORITY_FEE_GWEI = 0.001;
59−
60−const tierFor = (baseFeeGwei, priorityFeeWei, wait) => {
61− const maxPriorityFeePerGas = Math.max(
62− weiToGwei(priorityFeeWei),
63− MIN_PRIORITY_FEE_GWEI
64− );
65− const maxFeePerGas = roundGwei(baseFeeGwei + maxPriorityFeePerGas);
66− return {
67− price: minGas(maxFeePerGas),
68− wait: formatWait(wait),
69− maxFeePerGas,
70− maxPriorityFeePerGas,
71− suggestedBaseFeePerGas: baseFeeGwei,
72− };
73−};
74−
75−// Estimates fees from the connected node via eth_feeHistory, in the same
76−// manner as wallets do. See: https://docs.alchemy.com/docs/how-to-build-a-gas-fee-estimator-using-eip-1559
77−const getGasForNetwork = async web3 => {
46+const getGasForNetwork = async providerUrl => {
78 try {
47 try {
79− const history = await web3.eth.getFeeHistory(
48+ const [feeResponse, baseFeeResponse] = await Promise.all([
80− FEE_HISTORY_BLOCKS,
49+ fetch(
81− 'latest',
50+ 'https://beaconcha.in/api/v1/execution/gasnow',
82− REWARD_PERCENTILES
51+ {
52+ method: 'get',
53+ cache: 'no-cache',
54+ }
83− );
55+ ),
84−
56+ fetch(
85− // baseFeePerGas includes one extra entry: the base fee of the next block
57+ `${providerUrl}/v2/api` +
86− const nextBaseFeeWei = Number(history.baseFeePerGas.at(-1));
58+ '?module=gastracker' +
87− const baseFeeGwei = nextBaseFeeWei / 1_000_000_000;
59+ '&action=gasoracle' +
88−
60+ '&apikey=CG52E4R96W56GIKUI4IJ8CH9EZIXPUW1W8' +
89− const [low, average, fast] = REWARD_PERCENTILES.map((_, i) =>
61+ '&chainid=1',
90− median(history.reward.map(rewards => Number(rewards[i])))
62+ {
91− );
63+ method: 'GET',
92−
64+ cache: 'no-cache',
65+ }
66+ ),
67+ ]);
68+
69+ const [feeJson, baseFeeJson] = await Promise.all([
70+ feeResponse.json(),
71+ baseFeeResponse.json(),
72+ ]);
73+
74+ const suggestedBaseFeePerGas = Number(baseFeeJson.result.suggestBaseFee);
75+
76+ // Calculations derived from:
77+ // https://www.blocknative.com/blog/eip-1559-fees
93 return {
78 return {
94− fast: tierFor(baseFeeGwei, fast, 15),
79+ fast: {
95− average: tierFor(baseFeeGwei, average, 60),
80+ price: minGas(weiToGwei(feeJson.data.rapid)),
96− low: tierFor(baseFeeGwei, low, 180),
81+ wait: formatWait(15),
82+ maxFeePerGas: weiToGwei(feeJson.data.rapid),
83+ maxPriorityFeePerGas: feeToInt(
84+ weiToGwei(feeJson.data.rapid) - suggestedBaseFeePerGas
85+ )
86+ },
87+ average: {
88+ price: minGas(weiToGwei(feeJson.data.fast)),
89+ wait: formatWait(60),
90+ maxFeePerGas: weiToGwei(feeJson.data.fast),
91+ maxPriorityFeePerGas: feeToInt(
92+ weiToGwei(feeJson.data.fast) - suggestedBaseFeePerGas
93+ )
94+ },
95+ low: {
96+ price: minGas(weiToGwei(feeJson.data.slow)),
97+ wait: formatWait(180),
98+ maxFeePerGas: weiToGwei(feeJson.data.slow),
99+ maxPriorityFeePerGas: feeToInt(
100+ weiToGwei(feeJson.data.slow) - suggestedBaseFeePerGas
101+ )
102+ },
97 };
103 };
98 } catch (e) {
104 } catch (e) {
99 console.warn(e);
105 console.warn(e);
@@ -101,10 +107,14 @@ const getGasForNetwork = async web3 => {
101 }
107 }
102};
108};
103
109
104−export default async function getSuggestedGasPrice(networkType, web3) {
110+export default async function getSuggestedGasPrice(networkType) {
111+ switch (networkType) {
112+ case NETWORK_TYPES.GOERLI:
113+ return getGasForNetwork('https://api-goerli.etherscan.io');
105− if (networkType === NETWORK_TYPES.OFFLINE || !web3) {
114+ case NETWORK_TYPES.OFFLINE:
106− return defaultGasValues(DEFAULT_GAS_PRICE_GWEI);
115+ return defaultGasValues(DEFAULT_GAS_PRICE_GWEI);
116+ case NETWORK_TYPES.LOCAL:
117+ default:
118+ return getGasForNetwork('https://api.etherscan.io');
107 }
119 }
108−
109− return getGasForNetwork(web3);
110}
120}
src/lib/lib.js−4
@@ -26,9 +26,6 @@ const safeToWei = (num, source) => {
26 }
26 }
27};
27};
28
28
29−// Converts a (possibly fractional) gwei amount to a wei BN
30−const gweiToWei = gwei => toBN(toWei(Number(gwei).toFixed(9), 'gwei'));
31−
32const compose = (...fs) =>
29const compose = (...fs) =>
33 fs.reduceRight(
30 fs.reduceRight(
34 (pF, nF) => (...args) => nF(pF(...args)),
31 (pF, nF) => (...args) => nF(pF(...args)),
@@ -76,7 +73,6 @@ const patpStringLength = byteLength =>
76export {
73export {
77 safeFromWei,
74 safeFromWei,
78 safeToWei,
75 safeToWei,
79− gweiToWei,
80 compose,
76 compose,
81 allFalse,
77 allFalse,
82 isLast,
78 isLast,
src/lib/reticket.js+4−3
@@ -16,7 +16,7 @@ import {
16import getSuggestedGasPrice from './getSuggestedGasPrice';
16import getSuggestedGasPrice from './getSuggestedGasPrice';
17import { GAS_LIMITS, INITIAL_NETWORK_KEY_REVISION } from './constants';
17import { GAS_LIMITS, INITIAL_NETWORK_KEY_REVISION } from './constants';
18import { toBN } from 'web3-utils';
18import { toBN } from 'web3-utils';
19−import { gweiToWei } from './lib';
19+import { safeToWei } from './lib';
20import { isGalaxy, isPlanet } from './utils/point';
20import { isGalaxy, isPlanet } from './utils/point';
21
21
22export const TRANSACTION_PROGRESS = {
22export const TRANSACTION_PROGRESS = {
@@ -146,9 +146,10 @@ export async function reticketPointBetweenWallets({
146
146
147 progress(TRANSACTION_PROGRESS.SIGNING);
147 progress(TRANSACTION_PROGRESS.SIGNING);
148
148
149− const gasPriceData = (await getSuggestedGasPrice(networkType, web3)).average;
149+ const gasPriceData = (await getSuggestedGasPrice(networkType)).average;
150+ const gasPriceGwei = gasPriceData.price.toFixed();
150 const chainId = await web3.eth.net.getId();
151 const chainId = await web3.eth.net.getId();
151− const gasPriceWeiBN = gweiToWei(gasPriceData.price);
152+ const gasPriceWeiBN = toBN(safeToWei(gasPriceGwei, 'gwei'));
152 let inviteNonce = await web3.eth.getTransactionCount(fromWallet.address);
153 let inviteNonce = await web3.eth.getTransactionCount(fromWallet.address);
153 const totalCost = txs.reduce(
154 const totalCost = txs.reduce(
154 (acc, tx) => acc.add(gasPriceWeiBN.mul(toBN(tx.gas))),
155 (acc, tx) => acc.add(gasPriceWeiBN.mul(toBN(tx.gas))),
src/lib/txn.ts+1−1
@@ -99,7 +99,7 @@ const signTransaction = async ({
99
99
100 // from user dropdown
100 // from user dropdown
101 const maxPriorityFeePerGas = toWei(
101 const maxPriorityFeePerGas = toWei(
102− Number(gasPriceData.maxPriorityFeePerGas).toFixed(9),
102+ String(Math.round(gasPriceData.maxPriorityFeePerGas)),
103 'gwei'
103 'gwei'
104 );
104 );
105
105
src/lib/useBrowser.tsdeleted−32
@@ -1,32 +0,0 @@
1−import { useEffect, useState } from 'react';
2−
3−export function useBrowser() {
4− const [browser, setBrowser] = useState<{
5− name: 'chrome' | 'brave' | 'safari' | 'firefox' | 'edge' | 'other';
6− isChromium: boolean;
7− } | null>(null);
8−
9− useEffect(() => {
10− const ua = navigator.userAgent;
11− const vendor = navigator.vendor ?? '';
12−
13− const isChromium = !!(window as any).chrome;
14− const isBrave = !!(navigator as any).brave;
15− const isSafari = /Safari/.test(ua) && !/Chrome/.test(ua);
16− const isFirefox = /Firefox/.test(ua);
17− const isEdge = /Edg/.test(ua);
18− const isChrome = isChromium && !isBrave && !isEdge && /Chrome/.test(ua);
19−
20− let name: typeof browser['name'] = 'other';
21− if (isBrave) name = 'brave';
22− else if (isChrome) name = 'chrome';
23− else if (isSafari) name = 'safari';
24− else if (isFirefox) name = 'firefox';
25− else if (isEdge) name = 'edge';
26−
27− setBrowser({ name, isChromium });
28− }, []);
29−
30− return browser;
31−}
32−
src/lib/useEthereumTransaction.js+13−9
@@ -23,7 +23,7 @@ import { ensureFundsFor } from 'lib/tank';
23import useDeepEqualReference from 'lib/useDeepEqualReference';
23import useDeepEqualReference from 'lib/useDeepEqualReference';
24import useGasPrice from 'lib/useGasPrice';
24import useGasPrice from 'lib/useGasPrice';
25import { timeout } from 'lib/timeout';
25import { timeout } from 'lib/timeout';
26−import { safeFromWei, gweiToWei } from 'lib/lib';
26+import { safeToWei, safeFromWei } from 'lib/lib';
27import { useWalletConnect } from './useWalletConnect';
27import { useWalletConnect } from './useWalletConnect';
28import { Transaction } from '@ethereumjs/tx';
28import { Transaction } from '@ethereumjs/tx';
29
29
@@ -181,9 +181,10 @@ export default function useEthereumTransaction(
181
181
182 const rawTxs = signedTransactions.map(stx => hexify(stx.serialize()));
182 const rawTxs = signedTransactions.map(stx => hexify(stx.serialize()));
183
183
184− const cost = toBN(gasLimit)
184+ const costGwei = toBN(gasLimit)
185− .mul(gweiToWei(gasPrice.price))
185+ .mul(toBN(gasPrice.price))
186 .mul(toBN(rawTxs.length));
186 .mul(toBN(rawTxs.length));
187+ const cost = safeToWei(costGwei, 'gwei');
187 let usedTank = false;
188 let usedTank = false;
188 // if this ethereum transaction is being executed by a specific point
189 // if this ethereum transaction is being executed by a specific point
189 // see if we can use the tank
190 // see if we can use the tank
@@ -225,12 +226,15 @@ export default function useEthereumTransaction(
225
226
226 setFinalCost(
227 setFinalCost(
227 safeFromWei(
228 safeFromWei(
229+ safeToWei(
228− receipts.reduce(
230+ receipts.reduce(
229− (acc, receipt) =>
231+ (acc, receipt) =>
230− toBN(receipt.gasUsed)
232+ toBN(receipt.gasUsed)
231− .mul(gweiToWei(gasPrice.price))
233+ .mul(toBN(gasPrice.price))
232− .add(acc),
234+ .add(acc),
233− toBN(0)
235+ toBN(0)
236+ ),
237+ 'gwei'
234 ),
238 ),
235 'ether'
239 'ether'
236 )
240 )
src/lib/useGasPrice.js+4−7
@@ -16,7 +16,7 @@ import { DEFAULT_GAS_PRICE_GWEI } from './constants';
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 [mounted, setMounted] = useState(false);
19− const { networkType, web3 } = useNetwork();
19+ const { networkType } = useNetwork();
20 const [suggestedGasPrices, setSuggestedGasPrices] = useState(
20 const [suggestedGasPrices, setSuggestedGasPrices] = useState(
21 defaultGasValues(initialGasPrice)
21 defaultGasValues(initialGasPrice)
22 ); // fast, average, low. In gwei
22 ); // fast, average, low. In gwei
@@ -29,22 +29,19 @@ export default function useGasPrice(initialGasPrice = DEFAULT_GAS_PRICE_GWEI) {
29 return;
29 return;
30 }
30 }
31
31
32− const suggestedGasPrices = await getSuggestedGasPrices(
32+ const suggestedGasPrices = await getSuggestedGasPrices(networkType);
33− networkType,
34− web3.getOrElse(null)
35− );
36 console.log(suggestedGasPrices);
33 console.log(suggestedGasPrices);
37
34
38 // TODO: BN
35 // TODO: BN
39 setSuggestedGasPrices(suggestedGasPrices);
36 setSuggestedGasPrices(suggestedGasPrices);
40 setGasPrice(suggestedGasPrices.average);
37 setGasPrice(suggestedGasPrices.average);
41− }, [mounted, networkType, web3]);
38+ }, [mounted, networkType]);
42
39
43 useEffect(() => {
40 useEffect(() => {
44 setMounted(true);
41 setMounted(true);
45 fetchPrices();
42 fetchPrices();
46 return () => setMounted(false);
43 return () => setMounted(false);
47− }, [mounted, networkType, web3, fetchPrices]);
44+ }, [mounted, networkType, fetchPrices]);
48
45
49 const resetGasPrice = useCallback(
46 const resetGasPrice = useCallback(
50 () => setGasPrice(suggestedGasPrices.average),
47 () => setGasPrice(suggestedGasPrices.average),
src/views/Activate/ActivateView.scss−31
@@ -1,34 +1,3 @@
1.activate-view {
1.activate-view {
2 min-height: 440px;
2 min-height: 440px;
3}
3}
4−
5−.activation-qualifier {
6− /* Container appearance */
7− margin-top: 1rem;
8− // color: #000000; /* default text colour */
9− padding: 1rem; /* some inner space */
10− border-radius: 5px;
11− background: rgba(0, 0, 0, 0.02);
12− font-family: 'Inter';
13− background: #fff4e5;
14− color: #663c00;
15− border: 1px solid #ffb74d;
16−}
17−
18−/* Each note inside the container */
19−.activation-qualifier .activation-note {
20− margin-bottom: 1rem; /* space between notes */
21−}
22−
23−/* Remove the bottom margin from the last note */
24−.activation-qualifier .activation-note:last-child {
25− margin-bottom: 0;
26−}
27−
28−/* Link styling – only for links that have the .linkout class */
29−.activation-qualifier a.linkout {
30− color: #663c00;
31− text-decoration: underline;
32− font-weight: 600;
33−}
34−
src/views/Activate/ActivateView.tsx−16
@@ -60,22 +60,6 @@ export default function ActivateView({
60 </Box>
60 </Box>
61 </BodyPane>
61 </BodyPane>
62 </Window>
62 </Window>
63− <div className="activation-qualifier">
64− <div className="activation-note"> Planet activation codes will give you a self-custody <a className="linkout" href="https://docs.urbit.org/user-manual/id/layer-2-for-planets">Layer 2 Urbit 'planet'↗</a> and a Master Ticket wallet.
65− </div>
66− <div className="activation-note">
67− This is a legacy feature not actively maintained in Bridge, if you run into issues we recommend you either: <br></br>
68− <ol>
69− <li>
70− <a className="linkout" href="https://join.tlon.io/0v3.r87kb.fjpft.3k7b5.pbsr5.5em17">Claim a free Layer 2 planet from Tlon↗</a>
71− </li>
72− <br></br>
73− <li>
74− <a className="linkout" href="https://docs.urbit.org/user-manual/id/get-id#l1-planet-markets">Buy a Layer 1 identity on Ethereum↗</a>
75− </li>
76− </ol>
77− </div>
78− </div>
79 </Grid.Item>
63 </Grid.Item>
80 </Grid>
64 </Grid>
81 );
65 );
src/views/UrbitOS/NetworkKeys.tsx+6−16
@@ -279,8 +279,8 @@ export default function UrbitOSNetworkKeys({
279 const viewTitle = completed
279 const viewTitle = completed
280 ? 'Network Keys have been set'
280 ? 'Network Keys have been set'
281 : hasKeys
281 : hasKeys
282− ? 'Set Network Keys'
282+ ? 'Set Network Keys'
283− : 'Initiate Network Keys';
283+ : 'Initiate Network Keys';
284
284
285 const bootMessage = () => (
285 const bootMessage = () => (
286 <Text as="p" textAlign={'center'}>
286 <Text as="p" textAlign={'center'}>
@@ -311,19 +311,9 @@ export default function UrbitOSNetworkKeys({
311
311
312 const waitMessage = () => (
312 const waitMessage = () => (
313 <Text as="p" textAlign={'center'}>
313 <Text as="p" textAlign={'center'}>
314− <strong>Important:</strong> It may take minutes to hours for the
314+ <strong>Important:</strong> it may take minutes to hours for the
315− keys to become usable as they propogate across the network.
316− Please be patient, trying to use the new keys
315+ keys to become usable. Please be patient, trying to use the new keys
317− during this period may result in an{' '}
316+ during this period may result in an invalid keys error.
318− <
319− Text as="code"
320− mono
321− bg={'washedGray'}
322− padding={1}
323− borderRadius={1}
324− textAlign={'center'}>
325− invalid keys</Text>
326− {' '}error.
327 </Text>
317 </Text>
328 );
318 );
329
319
@@ -449,4 +439,4 @@ export default function UrbitOSNetworkKeys({
449 </BodyPane>
439 </BodyPane>
450 </Window>
440 </Window>
451 );
441 );
452−}
442+}