commit
59ab595b5e
@ -1,4 +1,4 @@ |
|||||||
{ |
{ |
||||||
"presets": [["env"], "react", "stage-0"], |
"presets": [["env", { "targets": { "browsers": [">0.25%", "not ie 11", "not op_mini all"] } } ], "react", "stage-0"], |
||||||
"plugins": ["transform-runtime", "transform-async-to-generator", "transform-class-properties"] |
"plugins": ["transform-runtime", "transform-async-to-generator", "transform-class-properties"] |
||||||
} |
} |
||||||
|
@ -1,3 +0,0 @@ |
|||||||
{ |
|
||||||
"generator-mocha": {} |
|
||||||
} |
|
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 795 B |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.5 KiB |
@ -0,0 +1,12 @@ |
|||||||
|
const TRANSACTION_TYPE_CANCEL = 'cancel' |
||||||
|
const TRANSACTION_TYPE_RETRY = 'retry' |
||||||
|
const TRANSACTION_TYPE_STANDARD = 'standard' |
||||||
|
|
||||||
|
const TRANSACTION_STATUS_APPROVED = 'approved' |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
TRANSACTION_TYPE_CANCEL, |
||||||
|
TRANSACTION_TYPE_RETRY, |
||||||
|
TRANSACTION_TYPE_STANDARD, |
||||||
|
TRANSACTION_STATUS_APPROVED, |
||||||
|
} |
@ -1,254 +0,0 @@ |
|||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const normalize = require('eth-sig-util').normalize |
|
||||||
const { |
|
||||||
MAINNET_RPC_URL, |
|
||||||
ROPSTEN_RPC_URL, |
|
||||||
KOVAN_RPC_URL, |
|
||||||
RINKEBY_RPC_URL, |
|
||||||
} = require('../controllers/network/enums') |
|
||||||
|
|
||||||
/* 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) { |
|
||||||
// ConfigManager is observable and will emit updates
|
|
||||||
this._subs = [] |
|
||||||
this.store = opts.store |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.setConfig = function (config) { |
|
||||||
var data = this.getData() |
|
||||||
data.config = config |
|
||||||
this.setData(data) |
|
||||||
this._emitUpdates(config) |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.getConfig = function () { |
|
||||||
var data = this.getData() |
|
||||||
return data.config |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.setData = function (data) { |
|
||||||
this.store.putState(data) |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.getData = function () { |
|
||||||
return this.store.getState() |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.setPasswordForgotten = function (passwordForgottenState) { |
|
||||||
const data = this.getData() |
|
||||||
data.forgottenPassword = passwordForgottenState |
|
||||||
this.setData(data) |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.getPasswordForgotten = function (passwordForgottenState) { |
|
||||||
const data = this.getData() |
|
||||||
return data.forgottenPassword |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.setWallet = function (wallet) { |
|
||||||
var data = this.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 data.vault |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.getKeychains = function () { |
|
||||||
return this.getData().keychains || [] |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.setKeychains = function (keychains) { |
|
||||||
var data = this.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.getData().wallet |
|
||||||
} |
|
||||||
|
|
||||||
// Takes a boolean
|
|
||||||
ConfigManager.prototype.setShowSeedWords = function (should) { |
|
||||||
var data = this.getData() |
|
||||||
data.showSeedWords = should |
|
||||||
this.setData(data) |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
ConfigManager.prototype.getShouldShowSeedWords = function () { |
|
||||||
var data = this.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 data.seedWords |
|
||||||
} |
|
||||||
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.getCurrentRpcAddress = function () { |
|
||||||
var provider = this.getProvider() |
|
||||||
if (!provider) return null |
|
||||||
switch (provider.type) { |
|
||||||
|
|
||||||
case 'mainnet': |
|
||||||
return MAINNET_RPC_URL |
|
||||||
|
|
||||||
case 'ropsten': |
|
||||||
return ROPSTEN_RPC_URL |
|
||||||
|
|
||||||
case 'kovan': |
|
||||||
return KOVAN_RPC_URL |
|
||||||
|
|
||||||
case 'rinkeby': |
|
||||||
return RINKEBY_RPC_URL |
|
||||||
|
|
||||||
default: |
|
||||||
return provider && provider.rpcTarget ? provider.rpcTarget : RINKEBY_RPC_URL |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
//
|
|
||||||
// Tx
|
|
||||||
//
|
|
||||||
|
|
||||||
ConfigManager.prototype.getTxList = function () { |
|
||||||
var data = this.getData() |
|
||||||
if (data.transactions !== undefined) { |
|
||||||
return data.transactions |
|
||||||
} else { |
|
||||||
return [] |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.setTxList = function (txList) { |
|
||||||
var data = this.getData() |
|
||||||
data.transactions = txList |
|
||||||
this.setData(data) |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// 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 = normalize(account) |
|
||||||
const nicknames = this.getWalletNicknames() |
|
||||||
return nicknames[address] |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.setNicknameForWallet = function (account, nickname) { |
|
||||||
const address = normalize(account) |
|
||||||
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 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.setLostAccounts = function (lostAccounts) { |
|
||||||
var data = this.getData() |
|
||||||
data.lostAccounts = lostAccounts |
|
||||||
this.setData(data) |
|
||||||
} |
|
||||||
|
|
||||||
ConfigManager.prototype.getLostAccounts = function () { |
|
||||||
var data = this.getData() |
|
||||||
return data.lostAccounts || [] |
|
||||||
} |
|
@ -1,50 +0,0 @@ |
|||||||
const version = 5 |
|
||||||
|
|
||||||
/* |
|
||||||
|
|
||||||
This is an incomplete migration bc it requires post-decrypted data |
|
||||||
which we dont have access to at the time of this writing. |
|
||||||
|
|
||||||
*/ |
|
||||||
|
|
||||||
const ObservableStore = require('obs-store') |
|
||||||
const ConfigManager = require('../../app/scripts/lib/config-manager') |
|
||||||
const IdentityStoreMigrator = require('../../app/scripts/lib/idStore-migrator') |
|
||||||
const KeyringController = require('eth-keyring-controller') |
|
||||||
|
|
||||||
const password = 'obviously not correct' |
|
||||||
|
|
||||||
module.exports = { |
|
||||||
version, |
|
||||||
|
|
||||||
migrate: function (versionedData) { |
|
||||||
versionedData.meta.version = version |
|
||||||
|
|
||||||
const store = new ObservableStore(versionedData.data) |
|
||||||
const configManager = new ConfigManager({ store }) |
|
||||||
const idStoreMigrator = new IdentityStoreMigrator({ configManager }) |
|
||||||
const keyringController = new KeyringController({ |
|
||||||
configManager: configManager, |
|
||||||
}) |
|
||||||
|
|
||||||
// attempt to migrate to multiVault
|
|
||||||
return idStoreMigrator.migratedVaultForPassword(password) |
|
||||||
.then((result) => { |
|
||||||
// skip if nothing to migrate
|
|
||||||
if (!result) return Promise.resolve(versionedData) |
|
||||||
delete versionedData.data.wallet |
|
||||||
// create new keyrings
|
|
||||||
const privKeys = result.lostAccounts.map(acct => acct.privateKey) |
|
||||||
return Promise.all([ |
|
||||||
keyringController.restoreKeyring(result.serialized), |
|
||||||
keyringController.restoreKeyring({ type: 'Simple Key Pair', data: privKeys }), |
|
||||||
]).then(() => { |
|
||||||
return keyringController.persistAllKeyrings(password) |
|
||||||
}).then(() => { |
|
||||||
// copy result on to state object
|
|
||||||
versionedData.data = store.get() |
|
||||||
return Promise.resolve(versionedData) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}, |
|
||||||
} |
|
@ -0,0 +1,5 @@ |
|||||||
|
window.onload = function() { |
||||||
|
if (window.location.pathname === '/phishing.html') { |
||||||
|
document.getElementById('esdbLink').innerHTML = '<b>To read more about this scam, navigate to: <a href="https://etherscamdb.info/domain/' + window.location.hash.substring(1) + '"> https://etherscamdb.info/domain/' + window.location.hash.substring(1) + '</a></b>' |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,202 @@ |
|||||||
|
const inherits = require('util').inherits |
||||||
|
const Component = require('react').Component |
||||||
|
const h = require('react-hyperscript') |
||||||
|
const connect = require('react-redux').connect |
||||||
|
const actions = require('../../ui/app/actions') |
||||||
|
const Tooltip = require('./components/tooltip.js') |
||||||
|
const ethUtil = require('ethereumjs-util') |
||||||
|
const Copyable = require('./components/copyable') |
||||||
|
const addressSummary = require('./util').addressSummary |
||||||
|
|
||||||
|
|
||||||
|
module.exports = connect(mapStateToProps)(AddSuggestedTokenScreen) |
||||||
|
|
||||||
|
function mapStateToProps (state) { |
||||||
|
return { |
||||||
|
identities: state.metamask.identities, |
||||||
|
suggestedTokens: state.metamask.suggestedTokens, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inherits(AddSuggestedTokenScreen, Component) |
||||||
|
function AddSuggestedTokenScreen () { |
||||||
|
this.state = { |
||||||
|
warning: null, |
||||||
|
} |
||||||
|
Component.call(this) |
||||||
|
} |
||||||
|
|
||||||
|
AddSuggestedTokenScreen.prototype.render = function () { |
||||||
|
const state = this.state |
||||||
|
const props = this.props |
||||||
|
const { warning } = state |
||||||
|
const key = Object.keys(props.suggestedTokens)[0] |
||||||
|
const { address, symbol, decimals } = props.suggestedTokens[key] |
||||||
|
|
||||||
|
return ( |
||||||
|
h('.flex-column.flex-grow', [ |
||||||
|
|
||||||
|
// subtitle and nav
|
||||||
|
h('.section-title.flex-row.flex-center', [ |
||||||
|
h('h2.page-subtitle', 'Add Suggested Token'), |
||||||
|
]), |
||||||
|
|
||||||
|
h('.error', { |
||||||
|
style: { |
||||||
|
display: warning ? 'block' : 'none', |
||||||
|
padding: '0 20px', |
||||||
|
textAlign: 'center', |
||||||
|
}, |
||||||
|
}, warning), |
||||||
|
|
||||||
|
// conf view
|
||||||
|
h('.flex-column.flex-justify-center.flex-grow.select-none', [ |
||||||
|
h('.flex-space-around', { |
||||||
|
style: { |
||||||
|
padding: '20px', |
||||||
|
}, |
||||||
|
}, [ |
||||||
|
|
||||||
|
h('div', [ |
||||||
|
h(Tooltip, { |
||||||
|
position: 'top', |
||||||
|
title: 'The contract of the actual token contract. Click for more info.', |
||||||
|
}, [ |
||||||
|
h('a', { |
||||||
|
style: { fontWeight: 'bold', paddingRight: '10px'}, |
||||||
|
href: 'https://support.metamask.io/kb/article/24-what-is-a-token-contract-address', |
||||||
|
target: '_blank', |
||||||
|
}, [ |
||||||
|
h('span', 'Token Contract Address '), |
||||||
|
h('i.fa.fa-question-circle'), |
||||||
|
]), |
||||||
|
]), |
||||||
|
]), |
||||||
|
|
||||||
|
h('div', { |
||||||
|
style: { display: 'flex' }, |
||||||
|
}, [ |
||||||
|
h(Copyable, { |
||||||
|
value: ethUtil.toChecksumAddress(address), |
||||||
|
}, [ |
||||||
|
h('span#token-address', { |
||||||
|
style: { |
||||||
|
width: 'inherit', |
||||||
|
flex: '1 0 auto', |
||||||
|
height: '30px', |
||||||
|
margin: '8px', |
||||||
|
display: 'flex', |
||||||
|
}, |
||||||
|
}, addressSummary(address, 24, 4, false)), |
||||||
|
]), |
||||||
|
]), |
||||||
|
|
||||||
|
h('div', [ |
||||||
|
h('span', { |
||||||
|
style: { fontWeight: 'bold', paddingRight: '10px'}, |
||||||
|
}, 'Token Symbol'), |
||||||
|
]), |
||||||
|
|
||||||
|
h('div', { style: {display: 'flex'} }, [ |
||||||
|
h('p#token_symbol', { |
||||||
|
style: { |
||||||
|
width: 'inherit', |
||||||
|
flex: '1 0 auto', |
||||||
|
height: '30px', |
||||||
|
margin: '8px', |
||||||
|
}, |
||||||
|
}, symbol), |
||||||
|
]), |
||||||
|
|
||||||
|
h('div', [ |
||||||
|
h('span', { |
||||||
|
style: { fontWeight: 'bold', paddingRight: '10px'}, |
||||||
|
}, 'Decimals of Precision'), |
||||||
|
]), |
||||||
|
|
||||||
|
h('div', { style: {display: 'flex'} }, [ |
||||||
|
h('p#token_decimals', { |
||||||
|
type: 'number', |
||||||
|
style: { |
||||||
|
width: 'inherit', |
||||||
|
flex: '1 0 auto', |
||||||
|
height: '30px', |
||||||
|
margin: '8px', |
||||||
|
}, |
||||||
|
}, decimals), |
||||||
|
]), |
||||||
|
|
||||||
|
h('button', { |
||||||
|
style: { |
||||||
|
alignSelf: 'center', |
||||||
|
margin: '8px', |
||||||
|
}, |
||||||
|
onClick: (event) => { |
||||||
|
this.props.dispatch(actions.removeSuggestedTokens()) |
||||||
|
}, |
||||||
|
}, 'Cancel'), |
||||||
|
|
||||||
|
h('button', { |
||||||
|
style: { |
||||||
|
alignSelf: 'center', |
||||||
|
margin: '8px', |
||||||
|
}, |
||||||
|
onClick: (event) => { |
||||||
|
const valid = this.validateInputs({ address, symbol, decimals }) |
||||||
|
if (!valid) return |
||||||
|
|
||||||
|
this.props.dispatch(actions.addToken(address.trim(), symbol.trim(), decimals)) |
||||||
|
.then(() => { |
||||||
|
this.props.dispatch(actions.removeSuggestedTokens()) |
||||||
|
}) |
||||||
|
}, |
||||||
|
}, 'Add'), |
||||||
|
]), |
||||||
|
]), |
||||||
|
]) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
AddSuggestedTokenScreen.prototype.componentWillMount = function () { |
||||||
|
if (typeof global.ethereumProvider === 'undefined') return |
||||||
|
} |
||||||
|
|
||||||
|
AddSuggestedTokenScreen.prototype.validateInputs = function (opts) { |
||||||
|
let msg = '' |
||||||
|
const identitiesList = Object.keys(this.props.identities) |
||||||
|
const { address, symbol, decimals } = opts |
||||||
|
const standardAddress = ethUtil.addHexPrefix(address).toLowerCase() |
||||||
|
|
||||||
|
const validAddress = ethUtil.isValidAddress(address) |
||||||
|
if (!validAddress) { |
||||||
|
msg += 'Address is invalid.' |
||||||
|
} |
||||||
|
|
||||||
|
const validDecimals = decimals >= 0 && decimals <= 36 |
||||||
|
if (!validDecimals) { |
||||||
|
msg += 'Decimals must be at least 0, and not over 36. ' |
||||||
|
} |
||||||
|
|
||||||
|
const symbolLen = symbol.trim().length |
||||||
|
const validSymbol = symbolLen > 0 && symbolLen < 10 |
||||||
|
if (!validSymbol) { |
||||||
|
msg += 'Symbol must be between 0 and 10 characters.' |
||||||
|
} |
||||||
|
|
||||||
|
const ownAddress = identitiesList.includes(standardAddress) |
||||||
|
if (ownAddress) { |
||||||
|
msg = 'Personal address detected. Input the token contract address.' |
||||||
|
} |
||||||
|
|
||||||
|
const isValid = validAddress && validDecimals && !ownAddress |
||||||
|
|
||||||
|
if (!isValid) { |
||||||
|
this.setState({ |
||||||
|
warning: msg, |
||||||
|
}) |
||||||
|
} else { |
||||||
|
this.setState({ warning: null }) |
||||||
|
} |
||||||
|
|
||||||
|
return isValid |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,9 +0,0 @@ |
|||||||
const ObservableStore = require('obs-store') |
|
||||||
const clone = require('clone') |
|
||||||
const ConfigManager = require('../../app/scripts/lib/config-manager') |
|
||||||
const firstTimeState = require('../../app/scripts/first-time-state') |
|
||||||
|
|
||||||
module.exports = function () { |
|
||||||
const store = new ObservableStore(clone(firstTimeState)) |
|
||||||
return new ConfigManager({ store }) |
|
||||||
} |
|
@ -0,0 +1,42 @@ |
|||||||
|
const { shallow, mount } = require('enzyme') |
||||||
|
import { BrowserRouter } from 'react-router-dom' |
||||||
|
import { shape } from 'prop-types' |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
shallowWithStore, |
||||||
|
mountWithStore, |
||||||
|
mountWithRouter, |
||||||
|
} |
||||||
|
|
||||||
|
function shallowWithStore (component, store) { |
||||||
|
const context = { |
||||||
|
store, |
||||||
|
} |
||||||
|
return shallow(component, {context}) |
||||||
|
} |
||||||
|
|
||||||
|
function mountWithStore (component, store) { |
||||||
|
const context = { |
||||||
|
store, |
||||||
|
} |
||||||
|
return mount(component, {context}) |
||||||
|
} |
||||||
|
|
||||||
|
function mountWithRouter (node) { |
||||||
|
|
||||||
|
// Instantiate router context
|
||||||
|
const router = { |
||||||
|
history: new BrowserRouter().history, |
||||||
|
route: { |
||||||
|
location: {}, |
||||||
|
match: {}, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
const createContext = () => ({ |
||||||
|
context: { router, t: () => {} }, |
||||||
|
childContextTypes: { router: shape({}), t: () => {} }, |
||||||
|
}) |
||||||
|
|
||||||
|
return mount(node, createContext()) |
||||||
|
} |
@ -1,20 +0,0 @@ |
|||||||
const { shallow, mount } = require('enzyme') |
|
||||||
|
|
||||||
module.exports = { |
|
||||||
shallowWithStore, |
|
||||||
mountWithStore, |
|
||||||
} |
|
||||||
|
|
||||||
function shallowWithStore (component, store) { |
|
||||||
const context = { |
|
||||||
store, |
|
||||||
} |
|
||||||
return shallow(component, {context}) |
|
||||||
} |
|
||||||
|
|
||||||
function mountWithStore (component, store) { |
|
||||||
const context = { |
|
||||||
store, |
|
||||||
} |
|
||||||
return mount(component, {context}) |
|
||||||
} |
|
@ -0,0 +1,33 @@ |
|||||||
|
const assert = require('assert') |
||||||
|
const cleanErrorStack = require('../../../app/scripts/lib/cleanErrorStack') |
||||||
|
|
||||||
|
describe('Clean Error Stack', () => { |
||||||
|
|
||||||
|
const testMessage = 'Test Message' |
||||||
|
const testError = new Error(testMessage) |
||||||
|
const undefinedErrorName = new Error(testMessage) |
||||||
|
const blankErrorName = new Error(testMessage) |
||||||
|
const blankMsgError = new Error() |
||||||
|
|
||||||
|
beforeEach(() => { |
||||||
|
undefinedErrorName.name = undefined |
||||||
|
blankErrorName.name = '' |
||||||
|
}) |
||||||
|
|
||||||
|
it('tests error with message', () => { |
||||||
|
assert.equal(cleanErrorStack(testError), 'Error: Test Message') |
||||||
|
}) |
||||||
|
|
||||||
|
it('tests error with undefined name', () => { |
||||||
|
assert.equal(cleanErrorStack(undefinedErrorName).toString(), 'Error: Test Message') |
||||||
|
}) |
||||||
|
|
||||||
|
it('tests error with blank name', () => { |
||||||
|
assert.equal(cleanErrorStack(blankErrorName).toString(), 'Test Message') |
||||||
|
}) |
||||||
|
|
||||||
|
it('tests error with blank message', () => { |
||||||
|
assert.equal(cleanErrorStack(blankMsgError), 'Error') |
||||||
|
}) |
||||||
|
|
||||||
|
}) |
@ -1,112 +0,0 @@ |
|||||||
const assert = require('assert') |
|
||||||
const configManagerGen = require('../lib/mock-config-manager') |
|
||||||
|
|
||||||
describe('config-manager', function () { |
|
||||||
var configManager |
|
||||||
|
|
||||||
beforeEach(function () { |
|
||||||
configManager = configManagerGen() |
|
||||||
}) |
|
||||||
|
|
||||||
describe('#setConfig', function () { |
|
||||||
it('should set the config key', function () { |
|
||||||
var testConfig = { |
|
||||||
provider: { |
|
||||||
type: 'rpc', |
|
||||||
rpcTarget: 'foobar', |
|
||||||
}, |
|
||||||
} |
|
||||||
configManager.setConfig(testConfig) |
|
||||||
var result = configManager.getData() |
|
||||||
|
|
||||||
assert.equal(result.config.provider.type, testConfig.provider.type) |
|
||||||
assert.equal(result.config.provider.rpcTarget, testConfig.provider.rpcTarget) |
|
||||||
}) |
|
||||||
|
|
||||||
it('setting wallet should not overwrite config', function () { |
|
||||||
var testConfig = { |
|
||||||
provider: { |
|
||||||
type: 'rpc', |
|
||||||
rpcTarget: 'foobar', |
|
||||||
}, |
|
||||||
} |
|
||||||
configManager.setConfig(testConfig) |
|
||||||
|
|
||||||
var testWallet = { |
|
||||||
name: 'this is my fake wallet', |
|
||||||
} |
|
||||||
configManager.setWallet(testWallet) |
|
||||||
|
|
||||||
var result = configManager.getData() |
|
||||||
assert.equal(result.wallet.name, testWallet.name, 'wallet name is set') |
|
||||||
assert.equal(result.config.provider.rpcTarget, testConfig.provider.rpcTarget) |
|
||||||
|
|
||||||
testConfig.provider.type = 'something else!' |
|
||||||
configManager.setConfig(testConfig) |
|
||||||
|
|
||||||
result = configManager.getData() |
|
||||||
assert.equal(result.wallet.name, testWallet.name, 'wallet name is set') |
|
||||||
assert.equal(result.config.provider.rpcTarget, testConfig.provider.rpcTarget) |
|
||||||
assert.equal(result.config.provider.type, testConfig.provider.type) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('wallet nicknames', function () { |
|
||||||
it('should return null when no nicknames are saved', function () { |
|
||||||
var nick = configManager.nicknameForWallet('0x0') |
|
||||||
assert.equal(nick, null, 'no nickname returned') |
|
||||||
}) |
|
||||||
|
|
||||||
it('should persist nicknames', function () { |
|
||||||
var account = '0x0' |
|
||||||
var nick1 = 'foo' |
|
||||||
var nick2 = 'bar' |
|
||||||
configManager.setNicknameForWallet(account, nick1) |
|
||||||
|
|
||||||
var result1 = configManager.nicknameForWallet(account) |
|
||||||
assert.equal(result1, nick1) |
|
||||||
|
|
||||||
configManager.setNicknameForWallet(account, nick2) |
|
||||||
var result2 = configManager.nicknameForWallet(account) |
|
||||||
assert.equal(result2, nick2) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('rpc manipulations', function () { |
|
||||||
it('changing rpc should return a different rpc', function () { |
|
||||||
var firstRpc = 'first' |
|
||||||
var secondRpc = 'second' |
|
||||||
|
|
||||||
configManager.setRpcTarget(firstRpc) |
|
||||||
var firstResult = configManager.getCurrentRpcAddress() |
|
||||||
assert.equal(firstResult, firstRpc) |
|
||||||
|
|
||||||
configManager.setRpcTarget(secondRpc) |
|
||||||
var secondResult = configManager.getCurrentRpcAddress() |
|
||||||
assert.equal(secondResult, secondRpc) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('transactions', function () { |
|
||||||
beforeEach(function () { |
|
||||||
configManager.setTxList([]) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('#getTxList', function () { |
|
||||||
it('when new should return empty array', function () { |
|
||||||
var result = configManager.getTxList() |
|
||||||
assert.ok(Array.isArray(result)) |
|
||||||
assert.equal(result.length, 0) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
||||||
describe('#setTxList', function () { |
|
||||||
it('saves the submitted data to the tx list', function () { |
|
||||||
var target = [{ foo: 'bar' }] |
|
||||||
configManager.setTxList(target) |
|
||||||
var result = configManager.getTxList() |
|
||||||
assert.equal(result[0].foo, 'bar') |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
@ -0,0 +1,36 @@ |
|||||||
|
import React from 'react' |
||||||
|
import assert from 'assert' |
||||||
|
import thunk from 'redux-thunk' |
||||||
|
import configureMockStore from 'redux-mock-store' |
||||||
|
import { mount } from 'enzyme' |
||||||
|
|
||||||
|
import IdenticonComponent from '../../../../../ui/app/components/identicon' |
||||||
|
|
||||||
|
describe('Identicon Component', () => { |
||||||
|
|
||||||
|
const state = { |
||||||
|
metamask: { |
||||||
|
useBlockie: false, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
const middlewares = [thunk] |
||||||
|
const mockStore = configureMockStore(middlewares) |
||||||
|
const store = mockStore(state) |
||||||
|
|
||||||
|
it('renders default eth_logo identicon with no props', () => { |
||||||
|
const wrapper = mount(<IdenticonComponent store={store}/>) |
||||||
|
assert.equal(wrapper.find('img.balance-icon').prop('src'), './images/eth_logo.svg') |
||||||
|
}) |
||||||
|
|
||||||
|
it('renders custom image and add className props', () => { |
||||||
|
const wrapper = mount(<IdenticonComponent store={store} className={'test-image'} image={'test-image'} />) |
||||||
|
assert.equal(wrapper.find('img.test-image').prop('className'), 'test-image identicon') |
||||||
|
assert.equal(wrapper.find('img.test-image').prop('src'), 'test-image') |
||||||
|
}) |
||||||
|
|
||||||
|
it('renders div with address prop', () => { |
||||||
|
const wrapper = mount(<IdenticonComponent store={store} className={'test-address'} address={'0xTest'} />) |
||||||
|
assert.equal(wrapper.find('div.test-address').prop('className'), 'test-address identicon') |
||||||
|
}) |
||||||
|
}) |
@ -0,0 +1,69 @@ |
|||||||
|
import React from 'react' |
||||||
|
import assert from 'assert' |
||||||
|
import thunk from 'redux-thunk' |
||||||
|
import { Provider } from 'react-redux' |
||||||
|
import configureMockStore from 'redux-mock-store' |
||||||
|
import { mount } from 'enzyme' |
||||||
|
|
||||||
|
import TokenCell from '../../../../../ui/app/components/token-cell' |
||||||
|
import Identicon from '../../../../../ui/app/components/identicon' |
||||||
|
|
||||||
|
describe('Token Cell', () => { |
||||||
|
let wrapper |
||||||
|
|
||||||
|
const state = { |
||||||
|
metamask: { |
||||||
|
network: 'test', |
||||||
|
currentCurrency: 'usd', |
||||||
|
selectedTokenAddress: '0xToken', |
||||||
|
selectedAddress: '0xAddress', |
||||||
|
contractExchangeRates: { |
||||||
|
'0xAnotherToken': 0.015, |
||||||
|
}, |
||||||
|
conversionRate: 7.00, |
||||||
|
}, |
||||||
|
appState: { |
||||||
|
sidebar: { |
||||||
|
isOpen: true, |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
|
||||||
|
const middlewares = [thunk] |
||||||
|
const mockStore = configureMockStore(middlewares) |
||||||
|
const store = mockStore(state) |
||||||
|
|
||||||
|
beforeEach(() => { |
||||||
|
wrapper = mount( |
||||||
|
<Provider store={store}> |
||||||
|
<TokenCell |
||||||
|
address={'0xAnotherToken'} |
||||||
|
symbol={'TEST'} |
||||||
|
string={'5.000'} |
||||||
|
network={22} |
||||||
|
currentCurrency={'usd'} |
||||||
|
image={'./test-image'} |
||||||
|
/> |
||||||
|
</Provider> |
||||||
|
) |
||||||
|
}) |
||||||
|
|
||||||
|
it('renders Identicon with props from token cell', () => { |
||||||
|
assert.equal(wrapper.find(Identicon).prop('address'), '0xAnotherToken') |
||||||
|
assert.equal(wrapper.find(Identicon).prop('network'), 'test') |
||||||
|
assert.equal(wrapper.find(Identicon).prop('image'), './test-image') |
||||||
|
}) |
||||||
|
|
||||||
|
it('renders token balance', () => { |
||||||
|
assert.equal(wrapper.find('.token-list-item__token-balance').text(), '5.000') |
||||||
|
}) |
||||||
|
|
||||||
|
it('renders token symbol', () => { |
||||||
|
assert.equal(wrapper.find('.token-list-item__token-symbol').text(), 'TEST') |
||||||
|
}) |
||||||
|
|
||||||
|
it('renders converted fiat amount', () => { |
||||||
|
assert.equal(wrapper.find('.token-list-item__fiat-amount').text(), '0.52 USD') |
||||||
|
}) |
||||||
|
|
||||||
|
}) |
@ -0,0 +1,175 @@ |
|||||||
|
const assert = require('assert') |
||||||
|
const selectors = require('../../../../ui/app/selectors') |
||||||
|
const mockState = require('../../../data/mock-state.json') |
||||||
|
const Eth = require('ethjs') |
||||||
|
|
||||||
|
const { createTestProviderTools } = require('../../../stub/provider') |
||||||
|
const provider = createTestProviderTools({ scaffold: {}}).provider |
||||||
|
|
||||||
|
describe('Selectors', function () { |
||||||
|
|
||||||
|
describe('#getSelectedAddress', function () { |
||||||
|
let state |
||||||
|
beforeEach(function () { |
||||||
|
state = { |
||||||
|
metamask: { |
||||||
|
accounts: { |
||||||
|
'0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { |
||||||
|
'balance': '0x0', |
||||||
|
'address': '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns first account if selectedAddress is undefined', function () { |
||||||
|
assert.equal(selectors.getSelectedAddress(state), '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns selectedAddress', function () { |
||||||
|
assert.equal(selectors.getSelectedAddress(mockState), '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') |
||||||
|
}) |
||||||
|
|
||||||
|
}) |
||||||
|
|
||||||
|
it('returns selected identity', function () { |
||||||
|
const identity = selectors.getSelectedIdentity(mockState) |
||||||
|
assert.equal(identity.address, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') |
||||||
|
assert.equal(identity.name, 'Test Account') |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns selected account', function () { |
||||||
|
const account = selectors.getSelectedAccount(mockState) |
||||||
|
assert.equal(account.balance, '0x0') |
||||||
|
assert.equal(account.address, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns selected token from first token list', function () { |
||||||
|
const token = selectors.getSelectedToken(mockState) |
||||||
|
assert.equal(token.address, '0x108cf70c7d384c552f42c07c41c0e1e46d77ea0d') |
||||||
|
assert.equal(token.symbol, 'TEST') |
||||||
|
assert.equal(token.decimals, '0') |
||||||
|
}) |
||||||
|
|
||||||
|
describe('#getSelectedTokenExchangeRate', function () { |
||||||
|
it('returns token exchange rate for first token', function () { |
||||||
|
const tokenRate = selectors.getSelectedTokenExchangeRate(mockState) |
||||||
|
assert.equal(tokenRate, '0.00039345803819379796') |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
describe('#getTokenExchangeRate', function () { |
||||||
|
let missingTokenRate |
||||||
|
|
||||||
|
beforeEach(function () { |
||||||
|
missingTokenRate = { |
||||||
|
metamask: { |
||||||
|
'contractExchangeRates': {}, |
||||||
|
}, |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns 0 token exchange rate for a token not in state', function () { |
||||||
|
const tokenRate = selectors.getTokenExchangeRate(missingTokenRate, '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5') |
||||||
|
assert.equal(tokenRate, 0) |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns token exchange rate for specified token in state', function () { |
||||||
|
const tokenRate = selectors.getTokenExchangeRate(mockState, '0xd8f6a2ffb0fc5952d16c9768b71cfd35b6399aa5') |
||||||
|
assert.equal(tokenRate, 0.00008189274407698049) |
||||||
|
}) |
||||||
|
|
||||||
|
}) |
||||||
|
|
||||||
|
it('returns conversionRate from state', function () { |
||||||
|
assert.equal(selectors.conversionRateSelector(mockState), 556.12) |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns address book from state', function () { |
||||||
|
const addressBook = selectors.getAddressBook(mockState) |
||||||
|
assert.equal(addressBook[0].address, '0xc42edfcc21ed14dda456aa0756c153f7985d8813') |
||||||
|
assert.equal(addressBook[0].name, '') |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns accounts with balance, address, and name from identity and accounts in state', function () { |
||||||
|
const accountsWithSendEther = selectors.accountsWithSendEtherInfoSelector(mockState) |
||||||
|
assert.equal(accountsWithSendEther.length, 2) |
||||||
|
assert.equal(accountsWithSendEther[0].balance, '0x0') |
||||||
|
assert.equal(accountsWithSendEther[0].address, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') |
||||||
|
assert.equal(accountsWithSendEther[0].name, 'Test Account') |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns selected account with balance, address, and name from accountsWithSendEtherInfoSelector', function () { |
||||||
|
const currentAccountwithSendEther = selectors.getCurrentAccountWithSendEtherInfo(mockState) |
||||||
|
assert.equal(currentAccountwithSendEther.balance, '0x0') |
||||||
|
assert.equal(currentAccountwithSendEther.address, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') |
||||||
|
assert.equal(currentAccountwithSendEther.name, 'Test Account') |
||||||
|
}) |
||||||
|
|
||||||
|
describe('#transactionSelector', function () { |
||||||
|
it('returns transactions from state', function () { |
||||||
|
selectors.transactionsSelector(mockState) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
it('#getGasIsLoading', () => { |
||||||
|
const gasIsLoading = selectors.getGasIsLoading(mockState) |
||||||
|
assert.equal(gasIsLoading, false) |
||||||
|
}) |
||||||
|
|
||||||
|
describe('Send From', () => { |
||||||
|
it('#getSendFrom', () => { |
||||||
|
const sendFrom = selectors.getSendFrom(mockState) |
||||||
|
assert.equal(sendFrom, '0xc42edfcc21ed14dda456aa0756c153f7985d8813') |
||||||
|
}) |
||||||
|
|
||||||
|
it('#getForceGasMin', () => { |
||||||
|
const forceGasMin = selectors.getForceGasMin(mockState) |
||||||
|
assert.equal(forceGasMin, null) |
||||||
|
}) |
||||||
|
|
||||||
|
it('#getSendAmount', () => { |
||||||
|
const sendAmount = selectors.getSendAmount(mockState) |
||||||
|
assert.equal(sendAmount, '1bc16d674ec80000') |
||||||
|
}) |
||||||
|
|
||||||
|
it('#getSendMaxModeState', () => { |
||||||
|
const sendMaxModeState = selectors.getSendMaxModeState(mockState) |
||||||
|
assert.equal(sendMaxModeState, false) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
it('#getCurrentCurrency', () => { |
||||||
|
const currentCurrency = selectors.getCurrentCurrency(mockState) |
||||||
|
assert.equal(currentCurrency, 'usd') |
||||||
|
}) |
||||||
|
|
||||||
|
it('#getSelectedTokenToFiatRate', () => { |
||||||
|
const selectedTokenToFiatRate = selectors.getSelectedTokenToFiatRate(mockState) |
||||||
|
assert.equal(selectedTokenToFiatRate, '0.21880988420033493') |
||||||
|
}) |
||||||
|
|
||||||
|
describe('#getSelectedTokenContract', () => { |
||||||
|
|
||||||
|
beforeEach(() => { |
||||||
|
global.eth = new Eth(provider) |
||||||
|
}) |
||||||
|
|
||||||
|
it('', () => { |
||||||
|
const selectedTokenContract = selectors.getSelectedTokenContract(mockState) |
||||||
|
assert(selectedTokenContract.abi) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
it('#getCurrentViewContext', () => { |
||||||
|
const currentViewContext = selectors.getCurrentViewContext(mockState) |
||||||
|
assert.equal(currentViewContext, '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc') |
||||||
|
}) |
||||||
|
|
||||||
|
it('#getTotalUnapprovedCount', () => { |
||||||
|
const totalUnapprovedCount = selectors.getTotalUnapprovedCount(mockState) |
||||||
|
assert.equal(totalUnapprovedCount, 1) |
||||||
|
}) |
||||||
|
}) |
@ -0,0 +1,26 @@ |
|||||||
|
const assert = require('assert') |
||||||
|
const etherscanNetworkPrefix = require('../../../ui/lib/etherscan-prefix-for-network') |
||||||
|
|
||||||
|
describe('Etherscan Network Prefix', () => { |
||||||
|
|
||||||
|
it('returns empy string as default value', () => { |
||||||
|
assert.equal(etherscanNetworkPrefix(), '') |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns empty string as a prefix for networkId of 1', () => { |
||||||
|
assert.equal(etherscanNetworkPrefix(1), '') |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns ropsten as prefix for networkId of 3', () => { |
||||||
|
assert.equal(etherscanNetworkPrefix(3), 'ropsten.') |
||||||
|
}) |
||||||
|
|
||||||
|
it('returns rinkeby as prefix for networkId of 4', () => { |
||||||
|
assert.equal(etherscanNetworkPrefix(4), 'rinkeby.') |
||||||
|
}) |
||||||
|
|
||||||
|
it('returs kovan as prefix for networkId of 42', () => { |
||||||
|
assert.equal(etherscanNetworkPrefix(42), 'kovan.') |
||||||
|
}) |
||||||
|
|
||||||
|
}) |
@ -1,33 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
// Main Views
|
|
||||||
const TxView = require('./components/tx-view') |
|
||||||
const WalletView = require('./components/wallet-view') |
|
||||||
|
|
||||||
module.exports = AccountAndTransactionDetails |
|
||||||
|
|
||||||
inherits(AccountAndTransactionDetails, Component) |
|
||||||
function AccountAndTransactionDetails () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
AccountAndTransactionDetails.prototype.render = function () { |
|
||||||
return h('div.account-and-transaction-details', [ |
|
||||||
// wallet
|
|
||||||
h(WalletView, { |
|
||||||
style: { |
|
||||||
}, |
|
||||||
responsiveDisplayClassname: '.lap-visible', |
|
||||||
}, [ |
|
||||||
]), |
|
||||||
|
|
||||||
// transaction
|
|
||||||
h(TxView, { |
|
||||||
style: { |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
]), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
@ -1,267 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const PropTypes = require('prop-types') |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const actions = require('../actions') |
|
||||||
const CoinbaseForm = require('./coinbase-form') |
|
||||||
const ShapeshiftForm = require('./shapeshift-form') |
|
||||||
const Loading = require('./loading-screen') |
|
||||||
const AccountPanel = require('./account-panel') |
|
||||||
const RadioList = require('./custom-radio-list') |
|
||||||
const { getNetworkDisplayName } = require('../../../app/scripts/controllers/network/util') |
|
||||||
|
|
||||||
BuyButtonSubview.contextTypes = { |
|
||||||
t: PropTypes.func, |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(BuyButtonSubview) |
|
||||||
|
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
identity: state.appState.identity, |
|
||||||
account: state.metamask.accounts[state.appState.buyView.buyAddress], |
|
||||||
warning: state.appState.warning, |
|
||||||
buyView: state.appState.buyView, |
|
||||||
network: state.metamask.network, |
|
||||||
provider: state.metamask.provider, |
|
||||||
context: state.appState.currentView.context, |
|
||||||
isSubLoading: state.appState.isSubLoading, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(BuyButtonSubview, Component) |
|
||||||
function BuyButtonSubview () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
BuyButtonSubview.prototype.render = function () { |
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
this.headerSubview(), |
|
||||||
this.primarySubview(), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
BuyButtonSubview.prototype.headerSubview = function () { |
|
||||||
const props = this.props |
|
||||||
const isLoading = props.isSubLoading |
|
||||||
return ( |
|
||||||
|
|
||||||
h('.flex-column', { |
|
||||||
style: { |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// header bar (back button, label)
|
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
alignItems: 'center', |
|
||||||
justifyContent: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', { |
|
||||||
onClick: this.backButtonContext.bind(this), |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
left: '10px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('h2.text-transform-uppercase.flex-center', { |
|
||||||
style: { |
|
||||||
width: '100vw', |
|
||||||
background: 'rgb(235, 235, 235)', |
|
||||||
color: 'rgb(174, 174, 174)', |
|
||||||
paddingTop: '4px', |
|
||||||
paddingBottom: '4px', |
|
||||||
}, |
|
||||||
}, this.context.t('depositEth')), |
|
||||||
]), |
|
||||||
|
|
||||||
// loading indication
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
top: '57vh', |
|
||||||
left: '49vw', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
isLoading && h(Loading), |
|
||||||
]), |
|
||||||
|
|
||||||
// account panel
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
width: '80%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(AccountPanel, { |
|
||||||
showFullAddress: true, |
|
||||||
identity: props.identity, |
|
||||||
account: props.account, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
alignItems: 'center', |
|
||||||
justifyContent: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('h3.text-transform-uppercase.flex-center', { |
|
||||||
style: { |
|
||||||
paddingLeft: '15px', |
|
||||||
width: '100vw', |
|
||||||
background: 'rgb(235, 235, 235)', |
|
||||||
color: 'rgb(174, 174, 174)', |
|
||||||
paddingTop: '4px', |
|
||||||
paddingBottom: '4px', |
|
||||||
}, |
|
||||||
}, this.context.t('selectService')), |
|
||||||
]), |
|
||||||
|
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
BuyButtonSubview.prototype.primarySubview = function () { |
|
||||||
const props = this.props |
|
||||||
const network = props.network |
|
||||||
|
|
||||||
switch (network) { |
|
||||||
case 'loading': |
|
||||||
return |
|
||||||
|
|
||||||
case '1': |
|
||||||
return this.mainnetSubview() |
|
||||||
|
|
||||||
// Ropsten, Rinkeby, Kovan
|
|
||||||
case '3': |
|
||||||
case '4': |
|
||||||
case '42': |
|
||||||
const networkName = getNetworkDisplayName(network) |
|
||||||
const label = `${networkName} ${this.context.t('testFaucet')}` |
|
||||||
return ( |
|
||||||
h('div.flex-column', { |
|
||||||
style: { |
|
||||||
alignItems: 'center', |
|
||||||
margin: '20px 50px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('button.text-transform-uppercase', { |
|
||||||
onClick: () => this.props.dispatch(actions.buyEth({ network })), |
|
||||||
style: { |
|
||||||
marginTop: '15px', |
|
||||||
}, |
|
||||||
}, label), |
|
||||||
// Kovan only: Dharma loans beta
|
|
||||||
network === '42' ? ( |
|
||||||
h('button.text-transform-uppercase', { |
|
||||||
onClick: () => this.navigateTo('https://borrow.dharma.io/'), |
|
||||||
style: { |
|
||||||
marginTop: '15px', |
|
||||||
}, |
|
||||||
}, this.context.t('borrowDharma')) |
|
||||||
) : null, |
|
||||||
]) |
|
||||||
) |
|
||||||
|
|
||||||
default: |
|
||||||
return ( |
|
||||||
h('h2.error', this.context.t('unknownNetworkId')) |
|
||||||
) |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
BuyButtonSubview.prototype.mainnetSubview = function () { |
|
||||||
const props = this.props |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.flex-column', { |
|
||||||
style: { |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('.flex-row.selected-exchange', { |
|
||||||
style: { |
|
||||||
position: 'relative', |
|
||||||
right: '35px', |
|
||||||
marginTop: '20px', |
|
||||||
marginBottom: '20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(RadioList, { |
|
||||||
defaultFocus: props.buyView.subview, |
|
||||||
labels: [ |
|
||||||
'Coinbase', |
|
||||||
'ShapeShift', |
|
||||||
], |
|
||||||
subtext: { |
|
||||||
'Coinbase': `${this.context.t('crypto')}/${this.context.t('fiat')} (${this.context.t('usaOnly')})`, |
|
||||||
'ShapeShift': this.context.t('crypto'), |
|
||||||
}, |
|
||||||
onClick: this.radioHandler.bind(this), |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
h('h3.text-transform-uppercase', { |
|
||||||
style: { |
|
||||||
paddingLeft: '15px', |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
width: '100vw', |
|
||||||
background: 'rgb(235, 235, 235)', |
|
||||||
color: 'rgb(174, 174, 174)', |
|
||||||
paddingTop: '4px', |
|
||||||
paddingBottom: '4px', |
|
||||||
}, |
|
||||||
}, props.buyView.subview), |
|
||||||
|
|
||||||
this.formVersionSubview(), |
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
BuyButtonSubview.prototype.formVersionSubview = function () { |
|
||||||
const network = this.props.network |
|
||||||
if (network === '1') { |
|
||||||
if (this.props.buyView.formView.coinbase) { |
|
||||||
return h(CoinbaseForm, this.props) |
|
||||||
} else if (this.props.buyView.formView.shapeshift) { |
|
||||||
return h(ShapeshiftForm, this.props) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
BuyButtonSubview.prototype.navigateTo = function (url) { |
|
||||||
global.platform.openWindow({ url }) |
|
||||||
} |
|
||||||
|
|
||||||
BuyButtonSubview.prototype.backButtonContext = function () { |
|
||||||
if (this.props.context === 'confTx') { |
|
||||||
this.props.dispatch(actions.showConfTxPage({transForward: false})) |
|
||||||
} else { |
|
||||||
this.props.dispatch(actions.goHome()) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
BuyButtonSubview.prototype.radioHandler = function (event) { |
|
||||||
switch (event.target.title) { |
|
||||||
case 'Coinbase': |
|
||||||
return this.props.dispatch(actions.coinBaseSubview()) |
|
||||||
case 'ShapeShift': |
|
||||||
return this.props.dispatch(actions.shapeShiftSubview(this.props.provider.type)) |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,25 @@ |
|||||||
|
import React, { PureComponent } from 'react' |
||||||
|
import PropTypes from 'prop-types' |
||||||
|
import classnames from 'classnames' |
||||||
|
|
||||||
|
export default class Card extends PureComponent { |
||||||
|
static propTypes = { |
||||||
|
className: PropTypes.string, |
||||||
|
overrideClassName: PropTypes.bool, |
||||||
|
title: PropTypes.string, |
||||||
|
children: PropTypes.node, |
||||||
|
} |
||||||
|
|
||||||
|
render () { |
||||||
|
const { className, overrideClassName, title } = this.props |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className={classnames({ 'card': !overrideClassName }, className)}> |
||||||
|
<div className="card__title"> |
||||||
|
{ title } |
||||||
|
</div> |
||||||
|
{ this.props.children } |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
export { default } from './card.component' |
@ -0,0 +1,11 @@ |
|||||||
|
.card { |
||||||
|
border-radius: 4px; |
||||||
|
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.08); |
||||||
|
padding: 8px; |
||||||
|
|
||||||
|
&__title { |
||||||
|
border-bottom: 1px solid #d8d8d8; |
||||||
|
padding-bottom: 4px; |
||||||
|
text-transform: capitalize; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
import React from 'react' |
||||||
|
import assert from 'assert' |
||||||
|
import { shallow } from 'enzyme' |
||||||
|
import Card from '../card.component' |
||||||
|
|
||||||
|
describe('Card Component', () => { |
||||||
|
it('should render a card with a title and child element', () => { |
||||||
|
const wrapper = shallow( |
||||||
|
<Card |
||||||
|
title="Test" |
||||||
|
className="card-test-class" |
||||||
|
> |
||||||
|
<div className="child-test-class">Child</div> |
||||||
|
</Card> |
||||||
|
) |
||||||
|
|
||||||
|
assert.ok(wrapper.hasClass('card-test-class')) |
||||||
|
const title = wrapper.find('.card__title') |
||||||
|
assert.ok(title) |
||||||
|
assert.equal(title.text(), 'Test') |
||||||
|
const child = wrapper.find('.child-test-class') |
||||||
|
assert.ok(child) |
||||||
|
assert.equal(child.text(), 'Child') |
||||||
|
}) |
||||||
|
}) |
@ -1 +0,0 @@ |
|||||||
export { default } from './confirm-page-container-error.component' |
|
@ -1,4 +1,3 @@ |
|||||||
export { default } from './confirm-page-container-content.component' |
export { default } from './confirm-page-container-content.component' |
||||||
export { default as ConfirmPageContainerSummary } from './confirm-page-container-summary' |
export { default as ConfirmPageContainerSummary } from './confirm-page-container-summary' |
||||||
export { default as ConfirmPageContainerError } from './confirm-page-container-error' |
|
||||||
export { default as ConfirmPageContainerWarning } from './confirm-page-container-warning' |
export { default as ConfirmPageContainerWarning } from './confirm-page-container-warning' |
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue