aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Miller <danjm.com@gmail.com>2018-10-24 14:31:45 +0800
committerDan Miller <danjm.com@gmail.com>2018-12-04 11:36:22 +0800
commit79de7a45ae8da7a9578ce394594e700886a640eb (patch)
tree2305ac70fc7bd7eee28a792b834186b302351a3e
parente3f015c88f30fb4243ebbb3d2f109be8f3d68196 (diff)
downloadtangerine-wallet-browser-79de7a45ae8da7a9578ce394594e700886a640eb.tar
tangerine-wallet-browser-79de7a45ae8da7a9578ce394594e700886a640eb.tar.gz
tangerine-wallet-browser-79de7a45ae8da7a9578ce394594e700886a640eb.tar.bz2
tangerine-wallet-browser-79de7a45ae8da7a9578ce394594e700886a640eb.tar.lz
tangerine-wallet-browser-79de7a45ae8da7a9578ce394594e700886a640eb.tar.xz
tangerine-wallet-browser-79de7a45ae8da7a9578ce394594e700886a640eb.tar.zst
tangerine-wallet-browser-79de7a45ae8da7a9578ce394594e700886a640eb.zip
Connect gas price chart to gas station api.
-rw-r--r--ui/app/ducks/gas.duck.js86
-rw-r--r--ui/app/ducks/tests/gas-duck.test.js139
-rw-r--r--ui/lib/local-storage-helpers.js20
3 files changed, 204 insertions, 41 deletions
diff --git a/ui/app/ducks/gas.duck.js b/ui/app/ducks/gas.duck.js
index 2dcec91de..3a2a1f576 100644
--- a/ui/app/ducks/gas.duck.js
+++ b/ui/app/ducks/gas.duck.js
@@ -1,6 +1,9 @@
-import { mockGasEstimateData } from './mock-gas-estimate-data'
import { clone, uniqBy } from 'ramda'
import BigNumber from 'bignumber.js'
+import {
+ loadLocalStorageData,
+ saveLocalStorageData,
+} from '../../lib/local-storage-helpers'
// Actions
const BASIC_GAS_ESTIMATE_LOADING_FINISHED = 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_FINISHED'
@@ -15,6 +18,7 @@ const SET_CUSTOM_GAS_LIMIT = 'metamask/gas/SET_CUSTOM_GAS_LIMIT'
const SET_CUSTOM_GAS_PRICE = 'metamask/gas/SET_CUSTOM_GAS_PRICE'
const SET_CUSTOM_GAS_TOTAL = 'metamask/gas/SET_CUSTOM_GAS_TOTAL'
const SET_PRICE_AND_TIME_ESTIMATES = 'metamask/gas/SET_PRICE_AND_TIME_ESTIMATES'
+const SET_API_ESTIMATES_LAST_RETRIEVED = 'metamask/gas/SET_API_ESTIMATES_LAST_RETRIEVED'
// TODO: determine if this approach to initState is consistent with conventional ducks pattern
const initState = {
@@ -38,6 +42,7 @@ const initState = {
basicEstimateIsLoading: true,
gasEstimatesLoading: true,
priceAndTimeEstimates: [],
+ priceAndTimeEstimatesLastRetrieved: 0,
errors: {},
}
@@ -108,6 +113,11 @@ export default function reducer ({ gas: gasState = initState }, action = {}) {
...action.value,
},
}
+ case SET_API_ESTIMATES_LAST_RETRIEVED:
+ return {
+ ...newState,
+ priceAndTimeEstimatesLastRetrieved: action.value,
+ }
case RESET_CUSTOM_DATA:
return {
...newState,
@@ -192,34 +202,51 @@ export function fetchBasicGasEstimates () {
}
export function fetchGasEstimates (blockTime) {
- return (dispatch) => {
+ return (dispatch, getState) => {
+ const {
+ priceAndTimeEstimatesLastRetrieved,
+ priceAndTimeEstimates,
+ } = getState().gas
+ const timeLastRetrieved = priceAndTimeEstimatesLastRetrieved || loadLocalStorageData('GAS_API_ESTIMATES_LAST_RETRIEVED')
+
dispatch(gasEstimatesLoadingStarted())
- // TODO: uncomment code when live api is ready
- // return fetch('https://ethgasstation.info/json/predictTable.json', {
- // 'headers': {},
- // 'referrer': 'http://ethgasstation.info/json/',
- // 'referrerPolicy': 'no-referrer-when-downgrade',
- // 'body': null,
- // 'method': 'GET',
- // 'mode': 'cors'}
- // )
- return new Promise(resolve => {
- resolve(mockGasEstimateData)
- })
- // .then(r => r.json())
- .then(r => {
- const estimatedPricesAndTimes = r.map(({ expectedTime, expectedWait, gasprice }) => ({ expectedTime, expectedWait, gasprice }))
- const estimatedTimeWithUniquePrices = uniqBy(({ expectedTime }) => expectedTime, estimatedPricesAndTimes)
- const timeMappedToSeconds = estimatedTimeWithUniquePrices.map(({ expectedWait, gasprice }) => {
- const expectedTime = (new BigNumber(expectedWait)).times(Number(blockTime), 10).toString(10)
- return {
- expectedTime,
- expectedWait,
- gasprice,
- }
+ const promiseToFetch = Date.now() - timeLastRetrieved > 75000
+ ? fetch('https://ethgasstation.info/json/predictTable.json', {
+ 'headers': {},
+ 'referrer': 'http://ethgasstation.info/json/',
+ 'referrerPolicy': 'no-referrer-when-downgrade',
+ 'body': null,
+ 'method': 'GET',
+ 'mode': 'cors'}
+ )
+ .then(r => r.json())
+ .then(r => {
+ const estimatedPricesAndTimes = r.map(({ expectedTime, expectedWait, gasprice }) => ({ expectedTime, expectedWait, gasprice }))
+ const estimatedTimeWithUniquePrices = uniqBy(({ expectedTime }) => expectedTime, estimatedPricesAndTimes)
+ const timeMappedToSeconds = estimatedTimeWithUniquePrices.map(({ expectedWait, gasprice }) => {
+ const expectedTime = (new BigNumber(expectedWait)).times(Number(blockTime), 10).toString(10)
+ return {
+ expectedTime,
+ expectedWait,
+ gasprice,
+ }
+ })
+
+ const timeRetrieved = Date.now()
+ dispatch(setApiEstimatesLastRetrieved(timeRetrieved))
+ saveLocalStorageData(timeRetrieved, 'GAS_API_ESTIMATES_LAST_RETRIEVED')
+ saveLocalStorageData(timeMappedToSeconds.slice(1), 'GAS_API_ESTIMATES')
+
+ return timeMappedToSeconds.slice(1)
})
- dispatch(setPricesAndTimeEstimates(timeMappedToSeconds.slice(1)))
+ : Promise.resolve(priceAndTimeEstimates.length
+ ? priceAndTimeEstimates
+ : loadLocalStorageData('GAS_API_ESTIMATES')
+ )
+
+ return promiseToFetch.then(estimates => {
+ dispatch(setPricesAndTimeEstimates(estimates))
dispatch(gasEstimatesLoadingFinished())
})
}
@@ -267,6 +294,13 @@ export function setCustomGasErrors (newErrors) {
}
}
+export function setApiEstimatesLastRetrieved (retrievalTime) {
+ return {
+ type: SET_API_ESTIMATES_LAST_RETRIEVED,
+ value: retrievalTime,
+ }
+}
+
export function resetCustomGasState () {
return { type: RESET_CUSTOM_GAS_STATE }
}
diff --git a/ui/app/ducks/tests/gas-duck.test.js b/ui/app/ducks/tests/gas-duck.test.js
index 464b122ae..96c00383b 100644
--- a/ui/app/ducks/tests/gas-duck.test.js
+++ b/ui/app/ducks/tests/gas-duck.test.js
@@ -14,33 +14,52 @@ import GasReducer, {
gasEstimatesLoadingStarted,
gasEstimatesLoadingFinished,
setPricesAndTimeEstimates,
+ fetchGasEstimates,
+ setApiEstimatesLastRetrieved,
} from '../gas.duck.js'
describe('Gas Duck', () => {
let tempFetch
- const fetchStub = sinon.stub().returns(new Promise(resolve => resolve({
- json: () => new Promise(resolve => resolve({
- average: 'mockAverage',
- avgWait: 'mockAvgWait',
- block_time: 'mockBlock_time',
- blockNum: 'mockBlockNum',
- fast: 'mockFast',
- fastest: 'mockFastest',
- fastestWait: 'mockFastestWait',
- fastWait: 'mockFastWait',
- safeLow: 'mockSafeLow',
- safeLowWait: 'mockSafeLowWait',
- speed: 'mockSpeed',
- })),
- })))
+ let tempDateNow
+ const mockEthGasApiResponse = {
+ average: 'mockAverage',
+ avgWait: 'mockAvgWait',
+ block_time: 'mockBlock_time',
+ blockNum: 'mockBlockNum',
+ fast: 'mockFast',
+ fastest: 'mockFastest',
+ fastestWait: 'mockFastestWait',
+ fastWait: 'mockFastWait',
+ safeLow: 'mockSafeLow',
+ safeLowWait: 'mockSafeLowWait',
+ speed: 'mockSpeed',
+ }
+ const mockPredictTableResponse = [
+ { expectedTime: 100, expectedWait: 10, gasprice: 1, somethingElse: 'foobar' },
+ { expectedTime: 50, expectedWait: 5, gasprice: 2, somethingElse: 'foobar' },
+ { expectedTime: 20, expectedWait: 4, gasprice: 4, somethingElse: 'foobar' },
+ { expectedTime: 10, expectedWait: 2, gasprice: 10, somethingElse: 'foobar' },
+ { expectedTime: 1, expectedWait: 0.5, gasprice: 20, somethingElse: 'foobar' },
+ ]
+ const fetchStub = sinon.stub().callsFake((url) => new Promise(resolve => {
+ const dataToResolve = url.match(/ethgasAPI/)
+ ? mockEthGasApiResponse
+ : mockPredictTableResponse
+ resolve({
+ json: () => new Promise(resolve => resolve(dataToResolve)),
+ })
+ }))
beforeEach(() => {
tempFetch = global.fetch
+ tempDateNow = global.Date.now
global.fetch = fetchStub
+ global.Date.now = () => 2000000
})
afterEach(() => {
global.fetch = tempFetch
+ global.Date.now = tempDateNow
})
const mockState = {
@@ -70,6 +89,7 @@ describe('Gas Duck', () => {
errors: {},
gasEstimatesLoading: true,
priceAndTimeEstimates: [],
+ priceAndTimeEstimatesLastRetrieved: 0,
}
const BASIC_GAS_ESTIMATE_LOADING_FINISHED = 'metamask/gas/BASIC_GAS_ESTIMATE_LOADING_FINISHED'
@@ -83,6 +103,7 @@ describe('Gas Duck', () => {
const SET_CUSTOM_GAS_PRICE = 'metamask/gas/SET_CUSTOM_GAS_PRICE'
const SET_CUSTOM_GAS_TOTAL = 'metamask/gas/SET_CUSTOM_GAS_TOTAL'
const SET_PRICE_AND_TIME_ESTIMATES = 'metamask/gas/SET_PRICE_AND_TIME_ESTIMATES'
+ const SET_API_ESTIMATES_LAST_RETRIEVED = 'metamask/gas/SET_API_ESTIMATES_LAST_RETRIEVED'
describe('GasReducer()', () => {
it('should initialize state', () => {
@@ -193,6 +214,16 @@ describe('Gas Duck', () => {
)
})
+ it('should set priceAndTimeEstimatesLastRetrieved when receivinga SET_API_ESTIMATES_LAST_RETRIEVED action', () => {
+ assert.deepEqual(
+ GasReducer(mockState, {
+ type: SET_API_ESTIMATES_LAST_RETRIEVED,
+ value: 1500000000000,
+ }),
+ Object.assign({ priceAndTimeEstimatesLastRetrieved: 1500000000000 }, mockState.gas)
+ )
+ })
+
it('should set errors when receiving a SET_CUSTOM_GAS_ERRORS action', () => {
assert.deepEqual(
GasReducer(mockState, {
@@ -279,6 +310,75 @@ describe('Gas Duck', () => {
})
})
+ describe('fetchGasEstimates', () => {
+ const mockDistpatch = sinon.spy()
+ it('should call fetch with the expected params', async () => {
+ global.fetch.resetHistory()
+ await fetchGasEstimates(5)(mockDistpatch, () => ({ gas: Object.assign(
+ {},
+ initState,
+ { priceAndTimeEstimatesLastRetrieved: 1000000 }
+ ) }))
+ assert.deepEqual(
+ mockDistpatch.getCall(0).args,
+ [{ type: GAS_ESTIMATE_LOADING_STARTED} ]
+ )
+ assert.deepEqual(
+ global.fetch.getCall(0).args,
+ [
+ 'https://ethgasstation.info/json/predictTable.json',
+ {
+ 'headers': {},
+ 'referrer': 'http://ethgasstation.info/json/',
+ 'referrerPolicy': 'no-referrer-when-downgrade',
+ 'body': null,
+ 'method': 'GET',
+ 'mode': 'cors',
+ },
+ ]
+ )
+
+ assert.deepEqual(
+ mockDistpatch.getCall(1).args,
+ [{ type: SET_API_ESTIMATES_LAST_RETRIEVED, value: 2000000 }]
+ )
+
+ assert.deepEqual(
+ mockDistpatch.getCall(2).args,
+ [{
+ type: SET_PRICE_AND_TIME_ESTIMATES,
+ value: [
+ {
+ expectedTime: '25',
+ expectedWait: 5,
+ gasprice: 2,
+ },
+ {
+ expectedTime: '20',
+ expectedWait: 4,
+ gasprice: 4,
+ },
+ {
+ expectedTime: '10',
+ expectedWait: 2,
+ gasprice: 10,
+ },
+ {
+ expectedTime: '2.5',
+ expectedWait: 0.5,
+ gasprice: 20,
+ },
+ ],
+
+ }]
+ )
+ assert.deepEqual(
+ mockDistpatch.getCall(3).args,
+ [{ type: GAS_ESTIMATE_LOADING_FINISHED }]
+ )
+ })
+ })
+
describe('gasEstimatesLoadingStarted', () => {
it('should create the correct action', () => {
assert.deepEqual(
@@ -351,6 +451,15 @@ describe('Gas Duck', () => {
})
})
+ describe('setApiEstimatesLastRetrieved', () => {
+ it('should create the correct action', () => {
+ assert.deepEqual(
+ setApiEstimatesLastRetrieved(1234),
+ { type: SET_API_ESTIMATES_LAST_RETRIEVED, value: 1234 }
+ )
+ })
+ })
+
describe('resetCustomGasState', () => {
it('should create the correct action', () => {
assert.deepEqual(
diff --git a/ui/lib/local-storage-helpers.js b/ui/lib/local-storage-helpers.js
new file mode 100644
index 000000000..287586c49
--- /dev/null
+++ b/ui/lib/local-storage-helpers.js
@@ -0,0 +1,20 @@
+export function loadLocalStorageData (itemKey) {
+ try {
+ const serializedData = localStorage.getItem(itemKey)
+ if (serializedData === null) {
+ return undefined
+ }
+ return JSON.parse(serializedData)
+ } catch (err) {
+ return undefined
+ }
+}
+
+export function saveLocalStorageData (data, itemKey) {
+ try {
+ const serializedData = JSON.stringify(data)
+ localStorage.setItem(itemKey, serializedData)
+ } catch (err) {
+ console.warn(err)
+ }
+}