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.
346 lines
7.8 KiB
346 lines
7.8 KiB
const Migrator = require('pojo-migrator')
|
|
const extend = require('xtend')
|
|
|
|
const STORAGE_KEY = 'metamask-config'
|
|
const DEFAULT_RPC = 'https://testrpc.metamask.io/'
|
|
|
|
const migrations = require('./migrations')
|
|
|
|
/* 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() {
|
|
// 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: loadData,
|
|
|
|
// How to persist migrated config.
|
|
setData: function(data) {
|
|
window.localStorage[STORAGE_KEY] = JSON.stringify(data)
|
|
},
|
|
})
|
|
}
|
|
|
|
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: 'rpc',
|
|
rpcTarget: DEFAULT_RPC,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ConfigManager.prototype.setRpcTarget = function(rpcUrl) {
|
|
var config = this.getConfig()
|
|
config.provider = {
|
|
type: 'rpc',
|
|
rpcTarget: rpcUrl,
|
|
}
|
|
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.getSelectedAccount = function() {
|
|
var config = this.getConfig()
|
|
return config.selectedAccount
|
|
}
|
|
|
|
ConfigManager.prototype.setSelectedAccount = function(address) {
|
|
var config = this.getConfig()
|
|
config.selectedAccount = 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.getCurrentRpcAddress = function() {
|
|
var config = this.getConfig()
|
|
if (!config) return null
|
|
return config.provider && config.provider.rpcTarget ? config.provider.rpcTarget : DEFAULT_RPC
|
|
}
|
|
|
|
ConfigManager.prototype.clearWallet = function() {
|
|
var data = this.getConfig()
|
|
delete data.wallet
|
|
this.setData(data)
|
|
}
|
|
|
|
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()
|
|
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)
|
|
}
|
|
|
|
//
|
|
// Msg
|
|
//
|
|
|
|
ConfigManager.prototype.getMsgList = function() {
|
|
var data = this.migrator.getData()
|
|
if (data.messages !== undefined) {
|
|
return data.messages
|
|
} else {
|
|
return []
|
|
}
|
|
}
|
|
|
|
ConfigManager.prototype.unconfirmedMsgs = function() {
|
|
var messages = this.getMsgList()
|
|
return messages.filter(msg => msg.status === 'unconfirmed')
|
|
.reduce((result, msg) => { result[msg.id] = msg; return result }, {})
|
|
}
|
|
|
|
ConfigManager.prototype._saveMsgList = function(msgList) {
|
|
var data = this.migrator.getData()
|
|
data.messages = msgList
|
|
this.setData(data)
|
|
}
|
|
|
|
ConfigManager.prototype.addMsg = function(msg) {
|
|
var messages = this.getMsgList()
|
|
messages.push(msg)
|
|
this._saveMsgList(messages)
|
|
}
|
|
|
|
ConfigManager.prototype.getMsg = function(msgId) {
|
|
var messages = this.getMsgList()
|
|
var matching = messages.filter(msg => msg.id === msgId)
|
|
return matching.length > 0 ? matching[0] : null
|
|
}
|
|
|
|
ConfigManager.prototype.confirmMsg = function(msgId) {
|
|
this._setMsgStatus(msgId, 'confirmed')
|
|
}
|
|
|
|
ConfigManager.prototype.rejectMsg = function(msgId) {
|
|
this._setMsgStatus(msgId, 'rejected')
|
|
}
|
|
|
|
ConfigManager.prototype._setMsgStatus = function(msgId, status) {
|
|
var msg = this.getMsg(msgId)
|
|
msg.status = status
|
|
this.updateMsg(msg)
|
|
}
|
|
|
|
ConfigManager.prototype.updateMsg = function(msg) {
|
|
var messages = this.getMsgList()
|
|
var found, index
|
|
messages.forEach((otherMsg, i) => {
|
|
if (otherMsg.id === msg.id) {
|
|
found = true
|
|
index = i
|
|
}
|
|
})
|
|
if (found) {
|
|
messages[index] = msg
|
|
}
|
|
this._saveMsgList(messages)
|
|
}
|
|
|
|
|
|
|
|
// observable
|
|
|
|
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)
|
|
})
|
|
}
|
|
|
|
|
|
function loadData() {
|
|
|
|
var oldData = getOldStyleData()
|
|
var newData
|
|
try {
|
|
newData = JSON.parse(window.localStorage[STORAGE_KEY])
|
|
} catch (e) {}
|
|
|
|
var data = extend({
|
|
meta: {
|
|
version: 0,
|
|
},
|
|
data: {
|
|
config: {
|
|
rpcTarget: DEFAULT_RPC,
|
|
}
|
|
}
|
|
}, oldData ? oldData : null, newData ? newData : null)
|
|
return data
|
|
}
|
|
|
|
function getOldStyleData() {
|
|
var config, wallet, seedWords
|
|
|
|
var result = {
|
|
meta: { version: 0 },
|
|
data: {},
|
|
}
|
|
|
|
try {
|
|
config = JSON.parse(window.localStorage['config'])
|
|
result.data.config = config
|
|
} catch (e) {}
|
|
try {
|
|
wallet = JSON.parse(window.localStorage['lightwallet'])
|
|
result.data.wallet = wallet
|
|
} catch (e) {}
|
|
try {
|
|
seedWords = window.localStorage['seedWords']
|
|
result.data.seedWords = seedWords
|
|
} catch (e) {}
|
|
|
|
return result
|
|
}
|
|
|
|
|