Skip to content
This repository was archived by the owner on Oct 11, 2024. It is now read-only.

Commit 1c10e93

Browse files
authored
Merge pull request #416 from 0xProject/kim/fix/eip1559-gas-estimation
feat: EIP1559 style gas price estimation
2 parents a836942 + 6a17184 commit 1c10e93

File tree

12 files changed

+303
-239
lines changed

12 files changed

+303
-239
lines changed

package.json

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
"eslint": "eslint 'ts/**/*.{ts,tsx}'",
1818
"lint": "tslint --format stylish --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
1919
"fix": "yarn lint --fix",
20-
"pre_push": "yarn lint:prettier && yarn lint && yarn test",
20+
"pre_push": "yarn typecheck && yarn lint:prettier && yarn lint && yarn test",
2121
"update:tools": "aws s3 sync --delete s3://docs-markdown/ mdx/tools/ --profile $(npm config get awscli_profile)",
22-
"dev": "npm run update:tools && node --max-old-space-size=16384 ./node_modules/webpack-dev-server/bin/webpack-dev-server.js --mode development --content-base public --https",
22+
"dev": "npm run update:tools && node --max-old-space-size=16384 ./node_modules/webpack-dev-server/bin/webpack-dev-server.js --mode development --content-base public",
2323
"deploy_dogfood": "npm run update:tools && yarn index_docs --environment dogfood && npm run build:prod && aws s3 sync ./public/. s3://dogfood.0xproject.com --profile $(npm config get awscli_profile) --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers && ./cdn-cache-clear.sh dogfood",
2424
"deploy_staging": "npm run update:tools && yarn index_docs --environment staging && npm run build:prod && aws s3 sync ./public/. s3://staging-0xproject --profile $(npm config get awscli_profile) --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
2525
"deploy_live": "npm run update:tools && yarn index_docs --environment production && DEPLOY_ROLLBAR_SOURCEMAPS=true npm run build:prod && aws s3 sync ./public/. s3://0x.org --profile $(npm config get awscli_profile) --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --exclude *.map.js && ./cdn-cache-clear.sh live",
@@ -36,13 +36,13 @@
3636
"dependencies": {
3737
"@0x/asset-buyer": "6.2.0-beta.3",
3838
"@0x/contract-addresses": "^4.1.0",
39-
"@0x/contract-wrappers": "^13.2.0",
39+
"@0x/contract-wrappers": "^13.18.0",
4040
"@0x/contracts-dev-utils": "^1.0.2",
41-
"@0x/contracts-treasury": "^1.0.2",
42-
"@0x/json-schemas": "^5.0.2",
41+
"@0x/contracts-treasury": "^1.4.2",
42+
"@0x/json-schemas": "^6.4.0",
4343
"@0x/order-utils": "^10.0.1",
44-
"@0x/subproviders": "^6.0.2",
45-
"@0x/utils": "^5.1.1",
44+
"@0x/subproviders": "^6.6.1",
45+
"@0x/utils": "^6.4.4",
4646
"@0x/web3-wrapper": "^7.0.2",
4747
"@reach/dialog": "^0.11.2",
4848
"@reach/tabs": "^0.1.6",
@@ -70,7 +70,7 @@
7070
"deep-equal": "^1.0.1",
7171
"dotenv": "^10.0.0",
7272
"dotenv-webpack": "^7.0.3",
73-
"ethereum-types": "^3.0.0",
73+
"ethereum-types": "^3.6.0",
7474
"ethereumjs-util": "^5.1.1",
7575
"ethers": "^5.0.24",
7676
"find-versions": "^2.0.0",
@@ -125,7 +125,7 @@
125125
"sass-loader": "^7.1.0",
126126
"semver": "5.5.0",
127127
"semver-sort": "0.0.4",
128-
"styled-components": "^5.0.0",
128+
"styled-components": "^5.3.1",
129129
"thenby": "^1.2.3",
130130
"truffle-contract": "2.0.1",
131131
"urql": "^2.0.4",
@@ -169,7 +169,7 @@
169169
"@types/react-syntax-highlighter": "^10.2.1",
170170
"@types/react-transition-group": "^4.2.0",
171171
"@types/redux": "^3.6.0",
172-
"@types/styled-components": "4.1.1",
172+
"@types/styled-components": "^5.1.15",
173173
"@types/valid-url": "^1.0.2",
174174
"@types/web3-provider-engine": "^14.0.0",
175175
"@types/yargs": "^11.0.0",
@@ -206,7 +206,7 @@
206206
"ts-node": "^8.3.0",
207207
"tslint": "5.11.0",
208208
"tslint-config-0xproject": "^0.0.2",
209-
"typescript": "^3.7.4",
209+
"typescript": "^3.8.3",
210210
"unist-util-find-after": "^2.0.4",
211211
"unist-util-modify-children": "^1.1.4",
212212
"unist-util-select": "^2.0.2",

ts/blockchain.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ export class Blockchain {
622622
const provider = this._contractWrappers.getProvider();
623623
const web3Wrapper = new Web3Wrapper(provider);
624624
const exchangeAbi = this._contractWrappers.exchange.abi;
625-
web3Wrapper.abiDecoder.addABI(exchangeAbi);
625+
web3Wrapper.abiDecoder.addABI(exchangeAbi as any);
626626
const receipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
627627
return receipt;
628628
}
@@ -935,9 +935,9 @@ export class Blockchain {
935935
}
936936
private async _updateDefaultGasPriceAsync(): Promise<void> {
937937
try {
938-
const localStorageSpeed = localStorage.getItem('gas-speed');
939-
const { gasPriceInWei } = await backendClient.getGasInfoAsync(localStorageSpeed || 'standard');
940-
this._defaultGasPrice = gasPriceInWei;
938+
const { price } = await backendClient.getGasInfoAsync('standard');
939+
// HACK: this is not supporting EIP1559 but this file is legacy and not used anywhere
940+
this._defaultGasPrice = new BigNumber(price);
941941
} catch (err) {
942942
return;
943943
}

ts/hooks/use_allowance.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ export const useAllowance = (): UseAllowanceHookResult => {
4040
setIsStarted(true);
4141
const ownerAddress = (providerState.account as AccountReady).address;
4242

43-
// const localStorageSpeed = localStorage.getItem('gas-speed');
44-
const gasInfo = await backendClient.getGasInfoAsync('instant');
43+
const localStorageSpeed = localStorage.getItem('gas-speed');
44+
const gasInfo = await backendClient.getGasInfoAsync(localStorageSpeed);
4545

4646
const contractAddresses = getContractAddressesForChainOrThrow(networkId);
4747
const erc20ProxyAddress = contractAddresses.erc20Proxy;
@@ -56,7 +56,8 @@ export const useAllowance = (): UseAllowanceHookResult => {
5656
.approve(erc20ProxyAddress, constants.UNLIMITED_ALLOWANCE_IN_BASE_UNITS)
5757
.awaitTransactionSuccessAsync({
5858
from: ownerAddress,
59-
gasPrice: gasInfo.gasPriceInWei,
59+
maxFeePerGas: gasInfo.maxFeePerGas,
60+
maxPriorityFeePerGas: gasInfo.maxPriorityFeePerGas,
6061
});
6162

6263
await txPromise.txHashPromise;

ts/hooks/use_stake.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,13 @@ export const useStake = (networkId: ChainId, providerState: ProviderState): UseS
118118
async (data: string[]) => {
119119
setLoadingState(TransactionLoadingState.WaitingForSignature);
120120

121-
// const localStorageSpeed = localStorage.getItem('gas-speed');
122-
const gasInfo = await backendClient.getGasInfoAsync('instant');
123-
const txPromise = stakingProxyContract
124-
.batchExecute(data)
125-
.awaitTransactionSuccessAsync({ from: ownerAddress, gasPrice: gasInfo.gasPriceInWei });
121+
const localStorageSpeed = localStorage.getItem('gas-speed');
122+
const gasInfo = await backendClient.getGasInfoAsync(localStorageSpeed);
123+
const txPromise = stakingProxyContract.batchExecute(data).awaitTransactionSuccessAsync({
124+
from: ownerAddress,
125+
maxFeePerGas: gasInfo.maxFeePerGas,
126+
maxPriorityFeePerGas: gasInfo.maxPriorityFeePerGas,
127+
});
126128

127129
await txPromise.txHashPromise;
128130
setEstimatedTimeMs(gasInfo.estimatedTimeMs);
@@ -249,11 +251,14 @@ export const useStake = (networkId: ChainId, providerState: ProviderState): UseS
249251

250252
setLoadingState(TransactionLoadingState.WaitingForSignature);
251253

252-
const gasInfo = await backendClient.getGasInfoAsync('instant');
254+
const localStorageSpeed = localStorage.getItem('gas-speed');
255+
const gasInfo = await backendClient.getGasInfoAsync(localStorageSpeed);
253256

254-
const txPromise = stakingContract
255-
.unstake(zrxAmountBaseUnits)
256-
.awaitTransactionSuccessAsync({ from: ownerAddress, gasPrice: gasInfo.gasPriceInWei });
257+
const txPromise = stakingContract.unstake(zrxAmountBaseUnits).awaitTransactionSuccessAsync({
258+
from: ownerAddress,
259+
maxFeePerGas: gasInfo.maxFeePerGas,
260+
maxPriorityFeePerGas: gasInfo.maxPriorityFeePerGas,
261+
});
257262

258263
await txPromise.txHashPromise;
259264
setEstimatedTimeMs(gasInfo.estimatedTimeMs);

ts/pages/governance/vote_form.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,16 +274,20 @@ class VoteFormComponent extends React.Component<Props> {
274274

275275
const { votePreference } = this.state;
276276

277-
// const localStorageSpeed = localStorage.getItem('gas-speed');
278-
const gasInfo = await backendClient.getGasInfoAsync('instant');
277+
const localStorageSpeed = localStorage.getItem('gas-speed');
278+
const gasInfo = await backendClient.getGasInfoAsync(localStorageSpeed);
279279

280280
const txPromise = contract
281281
.castVote(
282282
proposalIdBigNumber,
283283
votePreference === VoteValue.Yes,
284284
operatedPools ? operatedPools.map((pool) => encodePoolId(parseInt(pool.poolId, 10))) : [],
285285
)
286-
.awaitTransactionSuccessAsync({ from: selectedAddress, gasPrice: gasInfo.gasPriceInWei });
286+
.awaitTransactionSuccessAsync({
287+
from: selectedAddress,
288+
maxFeePerGas: gasInfo.maxFeePerGas,
289+
maxPriorityFeePerGas: gasInfo.maxPriorityFeePerGas,
290+
});
287291
const txHash = await txPromise.txHashPromise;
288292
if (onVoted) {
289293
this.setState({

ts/pages/mesh/mesh_stats.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const fetchOrders = async () => fetchUtils.requestAsync(ordersBaseUrl, ordersPat
2828
export const MeshStats: React.FC = () => {
2929
const [meshFetchedSnapshot, setMeshSnapshot] = useState<{ meshNodes: MeshNodeMetaData[] }>();
3030
const [meshData, setMeshData] = useState<{ numActiveNodes: number; numEdges: number }>();
31-
const [orders, setOrders] = useState();
31+
const [orders, setOrders] = useState<{ total: number }>();
3232

3333
const [nodeDetails, setNodeDetails] = useState<{ data?: MeshNodeMetaData; isVisible: boolean }>({
3434
data: undefined,

ts/style/theme.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,7 @@ export interface IThemeInterface {
2727
}
2828

2929
// tslint:disable:no-unnecessary-type-assertion
30-
const {
31-
default: styled,
32-
css,
33-
createGlobalStyle,
34-
keyframes,
35-
ThemeProvider,
36-
} = styledComponents as styledComponents.ThemedStyledComponentsModule<IThemeInterface>;
30+
const { default: styled, css, createGlobalStyle, keyframes, ThemeProvider } = styledComponents;
3731
// tslint:enable:no-unnecessary-type-assertion
3832

3933
export { styled, css, createGlobalStyle, keyframes, ThemeProvider };

ts/types.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -817,11 +817,17 @@ export interface WebsiteBackendTokenInfo {
817817
symbol: string;
818818
}
819819

820-
export interface GasInfo {
821-
gasPriceInWei: BigNumber;
822-
estimatedTimeMs: number;
820+
export interface EIP1559GasInfo {
821+
price: number;
822+
maxPriorityFeePerGas: number;
823+
maxFeePerGas: number;
824+
baseFeePerGas: number;
823825
}
824826

827+
export type GasInfo = EIP1559GasInfo & {
828+
estimatedTimeMs: number;
829+
};
830+
825831
export interface WebsiteBackendGasWaitTimeInfo {
826832
fastestWait: number;
827833
fastWait: number;

ts/utils/backend_client.ts

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { BigNumber } from '@0x/utils';
21
import * as _ from 'lodash';
32

43
import { Web3Wrapper } from '@0x/web3-wrapper';
54
import { ZeroExProvider } from 'ethereum-types';
65

76
import {
7+
EIP1559GasInfo,
88
GasInfo,
99
MailchimpSubscriberInfo,
1010
WebsiteBackendCFLMetricsData,
@@ -17,7 +17,6 @@ import {
1717
WebsiteBackendTokenInfo,
1818
WebsiteBackendTradingPairs,
1919
} from 'ts/types';
20-
import { constants } from 'ts/utils/constants';
2120
import { fetchUtils } from 'ts/utils/fetch_utils';
2221
import { utils } from 'ts/utils/utils';
2322

@@ -41,11 +40,18 @@ export interface GasInfoSelection {
4140
fast: number;
4241
}
4342

44-
const speedToSelectionMap: { [key: string]: string } = {
45-
standard: 'average',
46-
fast: 'fast',
47-
instant: 'fastest',
48-
};
43+
interface GasApiSingleSourceResponse {
44+
result: {
45+
source: string;
46+
timestamp: number;
47+
instant: EIP1559GasInfo;
48+
fast: EIP1559GasInfo;
49+
standard: EIP1559GasInfo;
50+
low: EIP1559GasInfo;
51+
};
52+
}
53+
54+
type GasSpeedSelectors = 'instant' | 'fast' | 'standard' | 'low';
4955

5056
const speedToWaitTimeMap: { [key: string]: string } = {
5157
standard: 'avgWait',
@@ -200,28 +206,26 @@ export const backendClient = {
200206
},
201207

202208
async getGasInfoAsync(speed?: string): Promise<GasInfo> {
203-
// Median gas prices across 0x api gas oracles
204-
// Defaulting to average/standard gas. Using eth gas station for time estimates
205-
const gasApiPath = 'source/gas_now?output=eth_gas_station';
206-
const gasInfoReq = fetchUtils.requestAsync(ZEROEX_GAS_API, gasApiPath);
209+
const gasApiPath = 'v2/source/block_native';
210+
const gasInfoReq: Promise<GasApiSingleSourceResponse> = fetchUtils.requestAsync(ZEROEX_GAS_API, gasApiPath);
207211
const speedInput = speed || 'standard';
208212

209-
const gasSpeed = speedToSelectionMap[speedInput];
210-
const waitTime = speedToWaitTimeMap[speedInput];
211213
const gasWaitTimesReq = fetchUtils.requestAsync(utils.getBackendBaseUrl(), ETH_GAS_STATION_ENDPOINT);
212214

213-
const res: [WebsiteBackendGasInfo, WebsiteBackendGasWaitTimeInfo] = await Promise.all([
215+
const [gasInfo, gasWaitTimes]: [GasApiSingleSourceResponse, WebsiteBackendGasWaitTimeInfo] = await Promise.all([
214216
gasInfoReq,
215217
gasWaitTimesReq,
216218
]);
217-
const gasInfo = res[0];
218-
const gasWaitTimes = res[1];
219-
// Eth Gas Station result is gwei * 10
220-
const gasPriceInGwei = new BigNumber((gasInfo as any)[gasSpeed] / 10);
221219
// Time is in minutes
220+
const waitTime = speedToWaitTimeMap[speedInput];
222221
const estimatedTimeMs = (gasWaitTimes as any)[waitTime] * 60 * 1000; // Minutes to MS
223222

224-
return { gasPriceInWei: gasPriceInGwei.multipliedBy(constants.GWEI_IN_WEI), estimatedTimeMs };
223+
// Try to use user selected value, fall back to standard if no match
224+
const gasPriceInfo = gasInfo.result[speedInput as GasSpeedSelectors]
225+
? gasInfo.result[speedInput as GasSpeedSelectors]
226+
: gasInfo.result.standard;
227+
228+
return { ...gasPriceInfo, estimatedTimeMs };
225229
},
226230

227231
async getGasInfoSelectionAsync(): Promise<GasInfoSelection> {

ts/utils/order_utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export const orderHashUtils = {
4848
// format, we only assert that we were indeed passed a string.
4949
assert.isString('orderHash', orderHash);
5050
const schemaValidator = new SchemaValidator();
51-
const isValid = schemaValidator.validate(orderHash, schemas.orderHashSchema).valid;
51+
const isValid = schemaValidator.isValid(orderHash, schemas.orderHashSchema);
5252
return isValid;
5353
},
5454

0 commit comments

Comments
 (0)