Fix swaps when initial network not Mainnet (#9745)

This is a continuation of #9726, which did not fix the problem
described.

If the initial network when the extension is started is something other
than Mainnet, the swaps controller will never successfully retrieve
swap quotes. This is because `ethers` will continue to communicate
with whichever network the provider was initially on.

We tried fixing this by hard-coding the `chainId` to Mainnet's
`chainId` when constructing the Ethers provider, but this did not work.
I suspect this failed because the `provider` we pass to `ethers` is not
compliant with EIP 1193, as `ethers` doubtless expects it to be.

Instead the entire `ethers` provider is now reconstructed each time the
network changes. This mirrors the approach we take in some other
controllers.
feature/default_network_editable
Mark Stacey 4 years ago committed by GitHub
parent 336282d7d5
commit 1294955d81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      app/scripts/controllers/swaps.js
  2. 1
      app/scripts/metamask-controller.js
  3. 87
      test/unit/app/controllers/swaps-test.js

@ -18,7 +18,6 @@ import {
fetchTradesInfo as defaultFetchTradesInfo,
fetchSwapsFeatureLiveness as defaultFetchSwapsFeatureLiveness,
} from '../../../ui/app/pages/swaps/swaps.util'
import { MAINNET_CHAIN_ID } from './network/enums'
const METASWAP_ADDRESS = '0x881d40237659c251811cec9c364ef91dc08d300c'
@ -71,6 +70,7 @@ const initialState = {
export default class SwapsController {
constructor ({
getBufferedGasLimit,
networkController,
provider,
getProviderConfig,
tokenRatesStore,
@ -92,8 +92,14 @@ export default class SwapsController {
this.indexOfNewestCallInFlight = 0
// The chain ID is hard-coded as Mainnet because swaps is only used on Mainnet
this.ethersProvider = new ethers.providers.Web3Provider(provider, parseInt(MAINNET_CHAIN_ID, 16))
this.ethersProvider = new ethers.providers.Web3Provider(provider)
this._currentNetwork = networkController.store.getState().network
networkController.on('networkDidChange', (network) => {
if (network !== 'loading' && network !== this._currentNetwork) {
this._currentNetwork = network
this.ethersProvider = new ethers.providers.Web3Provider(provider)
}
})
this._setupSwapsLivenessFetching()
}

@ -311,6 +311,7 @@ export default class MetamaskController extends EventEmitter {
this.swapsController = new SwapsController({
getBufferedGasLimit: this.txController.txGasUtil.getBufferedGasLimit.bind(this.txController.txGasUtil),
networkController: this.networkController,
provider: this.provider,
getProviderConfig: this.networkController.getProviderConfig.bind(this.networkController),
tokenRatesStore: this.tokenRatesController.store,

@ -4,6 +4,7 @@ import sinon from 'sinon'
import { ethers } from 'ethers'
import BigNumber from 'bignumber.js'
import ObservableStore from 'obs-store'
import { ROPSTEN_NETWORK_ID, MAINNET_NETWORK_ID } from '../../../../app/scripts/controllers/network/enums'
import { createTestProviderTools } from '../../../stub/provider'
import SwapsController, { utils } from '../../../../app/scripts/controllers/swaps'
@ -75,6 +76,19 @@ const MOCK_GET_BUFFERED_GAS_LIMIT = async () => ({
simulationFails: undefined,
})
function getMockNetworkController () {
return {
store: {
getState: () => {
return {
network: ROPSTEN_NETWORK_ID,
}
},
},
on: sinon.stub().withArgs('networkDidChange').callsArgAsync(1),
}
}
const EMPTY_INIT_STATE = {
swapsState: {
quotes: {},
@ -104,6 +118,7 @@ describe('SwapsController', function () {
const getSwapsController = () => {
return new SwapsController({
getBufferedGasLimit: MOCK_GET_BUFFERED_GAS_LIMIT,
networkController: getMockNetworkController(),
provider,
getProviderConfig: MOCK_GET_PROVIDER_CONFIG,
tokenRatesStore: MOCK_TOKEN_RATES_STORE,
@ -141,6 +156,78 @@ describe('SwapsController', function () {
MOCK_GET_PROVIDER_CONFIG,
)
})
it('should replace ethers instance when network changes', function () {
const networkController = getMockNetworkController()
const swapsController = new SwapsController({
getBufferedGasLimit: MOCK_GET_BUFFERED_GAS_LIMIT,
networkController,
provider,
getProviderConfig: MOCK_GET_PROVIDER_CONFIG,
tokenRatesStore: MOCK_TOKEN_RATES_STORE,
fetchTradesInfo: fetchTradesInfoStub,
fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub,
})
const currentEthersInstance = swapsController.ethersProvider
const onNetworkDidChange = networkController.on.getCall(0).args[1]
onNetworkDidChange(MAINNET_NETWORK_ID)
const newEthersInstance = swapsController.ethersProvider
assert.notStrictEqual(
currentEthersInstance,
newEthersInstance,
'Ethers provider should be replaced',
)
})
it('should not replace ethers instance when network changes to loading', function () {
const networkController = getMockNetworkController()
const swapsController = new SwapsController({
getBufferedGasLimit: MOCK_GET_BUFFERED_GAS_LIMIT,
networkController,
provider,
getProviderConfig: MOCK_GET_PROVIDER_CONFIG,
tokenRatesStore: MOCK_TOKEN_RATES_STORE,
fetchTradesInfo: fetchTradesInfoStub,
fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub,
})
const currentEthersInstance = swapsController.ethersProvider
const onNetworkDidChange = networkController.on.getCall(0).args[1]
onNetworkDidChange('loading')
const newEthersInstance = swapsController.ethersProvider
assert.strictEqual(
currentEthersInstance,
newEthersInstance,
'Ethers provider should not be replaced',
)
})
it('should not replace ethers instance when network changes to the same network', function () {
const networkController = getMockNetworkController()
const swapsController = new SwapsController({
getBufferedGasLimit: MOCK_GET_BUFFERED_GAS_LIMIT,
networkController,
provider,
getProviderConfig: MOCK_GET_PROVIDER_CONFIG,
tokenRatesStore: MOCK_TOKEN_RATES_STORE,
fetchTradesInfo: fetchTradesInfoStub,
fetchSwapsFeatureLiveness: fetchSwapsFeatureLivenessStub,
})
const currentEthersInstance = swapsController.ethersProvider
const onNetworkDidChange = networkController.on.getCall(0).args[1]
onNetworkDidChange(ROPSTEN_NETWORK_ID)
const newEthersInstance = swapsController.ethersProvider
assert.strictEqual(
currentEthersInstance,
newEthersInstance,
'Ethers provider should not be replaced',
)
})
})
describe('API', function () {

Loading…
Cancel
Save