You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
430 lines
11 KiB
430 lines
11 KiB
const Migrator = require('pojo-migrator')
|
|
const MetamaskConfig = require('../config.js')
|
|
const migrations = require('./migrations')
|
|
const rp = require('request-promise')
|
|
const ethUtil = require('ethereumjs-util')
|
|
|
|
const TESTNET_RPC = MetamaskConfig.network.testnet
|
|
const MAINNET_RPC = MetamaskConfig.network.mainnet
|
|
const txLimit = 40
|
|
|
|
/* The config-manager is a convenience object
|
|
* wrapping a pojo-migrator.
|
|
*
|
|
* It exists mostly to allow the creation of
|
|
* convenience methods to access and persist
|
|
* particular portions of the state.
|
|
*/
|
|
module.exports = ConfigManager
|
|
function ConfigManager (opts) {
|
|
this.txLimit = txLimit
|
|
|
|
// ConfigManager is observable and will emit updates
|
|
this._subs = []
|
|
|
|
/* The migrator exported on the config-manager
|
|
* has two methods the user should be concerned with:
|
|
*
|
|
* getData(), which returns the app-consumable data object
|
|
* saveData(), which persists the app-consumable data object.
|
|
*/
|
|
this.migrator = new Migrator({
|
|
|
|
// Migrations must start at version 1 or later.
|
|
// They are objects with a `version` number
|
|
// and a `migrate` function.
|
|
//
|
|
// The `migrate` function receives the previous
|
|
// config data format, and returns the new one.
|
|
migrations: migrations,
|
|
|
|
// How to load initial config.
|
|
// Includes step on migrating pre-pojo-migrator data.
|
|
loadData: opts.loadData,
|
|
|
|
// How to persist migrated config.
|
|
setData: opts.setData,
|
|
})
|
|
}
|
|
|
|
ConfigManager.prototype.setConfig = function (config) {
|
|
var data = this.migrator.getData()
|
|
data.config = config
|
|
this.setData(data)
|
|
this._emitUpdates(config)
|
|
}
|
|
|
|
ConfigManager.prototype.getConfig = function () {
|
|
var data = this.migrator.getData()
|
|
if ('config' in data) {
|
|
return data.config
|
|
} else {
|
|
return {
|
|
provider: {
|
|
type: 'testnet',
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
ConfigManager.prototype.setRpcTarget = function (rpcUrl) {
|
|
var config = this.getConfig()
|
|
config.provider = {
|
|
type: 'rpc',
|
|
rpcTarget: rpcUrl,
|
|
}
|
|
this.setConfig(config)
|
|
}
|
|
|
|
ConfigManager.prototype.setProviderType = function (type) {
|
|
var config = this.getConfig()
|
|
config.provider = {
|
|
type: type,
|
|
}
|
|
this.setConfig(config)
|
|
}
|
|
|
|
ConfigManager.prototype.useEtherscanProvider = function () {
|
|
var config = this.getConfig()
|
|
config.provider = {
|
|
type: 'etherscan',
|
|
}
|
|
this.setConfig(config)
|
|
}
|
|
|
|
ConfigManager.prototype.getProvider = function () {
|
|
var config = this.getConfig()
|
|
return config.provider
|
|
}
|
|
|
|
ConfigManager.prototype.setData = function (data) {
|
|
this.migrator.saveData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.getData = function () {
|
|
return this.migrator.getData()
|
|
}
|
|
|
|
ConfigManager.prototype.setWallet = function (wallet) {
|
|
var data = this.migrator.getData()
|
|
data.wallet = wallet
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.setVault = function (encryptedString) {
|
|
var data = this.getData()
|
|
data.vault = encryptedString
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.getVault = function () {
|
|
var data = this.getData()
|
|
return ('vault' in data) && data.vault
|
|
}
|
|
|
|
ConfigManager.prototype.getKeychains = function () {
|
|
return this.migrator.getData().keychains || []
|
|
}
|
|
|
|
ConfigManager.prototype.setKeychains = function (keychains) {
|
|
var data = this.migrator.getData()
|
|
data.keychains = keychains
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.getSelectedAccount = function () {
|
|
var config = this.getConfig()
|
|
return config.selectedAccount
|
|
}
|
|
|
|
ConfigManager.prototype.setSelectedAccount = function (address) {
|
|
var config = this.getConfig()
|
|
config.selectedAccount = ethUtil.addHexPrefix(address)
|
|
this.setConfig(config)
|
|
}
|
|
|
|
ConfigManager.prototype.getWallet = function () {
|
|
return this.migrator.getData().wallet
|
|
}
|
|
|
|
// Takes a boolean
|
|
ConfigManager.prototype.setShowSeedWords = function (should) {
|
|
var data = this.migrator.getData()
|
|
data.showSeedWords = should
|
|
this.setData(data)
|
|
}
|
|
|
|
|
|
ConfigManager.prototype.getShouldShowSeedWords = function () {
|
|
var data = this.migrator.getData()
|
|
return data.showSeedWords
|
|
}
|
|
|
|
ConfigManager.prototype.setSeedWords = function (words) {
|
|
var data = this.getData()
|
|
data.seedWords = words
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.getSeedWords = function () {
|
|
var data = this.getData()
|
|
return ('seedWords' in data) && data.seedWords
|
|
}
|
|
|
|
ConfigManager.prototype.getCurrentRpcAddress = function () {
|
|
var provider = this.getProvider()
|
|
if (!provider) return null
|
|
switch (provider.type) {
|
|
|
|
case 'mainnet':
|
|
return MAINNET_RPC
|
|
|
|
case 'testnet':
|
|
return TESTNET_RPC
|
|
|
|
default:
|
|
return provider && provider.rpcTarget ? provider.rpcTarget : TESTNET_RPC
|
|
}
|
|
}
|
|
|
|
ConfigManager.prototype.setData = function (data) {
|
|
this.migrator.saveData(data)
|
|
}
|
|
|
|
//
|
|
// Tx
|
|
//
|
|
|
|
ConfigManager.prototype.getTxList = function () {
|
|
var data = this.migrator.getData()
|
|
if (data.transactions !== undefined) {
|
|
return data.transactions
|
|
} else {
|
|
return []
|
|
}
|
|
}
|
|
|
|
ConfigManager.prototype.unconfirmedTxs = function () {
|
|
var transactions = this.getTxList()
|
|
return transactions.filter(tx => tx.status === 'unconfirmed')
|
|
.reduce((result, tx) => { result[tx.id] = tx; return result }, {})
|
|
}
|
|
|
|
ConfigManager.prototype._saveTxList = function (txList) {
|
|
var data = this.migrator.getData()
|
|
data.transactions = txList
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.addTx = function (tx) {
|
|
var transactions = this.getTxList()
|
|
while (transactions.length > this.txLimit - 1) {
|
|
transactions.shift()
|
|
}
|
|
transactions.push(tx)
|
|
this._saveTxList(transactions)
|
|
}
|
|
|
|
ConfigManager.prototype.getTx = function (txId) {
|
|
var transactions = this.getTxList()
|
|
var matching = transactions.filter(tx => tx.id === txId)
|
|
return matching.length > 0 ? matching[0] : null
|
|
}
|
|
|
|
ConfigManager.prototype.confirmTx = function (txId) {
|
|
this._setTxStatus(txId, 'confirmed')
|
|
}
|
|
|
|
ConfigManager.prototype.rejectTx = function (txId) {
|
|
this._setTxStatus(txId, 'rejected')
|
|
}
|
|
|
|
ConfigManager.prototype._setTxStatus = function (txId, status) {
|
|
var tx = this.getTx(txId)
|
|
tx.status = status
|
|
this.updateTx(tx)
|
|
}
|
|
|
|
ConfigManager.prototype.updateTx = function (tx) {
|
|
var transactions = this.getTxList()
|
|
var found, index
|
|
transactions.forEach((otherTx, i) => {
|
|
if (otherTx.id === tx.id) {
|
|
found = true
|
|
index = i
|
|
}
|
|
})
|
|
if (found) {
|
|
transactions[index] = tx
|
|
}
|
|
this._saveTxList(transactions)
|
|
}
|
|
|
|
// wallet nickname methods
|
|
|
|
ConfigManager.prototype.getWalletNicknames = function () {
|
|
var data = this.getData()
|
|
const nicknames = ('walletNicknames' in data) ? data.walletNicknames : {}
|
|
return nicknames
|
|
}
|
|
|
|
ConfigManager.prototype.nicknameForWallet = function (account) {
|
|
const address = ethUtil.addHexPrefix(account.toLowerCase())
|
|
const nicknames = this.getWalletNicknames()
|
|
return nicknames[address]
|
|
}
|
|
|
|
ConfigManager.prototype.setNicknameForWallet = function (account, nickname) {
|
|
const address = ethUtil.addHexPrefix(account.toLowerCase())
|
|
const nicknames = this.getWalletNicknames()
|
|
nicknames[address] = nickname
|
|
var data = this.getData()
|
|
data.walletNicknames = nicknames
|
|
this.setData(data)
|
|
}
|
|
|
|
// observable
|
|
|
|
ConfigManager.prototype.getSalt = function () {
|
|
var data = this.getData()
|
|
return ('salt' in data) && data.salt
|
|
}
|
|
|
|
ConfigManager.prototype.setSalt = function(salt) {
|
|
var data = this.getData()
|
|
data.salt = salt
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.subscribe = function (fn) {
|
|
this._subs.push(fn)
|
|
var unsubscribe = this.unsubscribe.bind(this, fn)
|
|
return unsubscribe
|
|
}
|
|
|
|
ConfigManager.prototype.unsubscribe = function (fn) {
|
|
var index = this._subs.indexOf(fn)
|
|
if (index !== -1) this._subs.splice(index, 1)
|
|
}
|
|
|
|
ConfigManager.prototype._emitUpdates = function (state) {
|
|
this._subs.forEach(function (handler) {
|
|
handler(state)
|
|
})
|
|
}
|
|
|
|
ConfigManager.prototype.setConfirmed = function (confirmed) {
|
|
var data = this.getData()
|
|
data.isConfirmed = confirmed
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.getConfirmed = function () {
|
|
var data = this.getData()
|
|
return ('isConfirmed' in data) && data.isConfirmed
|
|
}
|
|
|
|
ConfigManager.prototype.setTOSHash = function (hash) {
|
|
var data = this.getData()
|
|
data.TOSHash = hash
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.getTOSHash = function () {
|
|
var data = this.getData()
|
|
return ('TOSHash' in data) && data.TOSHash
|
|
}
|
|
|
|
ConfigManager.prototype.setCurrentFiat = function (currency) {
|
|
var data = this.getData()
|
|
data.fiatCurrency = currency
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.getCurrentFiat = function () {
|
|
var data = this.getData()
|
|
return ('fiatCurrency' in data) && data.fiatCurrency
|
|
}
|
|
|
|
ConfigManager.prototype.updateConversionRate = function () {
|
|
var data = this.getData()
|
|
return rp(`https://www.cryptonator.com/api/ticker/eth-${data.fiatCurrency}`)
|
|
.then((response) => {
|
|
const parsedResponse = JSON.parse(response)
|
|
this.setConversionPrice(parsedResponse.ticker.price)
|
|
this.setConversionDate(parsedResponse.timestamp)
|
|
}).catch((err) => {
|
|
console.error('Error in conversion.', err)
|
|
this.setConversionPrice(0)
|
|
this.setConversionDate('N/A')
|
|
})
|
|
|
|
}
|
|
|
|
ConfigManager.prototype.setConversionPrice = function (price) {
|
|
var data = this.getData()
|
|
data.conversionRate = Number(price)
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.setConversionDate = function (datestring) {
|
|
var data = this.getData()
|
|
data.conversionDate = datestring
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.getConversionRate = function () {
|
|
var data = this.getData()
|
|
return (('conversionRate' in data) && data.conversionRate) || 0
|
|
}
|
|
|
|
ConfigManager.prototype.getConversionDate = function () {
|
|
var data = this.getData()
|
|
return (('conversionDate' in data) && data.conversionDate) || 'N/A'
|
|
}
|
|
|
|
ConfigManager.prototype.getShapeShiftTxList = function () {
|
|
var data = this.getData()
|
|
var shapeShiftTxList = data.shapeShiftTxList ? data.shapeShiftTxList : []
|
|
shapeShiftTxList.forEach((tx) => {
|
|
if (tx.response.status !== 'complete') {
|
|
var requestListner = function (request) {
|
|
tx.response = JSON.parse(this.responseText)
|
|
if (tx.response.status === 'complete') {
|
|
tx.time = new Date().getTime()
|
|
}
|
|
}
|
|
|
|
var shapShiftReq = new XMLHttpRequest()
|
|
shapShiftReq.addEventListener('load', requestListner)
|
|
shapShiftReq.open('GET', `https://shapeshift.io/txStat/${tx.depositAddress}`, true)
|
|
shapShiftReq.send()
|
|
}
|
|
})
|
|
this.setData(data)
|
|
return shapeShiftTxList
|
|
}
|
|
|
|
ConfigManager.prototype.createShapeShiftTx = function (depositAddress, depositType) {
|
|
var data = this.getData()
|
|
|
|
var shapeShiftTx = {depositAddress, depositType, key: 'shapeshift', time: new Date().getTime(), response: {}}
|
|
if (!data.shapeShiftTxList) {
|
|
data.shapeShiftTxList = [shapeShiftTx]
|
|
} else {
|
|
data.shapeShiftTxList.push(shapeShiftTx)
|
|
}
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.getGasMultiplier = function () {
|
|
var data = this.getData()
|
|
return ('gasMultiplier' in data) && data.gasMultiplier
|
|
}
|
|
|
|
ConfigManager.prototype.setGasMultiplier = function (gasMultiplier) {
|
|
var data = this.getData()
|
|
|
|
data.gasMultiplier = gasMultiplier
|
|
this.setData(data)
|
|
}
|
|
|