Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GasFeeController #494

Merged
merged 46 commits into from
Jul 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
a71c93e
First draft of gas fee controller
danjm Jun 14, 2021
c4a2606
Second draft of gas fee controller
danjm Jun 16, 2021
7886180
Third draft of gas fee controller
danjm Jun 17, 2021
2be94cb
Delete use of legacy gas fee
danjm Jun 18, 2021
ba8e275
Track whether polling should be instantiated or stopped with tokens
danjm Jun 18, 2021
179dee6
Network controller getEIP1559Compatibility can be called whenever a n…
danjm Jun 18, 2021
55d3607
update tests (#495)
rickycodes Jun 18, 2021
16075b0
Fetch estimate using eth_gasPrice if on a custom network
danjm Jun 21, 2021
b70d323
getGasFeeEstimatesAndStartPolling returns poll token, and a new one i…
danjm Jun 21, 2021
0a8a248
Add getTimeEstimate to GasFee controller
danjm Jun 21, 2021
cb88478
export GasFeeController
rickycodes Jun 21, 2021
1ccd62a
Add public method for calling and returning gas estimates without pol…
danjm Jun 23, 2021
dbf9f6c
Fix return of fetchLegacyGasPriceEstimate
danjm Jun 23, 2021
16b313b
Proper error handling and fallback for _fetchGasFeeEstimateData
danjm Jun 23, 2021
a782c9d
Include estimated time bounds in gas fee state
danjm Jun 23, 2021
32b2930
rename
rickycodes Jun 23, 2021
97e9e8f
Add GasFeeController.test.ts
rickycodes Jun 23, 2021
47f3659
remove TODO
rickycodes Jun 24, 2021
9971e68
Add result token length test
rickycodes Jun 24, 2021
91a2cd2
Add estimates property test
rickycodes Jun 24, 2021
0dec6e7
Add should fail to re-initialize test
rickycodes Jun 24, 2021
e4e962e
remove console.log
rickycodes Jun 24, 2021
afdc385
do not modify state directly
rickycodes Jun 24, 2021
fd4bd64
Use before/afterEach and fix messenger
rickycodes Jun 24, 2021
b1c5631
check gasFeeEstimates properties
rickycodes Jun 24, 2021
3646d62
check that state is empty to start
rickycodes Jun 24, 2021
51dad0d
Add one additional property check
rickycodes Jun 24, 2021
4ac4ffe
Adding TokenListController to fetch the token list from token service…
NiranjanaBinoy Jun 28, 2021
c1ca513
address feedback
rickycodes Jun 30, 2021
0458679
add mock server for eip1559
rickycodes Jun 15, 2021
728c039
get tests working again
rickycodes Jun 30, 2021
cd90799
Use heroku endpoint
rickycodes Jun 30, 2021
8d570bb
Handle fetch correctly in gasfeecontroller unit tests, using nock
danjm Jun 30, 2021
2e2b1a7
gasFee controller calculateTimeEstimate handles decimals, by way of u…
danjm Jun 30, 2021
1516d87
Lint fix
danjm Jun 30, 2021
6eac11c
Fix dec to gwi (#504)
brad-decker Jul 1, 2021
3df6baf
use ethjs-unit for unit conversions (#506)
brad-decker Jul 1, 2021
117d898
Add metaswaps API and normalize all gas fee units to dec gwei (#507)
brad-decker Jul 1, 2021
b4eebac
update types to be more identifiable (#508)
brad-decker Jul 2, 2021
6fbf024
use LegacyGasFeeEstimate type
brad-decker Jul 2, 2021
5d2908e
handle hex prefixed
brad-decker Jul 5, 2021
283fc88
baseFee -> baseFeePerGas
brad-decker Jul 5, 2021
cf82e70
make more configurable (#513)
brad-decker Jul 6, 2021
8d04cc5
use optional chaining
brad-decker Jul 6, 2021
41cdace
update test case wording
brad-decker Jul 7, 2021
3a42d98
use testdata instead of programmatic testing
brad-decker Jul 7, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"eth-sig-util": "^3.0.0",
"ethereumjs-util": "^7.0.10",
"ethereumjs-wallet": "^1.0.1",
"ethjs-unit": "^0.1.6",
"ethjs-util": "^0.1.6",
"human-standard-collectible-abi": "^1.0.2",
"human-standard-token-abi": "^2.0.0",
Expand Down
2 changes: 2 additions & 0 deletions src/ComposableController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ describe('ComposableController', () => {
},
NetworkController: {
network: 'loading',
properties: { isEIP1559Compatible: false },
provider: { type: 'mainnet', chainId: NetworksChainId.mainnet },
},
PreferencesController: {
Expand Down Expand Up @@ -188,6 +189,7 @@ describe('ComposableController', () => {
ipfsGateway: 'https://ipfs.io/ipfs/',
lostIdentities: {},
network: 'loading',
properties: { isEIP1559Compatible: false },
provider: { type: 'mainnet', chainId: NetworksChainId.mainnet },
selectedAddress: '',
suggestedAssets: [],
Expand Down
2 changes: 2 additions & 0 deletions src/dependencies.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ declare module 'ethjs-provider-http';

declare module 'ethjs-util';

declare module 'ethjs-unit';

declare module 'human-standard-collectible-abi';

declare module 'human-standard-token-abi';
Expand Down
185 changes: 185 additions & 0 deletions src/gas/GasFeeController.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import { stub } from 'sinon';
import nock from 'nock';
import { ControllerMessenger } from '../ControllerMessenger';
import {
GasFeeController,
GetGasFeeState,
GasFeeStateChange,
LegacyGasPriceEstimate,
} from './GasFeeController';

const TEST_GAS_FEE_API = 'https://mock-gas-server.herokuapp.com/<chain_id>';
const TEST_LEGACY_FEE_API = 'https://test/<chain_id>';

const name = 'GasFeeController';

function getRestrictedMessenger() {
const controllerMessenger = new ControllerMessenger<
GetGasFeeState,
GasFeeStateChange
>();
const messenger = controllerMessenger.getRestricted<
typeof name,
never,
never
>({
name,
});
return messenger;
}

describe('GasFeeController', () => {
let gasFeeController: GasFeeController;
let getCurrentNetworkLegacyGasAPICompatibility: jest.Mock<boolean>;
let getIsEIP1559Compatible: jest.Mock<Promise<boolean>>;
let getChainId: jest.Mock<`0x${string}` | `${number}` | number>;

beforeAll(() => {
nock.disableNetConnect();
});

afterAll(() => {
nock.enableNetConnect();
});

beforeEach(() => {
getChainId = jest.fn().mockImplementation(() => '0x1');
getCurrentNetworkLegacyGasAPICompatibility = jest
.fn()
.mockImplementation(() => false);
getIsEIP1559Compatible = jest
.fn()
.mockImplementation(() => Promise.resolve(true));
nock(TEST_GAS_FEE_API.replace('<chain_id>', '1'))
.get(/.+/u)
.reply(200, {
low: {
minWaitTimeEstimate: 60000,
maxWaitTimeEstimate: 600000,
suggestedMaxPriorityFeePerGas: '1',
suggestedMaxFeePerGas: '35',
},
medium: {
minWaitTimeEstimate: 15000,
maxWaitTimeEstimate: 60000,
suggestedMaxPriorityFeePerGas: '1.8',
suggestedMaxFeePerGas: '38',
},
high: {
minWaitTimeEstimate: 0,
maxWaitTimeEstimate: 15000,
suggestedMaxPriorityFeePerGas: '2',
suggestedMaxFeePerGas: '50',
},
estimatedBaseFee: '28',
})
.persist();

nock(TEST_LEGACY_FEE_API.replace('<chain_id>', '0x1'))
.get(/.+/u)
.reply(200, {
SafeGasPrice: '22',
ProposeGasPrice: '25',
FastGasPrice: '30',
})
.persist();

gasFeeController = new GasFeeController({
interval: 10000,
messenger: getRestrictedMessenger(),
getProvider: () => stub(),
getChainId,
legacyAPIEndpoint: TEST_LEGACY_FEE_API,
EIP1559APIEndpoint: TEST_GAS_FEE_API,
onNetworkStateChange: () => stub(),
getCurrentNetworkLegacyGasAPICompatibility,
getCurrentNetworkEIP1559Compatibility: getIsEIP1559Compatible, // change this for networkController.state.properties.isEIP1559Compatible ???
});
});

afterEach(() => {
nock.cleanAll();
gasFeeController.destroy();
});

it('should initialize', async () => {
expect(gasFeeController.name).toBe(name);
});

it('should getGasFeeEstimatesAndStartPolling', async () => {
expect(gasFeeController.state.gasFeeEstimates).toStrictEqual({});
const result = await gasFeeController.getGasFeeEstimatesAndStartPolling(
undefined,
);
expect(result).toHaveLength(36);
expect(gasFeeController.state.gasFeeEstimates).toHaveProperty('low');
expect(gasFeeController.state.gasFeeEstimates).toHaveProperty('medium');
expect(gasFeeController.state.gasFeeEstimates).toHaveProperty('high');
expect(gasFeeController.state.gasFeeEstimates).toHaveProperty(
'estimatedBaseFee',
);
});

describe('when on any network supporting legacy gas estimation api', () => {
it('should _fetchGasFeeEstimateData', async () => {
getCurrentNetworkLegacyGasAPICompatibility.mockImplementation(() => true);
getIsEIP1559Compatible.mockImplementation(() => Promise.resolve(false));
expect(gasFeeController.state.gasFeeEstimates).toStrictEqual({});
const estimates = await gasFeeController._fetchGasFeeEstimateData();
expect(estimates).toHaveProperty('gasFeeEstimates');
expect(
(gasFeeController.state.gasFeeEstimates as LegacyGasPriceEstimate).high,
).toBe('30');
});
});

describe('getChainId', () => {
it('should work with a number input', async () => {
getChainId.mockImplementation(() => 1);
getCurrentNetworkLegacyGasAPICompatibility.mockImplementation(() => true);
getIsEIP1559Compatible.mockImplementation(() => Promise.resolve(false));
expect(gasFeeController.state.gasFeeEstimates).toStrictEqual({});
const estimates = await gasFeeController._fetchGasFeeEstimateData();
expect(estimates).toHaveProperty('gasFeeEstimates');
expect(
(gasFeeController.state.gasFeeEstimates as LegacyGasPriceEstimate).high,
).toBe('30');
});

it('should work with a hexstring input', async () => {
getChainId.mockImplementation(() => '0x1');
getCurrentNetworkLegacyGasAPICompatibility.mockImplementation(() => true);
getIsEIP1559Compatible.mockImplementation(() => Promise.resolve(false));
expect(gasFeeController.state.gasFeeEstimates).toStrictEqual({});
const estimates = await gasFeeController._fetchGasFeeEstimateData();
expect(estimates).toHaveProperty('gasFeeEstimates');
expect(
(gasFeeController.state.gasFeeEstimates as LegacyGasPriceEstimate).high,
).toBe('30');
});

it('should work with a numeric string input', async () => {
getChainId.mockImplementation(() => '1');
getCurrentNetworkLegacyGasAPICompatibility.mockImplementation(() => true);
getIsEIP1559Compatible.mockImplementation(() => Promise.resolve(false));
expect(gasFeeController.state.gasFeeEstimates).toStrictEqual({});
const estimates = await gasFeeController._fetchGasFeeEstimateData();
expect(estimates).toHaveProperty('gasFeeEstimates');
expect(
(gasFeeController.state.gasFeeEstimates as LegacyGasPriceEstimate).high,
).toBe('30');
});
});

describe('when on any network supporting EIP-1559', () => {
it('should _fetchGasFeeEstimateData', async () => {
getCurrentNetworkLegacyGasAPICompatibility.mockImplementation(() => true);
expect(gasFeeController.state.gasFeeEstimates).toStrictEqual({});
const estimates = await gasFeeController._fetchGasFeeEstimateData();
expect(estimates).toHaveProperty('gasFeeEstimates');
expect(gasFeeController.state.gasFeeEstimates).toHaveProperty(
'estimatedBaseFee',
);
});
});
});
Loading