1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

add method to detect EIP 1559 support (#11369)

This commit is contained in:
Brad Decker 2021-06-25 11:24:00 -05:00 committed by GitHub
parent a1d7271ed7
commit 23a859826f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 168 additions and 1 deletions

View File

@ -30,6 +30,9 @@ describe('DetectTokensController', function () {
'0x7e57e2',
'0xbc86727e770de68b1060c91f6bb6945c73e10388',
]);
sandbox
.stub(network, 'getLatestBlock')
.callsFake(() => Promise.resolve({}));
sandbox
.stub(preferences, '_detectIsERC721')
.returns(Promise.resolve(false));

View File

@ -1,11 +1,13 @@
import { strict as assert } from 'assert';
import sinon from 'sinon';
import { getNetworkDisplayName } from './util';
import NetworkController from './network';
import NetworkController, { NETWORK_EVENTS } from './network';
describe('NetworkController', function () {
describe('controller', function () {
let networkController;
let getLatestBlockStub;
let setProviderTypeAndWait;
const noop = () => undefined;
const networkControllerProviderConfig = {
getAccounts: noop,
@ -13,7 +15,21 @@ describe('NetworkController', function () {
beforeEach(function () {
networkController = new NetworkController();
getLatestBlockStub = sinon
.stub(networkController, 'getLatestBlock')
.callsFake(() => Promise.resolve({}));
networkController.setInfuraProjectId('foo');
setProviderTypeAndWait = () =>
new Promise((resolve) => {
networkController.on(NETWORK_EVENTS.NETWORK_DID_CHANGE, () => {
resolve();
});
networkController.setProviderType('mainnet');
});
});
afterEach(function () {
getLatestBlockStub.reset();
});
describe('#provider', function () {
@ -67,6 +83,59 @@ describe('NetworkController', function () {
);
});
});
describe('#getEIP1559Compatibility', function () {
it('should return false when baseFeePerGas is not in the block header', async function () {
networkController.initializeProvider(networkControllerProviderConfig);
const supportsEIP1559 = await networkController.getEIP1559Compatibility();
assert.equal(supportsEIP1559, false);
});
it('should return true when baseFeePerGas is in block header', async function () {
networkController.initializeProvider(networkControllerProviderConfig);
getLatestBlockStub.callsFake(() =>
Promise.resolve({ baseFeePerGas: '0xa ' }),
);
const supportsEIP1559 = await networkController.getEIP1559Compatibility();
assert.equal(supportsEIP1559, true);
});
it('should store EIP1559 support in state to reduce calls to getLatestBlock', async function () {
networkController.initializeProvider(networkControllerProviderConfig);
getLatestBlockStub.callsFake(() =>
Promise.resolve({ baseFeePerGas: '0xa ' }),
);
await networkController.getEIP1559Compatibility();
const supportsEIP1559 = await networkController.getEIP1559Compatibility();
assert.equal(getLatestBlockStub.calledOnce, true);
assert.equal(supportsEIP1559, true);
});
it('should clear stored EIP1559 support when changing networks', async function () {
networkController.initializeProvider(networkControllerProviderConfig);
networkController.consoleThis = true;
getLatestBlockStub.callsFake(() =>
Promise.resolve({ baseFeePerGas: '0xa ' }),
);
await networkController.getEIP1559Compatibility();
assert.equal(
networkController.networkDetails.getState().EIPS[1559],
true,
);
getLatestBlockStub.callsFake(() => Promise.resolve({}));
await setProviderTypeAndWait('mainnet');
assert.equal(
networkController.networkDetails.getState().EIPS[1559],
undefined,
);
await networkController.getEIP1559Compatibility();
assert.equal(
networkController.networkDetails.getState().EIPS[1559],
false,
);
assert.equal(getLatestBlockStub.calledTwice, true);
});
});
});
describe('utils', function () {

View File

@ -51,6 +51,10 @@ const defaultProviderConfig = {
...defaultProviderConfigOpts,
};
const defaultNetworkDetailsState = {
EIPS: { 1559: undefined },
};
export const NETWORK_EVENTS = {
// Fired after the actively selected network is changed
NETWORK_DID_CHANGE: 'networkDidChange',
@ -74,10 +78,21 @@ export default class NetworkController extends EventEmitter {
this.providerStore.getState(),
);
this.networkStore = new ObservableStore('loading');
// We need to keep track of a few details about the current network
// Ideally we'd merge this.networkStore with this new store, but doing so
// will require a decent sized refactor of how we're accessing network
// state. Currently this is only used for detecting EIP 1559 support but
// can be extended to track other network details.
this.networkDetails = new ObservableStore(
opts.networkDetails || {
...defaultNetworkDetailsState,
},
);
this.store = new ComposedStore({
provider: this.providerStore,
previousProviderStore: this.previousProviderStore,
network: this.networkStore,
networkDetails: this.networkDetails,
});
// provider and block tracker
@ -120,6 +135,42 @@ export default class NetworkController extends EventEmitter {
return { provider, blockTracker };
}
/**
* Method to return the latest block for the current network
* @returns {Object} Block header
*/
getLatestBlock() {
return new Promise((resolve, reject) => {
const { provider } = this.getProviderAndBlockTracker();
const ethQuery = new EthQuery(provider);
ethQuery.sendAsync(
{ method: 'eth_getBlockByNumber', params: ['latest', false] },
(err, block) => {
if (err) {
return reject(err);
}
return resolve(block);
},
);
});
}
/**
* Method to check if the block header contains fields that indicate EIP 1559
* support (baseFeePerGas).
* @returns {Promise<boolean>} true if current network supports EIP 1559
*/
async getEIP1559Compatibility() {
const { EIPS } = this.networkDetails.getState();
if (EIPS[1559] !== undefined) {
return EIPS[1559];
}
const latestBlock = await this.getLatestBlock();
const supportsEIP1559 = latestBlock.baseFeePerGas !== undefined;
this.setNetworkEIPSupport(1559, supportsEIP1559);
return supportsEIP1559;
}
verifyNetwork() {
// Check network when restoring connectivity:
if (this.isNetworkLoading()) {
@ -135,6 +186,26 @@ export default class NetworkController extends EventEmitter {
this.networkStore.putState(network);
}
/**
* Set EIP support indication in the networkDetails store
* @param {number} EIPNumber - The number of the EIP to mark support for
* @param {boolean} isSupported - True if the EIP is supported
*/
setNetworkEIPSupport(EIPNumber, isSupported) {
this.networkDetails.updateState({
EIPS: {
[EIPNumber]: isSupported,
},
});
}
/**
* Reset EIP support to default (no support)
*/
clearNetworkDetails() {
this.networkDetails.putState({ ...defaultNetworkDetailsState });
}
isNetworkLoading() {
return this.getNetworkState() === 'loading';
}
@ -154,6 +225,8 @@ export default class NetworkController extends EventEmitter {
'NetworkController - lookupNetwork aborted due to missing chainId',
);
this.setNetworkState('loading');
// keep network details in sync with network state
this.clearNetworkDetails();
return;
}
@ -174,10 +247,14 @@ export default class NetworkController extends EventEmitter {
if (initialNetwork === currentNetwork) {
if (err) {
this.setNetworkState('loading');
// keep network details in sync with network state
this.clearNetworkDetails();
return;
}
this.setNetworkState(networkVersion);
// look up EIP-1559 support
this.getEIP1559Compatibility();
}
});
}
@ -298,9 +375,15 @@ export default class NetworkController extends EventEmitter {
}
_switchNetwork(opts) {
// Indicate to subscribers that network is about to change
this.emit(NETWORK_EVENTS.NETWORK_WILL_CHANGE);
// Set loading state
this.setNetworkState('loading');
// Reset network details
this.clearNetworkDetails();
// Configure the provider appropriately
this._configureProvider(opts);
// Notify subscribers that network has changed
this.emit(NETWORK_EVENTS.NETWORK_DID_CHANGE, opts.type);
}

View File

@ -30,6 +30,9 @@ describe('preferences controller', function () {
network.initializeProvider(networkControllerProviderConfig);
provider = network.getProviderAndBlockTracker().provider;
sandbox
.stub(network, 'getLatestBlock')
.callsFake(() => Promise.resolve({}));
sandbox.stub(network, 'getCurrentChainId').callsFake(() => currentChainId);
sandbox
.stub(network, 'getProviderConfig')

View File

@ -21,6 +21,11 @@ const firstTimeState = {
rpcUrl: 'http://localhost:8545',
chainId: '0x539',
},
networkDetails: {
EIPS: {
1559: false,
},
},
},
};

View File

@ -238,3 +238,7 @@ export function getSendToAccounts(state) {
export function getUnapprovedTxs(state) {
return state.metamask.unapprovedTxs;
}
export function isEIP1559Network(state) {
return state.metamask.networkDetails.EIPS[1559] === true;
}