feature: integrate gaba/ShapeShiftController (#6569)

feature/default_network_editable
Paul Bouchon 6 years ago committed by GitHub
parent b81c4e5c98
commit e57ffbed59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 180
      app/scripts/controllers/shapeshift.js
  2. 12
      app/scripts/metamask-controller.js
  3. 2
      test/unit/app/controllers/metamask-controller-test.js

@ -1,180 +0,0 @@
const ObservableStore = require('obs-store')
const extend = require('xtend')
const log = require('loglevel')
// every three seconds when an incomplete tx is waiting
const POLLING_INTERVAL = 3000
class ShapeshiftController {
/**
* Controller responsible for managing the list of shapeshift transactions. On construction, it initiates a poll
* that queries a shapeshift.io API for updates to any pending shapeshift transactions
*
* @typedef {Object} ShapeshiftController
* @param {object} opts Overrides the defaults for the initial state of this.store
* @property {array} opts.initState initializes the the state of the ShapeshiftController. Can contain an
* shapeShiftTxList array.
* @property {array} shapeShiftTxList An array of ShapeShiftTx objects
*
*/
constructor (opts = {}) {
const initState = extend({
shapeShiftTxList: [],
}, opts.initState)
this.store = new ObservableStore(initState)
this.pollForUpdates()
}
/**
* Represents, and contains data about, a single shapeshift transaction.
* @typedef {Object} ShapeShiftTx
* @property {string} depositAddress - An address at which to send a crypto deposit, so that eth can be sent to the
* user's Metamask account
* @property {string} depositType - An abbreviation of the type of crypto currency to be deposited.
* @property {string} key - The 'shapeshift' key differentiates this from other types of txs in Metamask
* @property {number} time - The time at which the tx was created
* @property {object} response - Initiated as an empty object, which will be replaced by a Response object. @see {@link
* https://developer.mozilla.org/en-US/docs/Web/API/Response}
*/
//
// PUBLIC METHODS
//
/**
* A getter for the shapeShiftTxList property
*
* @returns {array<ShapeShiftTx>}
*
*/
getShapeShiftTxList () {
const shapeShiftTxList = this.store.getState().shapeShiftTxList
return shapeShiftTxList
}
/**
* A getter for all ShapeShiftTx in the shapeShiftTxList that have not successfully completed a deposit.
*
* @returns {array<ShapeShiftTx>} Only includes ShapeShiftTx which has a response property with a status !== complete
*
*/
getPendingTxs () {
const txs = this.getShapeShiftTxList()
const pending = txs.filter(tx => tx.response && tx.response.status !== 'complete')
return pending
}
/**
* A poll that exists as long as there are pending transactions. Each call attempts to update the data of any
* pendingTxs, and then calls itself again. If there are no pending txs, the recursive call is not made and
* the polling stops.
*
* this.updateTx is used to attempt the update to the pendingTxs in the ShapeShiftTxList, and that updated data
* is saved with saveTx.
*
*/
pollForUpdates () {
const pendingTxs = this.getPendingTxs()
if (pendingTxs.length === 0) {
return
}
Promise.all(pendingTxs.map((tx) => {
return this.updateTx(tx)
}))
.then((results) => {
results.forEach(tx => this.saveTx(tx))
this.timeout = setTimeout(this.pollForUpdates.bind(this), POLLING_INTERVAL)
})
}
/**
* Attempts to update a ShapeShiftTx with data from a shapeshift.io API. Both the response and time properties
* can be updated. The response property is updated with every call, but the time property is only updated when
* the response status updates to 'complete'. This will occur once the user makes a deposit as the ShapeShiftTx
* depositAddress
*
* @param {ShapeShiftTx} tx The tx to update
*
*/
async updateTx (tx) {
try {
const url = `https://shapeshift.io/txStat/${tx.depositAddress}`
const response = await fetch(url)
const json = await response.json()
tx.response = json
if (tx.response.status === 'complete') {
tx.time = new Date().getTime()
}
return tx
} catch (err) {
log.warn(err)
}
}
/**
* Saves an updated to a ShapeShiftTx in the shapeShiftTxList. If the passed ShapeShiftTx is not in the
* shapeShiftTxList, nothing happens.
*
* @param {ShapeShiftTx} tx The updated tx to save, if it exists in the current shapeShiftTxList
*
*/
saveTx (tx) {
const { shapeShiftTxList } = this.store.getState()
const index = shapeShiftTxList.indexOf(tx)
if (index !== -1) {
shapeShiftTxList[index] = tx
this.store.updateState({ shapeShiftTxList })
}
}
/**
* Removes a ShapeShiftTx from the shapeShiftTxList
*
* @param {ShapeShiftTx} tx The tx to remove
*
*/
removeShapeShiftTx () {
const { shapeShiftTxList } = this.store.getState()
const index = shapeShiftTxList.indexOf(index)
if (index !== -1) {
shapeShiftTxList.splice(index, 1)
}
this.updateState({ shapeShiftTxList })
}
/**
* Creates a new ShapeShiftTx, adds it to the shapeShiftTxList, and initiates a new poll for updates of pending txs
*
* @param {string} depositAddress - An address at which to send a crypto deposit, so that eth can be sent to the
* user's Metamask account
* @param {string} depositType - An abbreviation of the type of crypto currency to be deposited.
*
*/
createShapeShiftTx (depositAddress, depositType) {
const state = this.store.getState()
let { shapeShiftTxList } = state
var shapeShiftTx = {
depositAddress,
depositType,
key: 'shapeshift',
time: new Date().getTime(),
response: {},
}
if (!shapeShiftTxList) {
shapeShiftTxList = [shapeShiftTx]
} else {
shapeShiftTxList.push(shapeShiftTx)
}
this.store.updateState({ shapeShiftTxList })
this.pollForUpdates()
}
}
module.exports = ShapeshiftController

@ -27,7 +27,6 @@ const NetworkController = require('./controllers/network')
const PreferencesController = require('./controllers/preferences') const PreferencesController = require('./controllers/preferences')
const AppStateController = require('./controllers/app-state') const AppStateController = require('./controllers/app-state')
const CurrencyController = require('./controllers/currency') const CurrencyController = require('./controllers/currency')
const ShapeShiftController = require('./controllers/shapeshift')
const InfuraController = require('./controllers/infura') const InfuraController = require('./controllers/infura')
const CachedBalancesController = require('./controllers/cached-balances') const CachedBalancesController = require('./controllers/cached-balances')
const RecentBlocksController = require('./controllers/recent-blocks') const RecentBlocksController = require('./controllers/recent-blocks')
@ -57,6 +56,7 @@ const ethUtil = require('ethereumjs-util')
const sigUtil = require('eth-sig-util') const sigUtil = require('eth-sig-util')
const { const {
AddressBookController, AddressBookController,
ShapeShiftController,
PhishingController, PhishingController,
} = require('gaba') } = require('gaba')
const backEndMetaMetricsEvent = require('./lib/backend-metametrics') const backEndMetaMetricsEvent = require('./lib/backend-metametrics')
@ -237,9 +237,7 @@ module.exports = class MetamaskController extends EventEmitter {
}) })
this.balancesController.updateAllBalances() this.balancesController.updateAllBalances()
this.shapeshiftController = new ShapeShiftController({ this.shapeshiftController = new ShapeShiftController(undefined, initState.ShapeShiftController)
initState: initState.ShapeShiftController,
})
this.networkController.lookupNetwork() this.networkController.lookupNetwork()
this.messageManager = new MessageManager() this.messageManager = new MessageManager()
@ -265,7 +263,7 @@ module.exports = class MetamaskController extends EventEmitter {
PreferencesController: this.preferencesController.store, PreferencesController: this.preferencesController.store,
AddressBookController: this.addressBookController, AddressBookController: this.addressBookController,
CurrencyController: this.currencyController.store, CurrencyController: this.currencyController.store,
ShapeShiftController: this.shapeshiftController.store, ShapeShiftController: this.shapeshiftController,
NetworkController: this.networkController.store, NetworkController: this.networkController.store,
InfuraController: this.infuraController.store, InfuraController: this.infuraController.store,
CachedBalancesController: this.cachedBalancesController.store, CachedBalancesController: this.cachedBalancesController.store,
@ -287,7 +285,7 @@ module.exports = class MetamaskController extends EventEmitter {
RecentBlocksController: this.recentBlocksController.store, RecentBlocksController: this.recentBlocksController.store,
AddressBookController: this.addressBookController, AddressBookController: this.addressBookController,
CurrencyController: this.currencyController.store, CurrencyController: this.currencyController.store,
ShapeshiftController: this.shapeshiftController.store, ShapeshiftController: this.shapeshiftController,
InfuraController: this.infuraController.store, InfuraController: this.infuraController.store,
ProviderApprovalController: this.providerApprovalController.store, ProviderApprovalController: this.providerApprovalController.store,
}) })
@ -1633,7 +1631,7 @@ module.exports = class MetamaskController extends EventEmitter {
* @property {string} depositType - An abbreviation of the type of crypto currency to be deposited. * @property {string} depositType - An abbreviation of the type of crypto currency to be deposited.
*/ */
createShapeShiftTx (depositAddress, depositType) { createShapeShiftTx (depositAddress, depositType) {
this.shapeshiftController.createShapeShiftTx(depositAddress, depositType) this.shapeshiftController.createTransaction(depositAddress, depositType)
} }
// network // network

@ -464,7 +464,7 @@ describe('MetaMaskController', function () {
depositAddress = '3EevLFfB4H4XMWQwYCgjLie1qCAGpd2WBc' depositAddress = '3EevLFfB4H4XMWQwYCgjLie1qCAGpd2WBc'
depositType = 'ETH' depositType = 'ETH'
shapeShiftTxList = metamaskController.shapeshiftController.store.getState().shapeShiftTxList shapeShiftTxList = metamaskController.shapeshiftController.state.shapeShiftTxList
}) })
it('creates a shapeshift tx', async function () { it('creates a shapeshift tx', async function () {

Loading…
Cancel
Save