Merge pull request #6166 from whymarrh/bye-bye-old-ui
Delete the old UIfeature/default_network_editable
@ -1,6 +0,0 @@ |
|||||||
# Running UI Dev Mode |
|
||||||
|
|
||||||
You can run `npm run ui`, and your browser should open a live-reloading demo version of the plugin UI. |
|
||||||
|
|
||||||
Some actions will crash the app, so this is only for tuning aesthetics, but it allows live-reloading styles, which is a much faster feedback loop than reloading the full extension. |
|
||||||
|
|
@ -1,8 +0,0 @@ |
|||||||
### Developing on UI with Mocked Background Process |
|
||||||
|
|
||||||
You can run `npm run mock` and your browser should open a live-reloading demo version of the plugin UI, just like the `npm run ui`, except that it tries to actually perform all normal operations. |
|
||||||
|
|
||||||
It does not yet connect to a real blockchain (this could be a good test feature later, connecting to a test blockchain), so only local operations work. |
|
||||||
|
|
||||||
You can reset the mock ui at any time with the `Reset` button at the top of the screen. |
|
||||||
|
|
@ -1,66 +0,0 @@ |
|||||||
|
|
||||||
# Created by https://www.gitignore.io/api/osx,node |
|
||||||
|
|
||||||
### OSX ### |
|
||||||
.DS_Store |
|
||||||
.AppleDouble |
|
||||||
.LSOverride |
|
||||||
|
|
||||||
# Icon must end with two \r |
|
||||||
Icon
|
|
||||||
|
|
||||||
# Thumbnails |
|
||||||
._* |
|
||||||
|
|
||||||
# Files that might appear in the root of a volume |
|
||||||
.DocumentRevisions-V100 |
|
||||||
.fseventsd |
|
||||||
.Spotlight-V100 |
|
||||||
.TemporaryItems |
|
||||||
.Trashes |
|
||||||
.VolumeIcon.icns |
|
||||||
|
|
||||||
# Directories potentially created on remote AFP share |
|
||||||
.AppleDB |
|
||||||
.AppleDesktop |
|
||||||
Network Trash Folder |
|
||||||
Temporary Items |
|
||||||
.apdisk |
|
||||||
|
|
||||||
|
|
||||||
### Node ### |
|
||||||
# Logs |
|
||||||
logs |
|
||||||
*.log |
|
||||||
npm-debug.log* |
|
||||||
|
|
||||||
# Runtime data |
|
||||||
pids |
|
||||||
*.pid |
|
||||||
*.seed |
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover |
|
||||||
lib-cov |
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul |
|
||||||
coverage |
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) |
|
||||||
.grunt |
|
||||||
|
|
||||||
# node-waf configuration |
|
||||||
.lock-wscript |
|
||||||
|
|
||||||
# Compiled binary addons (http://nodejs.org/api/addons.html) |
|
||||||
build/Release |
|
||||||
|
|
||||||
# Dependency directory |
|
||||||
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git |
|
||||||
node_modules |
|
||||||
|
|
||||||
# Optional npm cache directory |
|
||||||
.npm |
|
||||||
|
|
||||||
# Optional REPL history |
|
||||||
.node_repl_history |
|
||||||
|
|
@ -1,297 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const extend = require('xtend') |
|
||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const actions = require('../../ui/app/actions') |
|
||||||
const valuesFor = require('./util').valuesFor |
|
||||||
const Identicon = require('./components/identicon') |
|
||||||
const EthBalance = require('./components/eth-balance') |
|
||||||
const TransactionList = require('./components/transaction-list') |
|
||||||
const ExportAccountView = require('./components/account-export') |
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const EditableLabel = require('./components/editable-label') |
|
||||||
const TabBar = require('./components/tab-bar') |
|
||||||
const TokenList = require('./components/token-list') |
|
||||||
const AccountDropdowns = require('./components/account-dropdowns').AccountDropdowns |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(AccountDetailScreen) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
metamask: state.metamask, |
|
||||||
identities: state.metamask.identities, |
|
||||||
accounts: state.metamask.accounts, |
|
||||||
address: state.metamask.selectedAddress, |
|
||||||
accountDetail: state.appState.accountDetail, |
|
||||||
network: state.metamask.network, |
|
||||||
unapprovedMsgs: valuesFor(state.metamask.unapprovedMsgs), |
|
||||||
shapeShiftTxList: state.metamask.shapeShiftTxList, |
|
||||||
transactions: state.metamask.selectedAddressTxList || [], |
|
||||||
conversionRate: state.metamask.conversionRate, |
|
||||||
currentCurrency: state.metamask.currentCurrency, |
|
||||||
currentAccountTab: state.metamask.currentAccountTab, |
|
||||||
tokens: state.metamask.tokens, |
|
||||||
suggestedTokens: state.metamask.suggestedTokens, |
|
||||||
computedBalances: state.metamask.computedBalances, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(AccountDetailScreen, Component) |
|
||||||
function AccountDetailScreen () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
AccountDetailScreen.prototype.render = function () { |
|
||||||
var props = this.props |
|
||||||
var selected = props.address || Object.keys(props.accounts)[0] |
|
||||||
var checksumAddress = selected && ethUtil.toChecksumAddress(selected) |
|
||||||
var identity = props.identities[selected] |
|
||||||
var account = props.accounts[selected] |
|
||||||
const { network, conversionRate, currentCurrency } = props |
|
||||||
|
|
||||||
if (Object.keys(props.suggestedTokens).length > 0) { |
|
||||||
this.props.dispatch(actions.showAddSuggestedTokenPage()) |
|
||||||
} |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.account-detail-section.full-flex-height', [ |
|
||||||
|
|
||||||
// identicon, label, balance, etc
|
|
||||||
h('.account-data-subsection', { |
|
||||||
style: { |
|
||||||
margin: '0 20px', |
|
||||||
flex: '1 0 auto', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// header - identicon + nav
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
paddingTop: '20px', |
|
||||||
display: 'flex', |
|
||||||
justifyContent: 'flex-start', |
|
||||||
alignItems: 'flex-start', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// large identicon and addresses
|
|
||||||
h('.identicon-wrapper.select-none', [ |
|
||||||
h(Identicon, { |
|
||||||
diameter: 62, |
|
||||||
address: selected, |
|
||||||
}), |
|
||||||
]), |
|
||||||
h('flex-column', { |
|
||||||
style: { |
|
||||||
lineHeight: '10px', |
|
||||||
marginLeft: '15px', |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(EditableLabel, { |
|
||||||
textValue: identity ? identity.name : '', |
|
||||||
state: { |
|
||||||
isEditingLabel: false, |
|
||||||
}, |
|
||||||
saveText: (text) => { |
|
||||||
props.dispatch(actions.setAccountLabel(selected, text)) |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// What is shown when not editing + edit text:
|
|
||||||
h('label.editing-label', [h('.edit-text', 'edit')]), |
|
||||||
h( |
|
||||||
'div', |
|
||||||
{ |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
justifyContent: 'flex-start', |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, |
|
||||||
[ |
|
||||||
h( |
|
||||||
'div.font-medium.color-forest', |
|
||||||
{ |
|
||||||
name: 'edit', |
|
||||||
style: { |
|
||||||
}, |
|
||||||
}, |
|
||||||
[ |
|
||||||
h('h2', { |
|
||||||
style: { |
|
||||||
maxWidth: '180px', |
|
||||||
overflow: 'hidden', |
|
||||||
textOverflow: 'ellipsis', |
|
||||||
padding: '5px 0px', |
|
||||||
lineHeight: '25px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
identity && identity.name, |
|
||||||
]), |
|
||||||
] |
|
||||||
), |
|
||||||
h( |
|
||||||
AccountDropdowns, |
|
||||||
{ |
|
||||||
style: { |
|
||||||
marginRight: '8px', |
|
||||||
marginLeft: 'auto', |
|
||||||
cursor: 'pointer', |
|
||||||
}, |
|
||||||
selected, |
|
||||||
network, |
|
||||||
identities: props.identities, |
|
||||||
enableAccountOptions: true, |
|
||||||
}, |
|
||||||
), |
|
||||||
] |
|
||||||
), |
|
||||||
]), |
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
width: '15em', |
|
||||||
justifyContent: 'space-between', |
|
||||||
alignItems: 'baseline', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// address
|
|
||||||
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
overflow: 'hidden', |
|
||||||
textOverflow: 'ellipsis', |
|
||||||
paddingTop: '3px', |
|
||||||
width: '5em', |
|
||||||
height: '15px', |
|
||||||
fontSize: '13px', |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
textRendering: 'geometricPrecision', |
|
||||||
marginBottom: '15px', |
|
||||||
color: '#AEAEAE', |
|
||||||
}, |
|
||||||
}, checksumAddress), |
|
||||||
]), |
|
||||||
|
|
||||||
// account ballence
|
|
||||||
|
|
||||||
]), |
|
||||||
]), |
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
justifyContent: 'space-between', |
|
||||||
alignItems: 'flex-start', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h(EthBalance, { |
|
||||||
value: account && account.balance, |
|
||||||
conversionRate, |
|
||||||
currentCurrency, |
|
||||||
style: { |
|
||||||
lineHeight: '7px', |
|
||||||
marginTop: '10px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
h('.flex-grow'), |
|
||||||
|
|
||||||
h('button', { |
|
||||||
onClick: () => props.dispatch(actions.buyEthView(selected)), |
|
||||||
style: { marginRight: '10px' }, |
|
||||||
}, 'BUY'), |
|
||||||
|
|
||||||
h('button', { |
|
||||||
onClick: () => props.dispatch(actions.showSendPage()), |
|
||||||
style: { |
|
||||||
marginBottom: '20px', |
|
||||||
marginRight: '8px', |
|
||||||
}, |
|
||||||
}, 'SEND'), |
|
||||||
|
|
||||||
]), |
|
||||||
]), |
|
||||||
|
|
||||||
// subview (tx history, pk export confirm, buy eth warning)
|
|
||||||
this.subview(), |
|
||||||
|
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
AccountDetailScreen.prototype.subview = function () { |
|
||||||
var subview |
|
||||||
try { |
|
||||||
subview = this.props.accountDetail.subview |
|
||||||
} catch (e) { |
|
||||||
subview = null |
|
||||||
} |
|
||||||
|
|
||||||
switch (subview) { |
|
||||||
case 'transactions': |
|
||||||
return this.tabSections() |
|
||||||
case 'export': |
|
||||||
var state = extend({key: 'export'}, this.props) |
|
||||||
return h(ExportAccountView, state) |
|
||||||
default: |
|
||||||
return this.tabSections() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
AccountDetailScreen.prototype.tabSections = function () { |
|
||||||
const { currentAccountTab } = this.props |
|
||||||
|
|
||||||
return h('section.tabSection.full-flex-height.grow-tenx', [ |
|
||||||
|
|
||||||
h(TabBar, { |
|
||||||
tabs: [ |
|
||||||
{ content: 'Sent', key: 'history' }, |
|
||||||
{ content: 'Tokens', key: 'tokens' }, |
|
||||||
], |
|
||||||
defaultTab: currentAccountTab || 'history', |
|
||||||
tabSelected: (key) => { |
|
||||||
this.props.dispatch(actions.setCurrentAccountTab(key)) |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
this.tabSwitchView(), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
AccountDetailScreen.prototype.tabSwitchView = function () { |
|
||||||
const props = this.props |
|
||||||
const { address, network } = props |
|
||||||
const { currentAccountTab, tokens } = this.props |
|
||||||
|
|
||||||
switch (currentAccountTab) { |
|
||||||
case 'tokens': |
|
||||||
return h(TokenList, { |
|
||||||
userAddress: address, |
|
||||||
network, |
|
||||||
tokens, |
|
||||||
addToken: () => this.props.dispatch(actions.showAddTokenPage()), |
|
||||||
}) |
|
||||||
default: |
|
||||||
return this.transactionList() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
AccountDetailScreen.prototype.transactionList = function () { |
|
||||||
const {transactions, unapprovedMsgs, address, |
|
||||||
network, shapeShiftTxList, conversionRate } = this.props |
|
||||||
|
|
||||||
return h(TransactionList, { |
|
||||||
transactions: transactions.sort((a, b) => b.time - a.time), |
|
||||||
network, |
|
||||||
unapprovedMsgs, |
|
||||||
conversionRate, |
|
||||||
address, |
|
||||||
shapeShiftTxList, |
|
||||||
viewPendingTx: (txId) => { |
|
||||||
this.props.dispatch(actions.viewPendingTx(txId)) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
@ -1,86 +0,0 @@ |
|||||||
const PropTypes = require('prop-types') |
|
||||||
const {PureComponent} = require('react') |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const {qrcode: qrCode} = require('qrcode-npm') |
|
||||||
const {connect} = require('react-redux') |
|
||||||
const {isHexPrefixed} = require('ethereumjs-util') |
|
||||||
const actions = require('../../ui/app/actions') |
|
||||||
const CopyButton = require('./components/copyButton') |
|
||||||
|
|
||||||
class AccountQrScreen extends PureComponent { |
|
||||||
static defaultProps = { |
|
||||||
warning: null, |
|
||||||
} |
|
||||||
|
|
||||||
static propTypes = { |
|
||||||
dispatch: PropTypes.func.isRequired, |
|
||||||
buyView: PropTypes.any.isRequired, |
|
||||||
Qr: PropTypes.object.isRequired, |
|
||||||
selectedAddress: PropTypes.string.isRequired, |
|
||||||
warning: PropTypes.node, |
|
||||||
} |
|
||||||
|
|
||||||
render () { |
|
||||||
const {dispatch, Qr, selectedAddress, warning} = this.props |
|
||||||
const address = `${isHexPrefixed(Qr.data) ? 'ethereum:' : ''}${Qr.data}` |
|
||||||
const qrImage = qrCode(4, 'M') |
|
||||||
|
|
||||||
qrImage.addData(address) |
|
||||||
qrImage.make() |
|
||||||
|
|
||||||
return h('div.flex-column.full-width', { |
|
||||||
style: { |
|
||||||
alignItems: 'center', |
|
||||||
boxSizing: 'border-box', |
|
||||||
padding: '50px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('div.flex-row.full-width', { |
|
||||||
style: { |
|
||||||
alignItems: 'flex-start', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', { |
|
||||||
onClick () { |
|
||||||
dispatch(actions.backToAccountDetail(selectedAddress)) |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
h('div.qr-header', Qr.message), |
|
||||||
warning && h('span.error.flex-center', { |
|
||||||
style: { |
|
||||||
textAlign: 'center', |
|
||||||
width: '229px', |
|
||||||
height: '82px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
this.props.warning, |
|
||||||
]), |
|
||||||
h('div#qr-container.flex-column', { |
|
||||||
style: { |
|
||||||
marginTop: '25px', |
|
||||||
marginBottom: '15px', |
|
||||||
}, |
|
||||||
dangerouslySetInnerHTML: { |
|
||||||
__html: qrImage.createTableTag(4), |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('div.flex-row.full-width', [ |
|
||||||
h('h3.ellip-address.grow-tenx', Qr.data), |
|
||||||
h(CopyButton, { |
|
||||||
value: Qr.data, |
|
||||||
}), |
|
||||||
]), |
|
||||||
]) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
Qr: state.appState.Qr, |
|
||||||
buyView: state.appState.buyView, |
|
||||||
warning: state.appState.warning, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(AccountQrScreen) |
|
@ -1,119 +0,0 @@ |
|||||||
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') |
|
||||||
import Select from 'react-select' |
|
||||||
|
|
||||||
// Subviews
|
|
||||||
const JsonImportView = require('./json.js') |
|
||||||
const PrivateKeyImportView = require('./private-key.js') |
|
||||||
|
|
||||||
const menuItems = [ |
|
||||||
'Private Key', |
|
||||||
'JSON File', |
|
||||||
] |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(AccountImportSubview) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
menuItems, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(AccountImportSubview, Component) |
|
||||||
function AccountImportSubview () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
AccountImportSubview.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const state = this.state || {} |
|
||||||
const { menuItems } = props |
|
||||||
const { type } = state |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div', [ |
|
||||||
h('.section-title.flex-row.flex-center', [ |
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { |
|
||||||
onClick: (event) => { |
|
||||||
props.dispatch(actions.goHome()) |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('h2.page-subtitle', 'Import Accounts'), |
|
||||||
]), |
|
||||||
h('.error', { |
|
||||||
style: { |
|
||||||
display: 'inline-block', |
|
||||||
alignItems: 'center', |
|
||||||
padding: '5px 15px 0px 15px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('span', 'Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts '), |
|
||||||
h('span', { |
|
||||||
style: { |
|
||||||
color: 'rgba(247, 134, 28, 1)', |
|
||||||
cursor: 'pointer', |
|
||||||
textDecoration: 'underline', |
|
||||||
}, |
|
||||||
onClick: () => { |
|
||||||
global.platform.openWindow({ |
|
||||||
url: 'https://metamask.zendesk.com/hc/en-us/articles/360015289592-What-Are-Loose-Accounts-', |
|
||||||
}) |
|
||||||
}, |
|
||||||
}, 'here.'), |
|
||||||
]), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
padding: '10px', |
|
||||||
color: 'rgb(174, 174, 174)', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('h3', { style: { padding: '3px' } }, 'SELECT TYPE'), |
|
||||||
|
|
||||||
h('style', ` |
|
||||||
.has-value.Select--single > .Select-control .Select-value .Select-value-label, .Select-value-label { |
|
||||||
color: rgb(174,174,174); |
|
||||||
} |
|
||||||
`),
|
|
||||||
|
|
||||||
h(Select, { |
|
||||||
name: 'import-type-select', |
|
||||||
clearable: false, |
|
||||||
value: type || menuItems[0], |
|
||||||
options: menuItems.map((type) => { |
|
||||||
return { |
|
||||||
value: type, |
|
||||||
label: type, |
|
||||||
} |
|
||||||
}), |
|
||||||
onChange: (opt) => { |
|
||||||
props.dispatch(actions.showImportPage()) |
|
||||||
this.setState({ type: opt.value }) |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
this.renderImportView(), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
AccountImportSubview.prototype.renderImportView = function () { |
|
||||||
const props = this.props |
|
||||||
const state = this.state || {} |
|
||||||
const { type } = state |
|
||||||
const { menuItems } = props |
|
||||||
const current = type || menuItems[0] |
|
||||||
|
|
||||||
switch (current) { |
|
||||||
case 'Private Key': |
|
||||||
return h(PrivateKeyImportView) |
|
||||||
case 'JSON File': |
|
||||||
return h(JsonImportView) |
|
||||||
default: |
|
||||||
return h(JsonImportView) |
|
||||||
} |
|
||||||
} |
|
@ -1,124 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const actions = require('../../../../ui/app/actions') |
|
||||||
const FileInput = require('react-simple-file-input').default |
|
||||||
const PropTypes = require('prop-types') |
|
||||||
|
|
||||||
const HELP_LINK = 'https://github.com/MetaMask/faq/blob/master/README.md#q-i-cant-use-the-import-feature-for-uploading-a-json-file-the-window-keeps-closing-when-i-try-to-select-a-file' |
|
||||||
|
|
||||||
class JsonImportSubview extends Component { |
|
||||||
constructor (props) { |
|
||||||
super(props) |
|
||||||
|
|
||||||
this.state = { |
|
||||||
file: null, |
|
||||||
fileContents: '', |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
render () { |
|
||||||
const { error } = this.props |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
flexDirection: 'column', |
|
||||||
alignItems: 'center', |
|
||||||
padding: '5px 15px 0px 15px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('p', 'Used by a variety of different clients'), |
|
||||||
h('a.warning', { |
|
||||||
href: HELP_LINK, |
|
||||||
target: '_blank', |
|
||||||
}, 'File import not working? Click here!'), |
|
||||||
|
|
||||||
h(FileInput, { |
|
||||||
readAs: 'text', |
|
||||||
onLoad: this.onLoad.bind(this), |
|
||||||
style: { |
|
||||||
margin: '20px 0px 12px 20px', |
|
||||||
fontSize: '15px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
h('input.large-input.letter-spacey', { |
|
||||||
type: 'password', |
|
||||||
placeholder: 'Enter password', |
|
||||||
id: 'json-password-box', |
|
||||||
onKeyPress: this.createKeyringOnEnter.bind(this), |
|
||||||
style: { |
|
||||||
width: 260, |
|
||||||
marginTop: 12, |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
h('button.primary', { |
|
||||||
onClick: this.createNewKeychain.bind(this), |
|
||||||
style: { |
|
||||||
margin: 12, |
|
||||||
}, |
|
||||||
}, 'Import'), |
|
||||||
|
|
||||||
error ? h('span.error', error) : null, |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
onLoad (event, file) { |
|
||||||
this.setState({file: file, fileContents: event.target.result}) |
|
||||||
} |
|
||||||
|
|
||||||
createKeyringOnEnter (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
event.preventDefault() |
|
||||||
this.createNewKeychain() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
createNewKeychain () { |
|
||||||
const { fileContents } = this.state |
|
||||||
|
|
||||||
if (!fileContents) { |
|
||||||
const message = 'You must select a file to import.' |
|
||||||
return this.props.displayWarning(message) |
|
||||||
} |
|
||||||
|
|
||||||
const passwordInput = document.getElementById('json-password-box') |
|
||||||
const password = passwordInput.value |
|
||||||
|
|
||||||
if (!password) { |
|
||||||
const message = 'You must enter a password for the selected file.' |
|
||||||
return this.props.displayWarning(message) |
|
||||||
} |
|
||||||
|
|
||||||
this.props.importNewAccount([ fileContents, password ]) |
|
||||||
// JS runtime requires caught rejections but failures are handled by Redux
|
|
||||||
.catch() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
JsonImportSubview.propTypes = { |
|
||||||
error: PropTypes.string, |
|
||||||
displayWarning: PropTypes.func, |
|
||||||
importNewAccount: PropTypes.func, |
|
||||||
} |
|
||||||
|
|
||||||
const mapStateToProps = state => { |
|
||||||
return { |
|
||||||
error: state.appState.warning, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => { |
|
||||||
return { |
|
||||||
goHome: () => dispatch(actions.goHome()), |
|
||||||
displayWarning: warning => dispatch(actions.displayWarning(warning)), |
|
||||||
importNewAccount: options => dispatch(actions.importNewAccount('JSON File', options)), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(JsonImportSubview) |
|
@ -1,69 +0,0 @@ |
|||||||
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') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(PrivateKeyImportView) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
error: state.appState.warning, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(PrivateKeyImportView, Component) |
|
||||||
function PrivateKeyImportView () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
PrivateKeyImportView.prototype.render = function () { |
|
||||||
const { error } = this.props |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
flexDirection: 'column', |
|
||||||
alignItems: 'center', |
|
||||||
padding: '5px 15px 0px 15px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('span', 'Paste your private key string here'), |
|
||||||
|
|
||||||
h('input.large-input.letter-spacey', { |
|
||||||
type: 'password', |
|
||||||
id: 'private-key-box', |
|
||||||
onKeyPress: this.createKeyringOnEnter.bind(this), |
|
||||||
style: { |
|
||||||
width: 260, |
|
||||||
marginTop: 12, |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
h('button.primary', { |
|
||||||
onClick: this.createNewKeychain.bind(this), |
|
||||||
style: { |
|
||||||
margin: 12, |
|
||||||
}, |
|
||||||
}, 'Import'), |
|
||||||
|
|
||||||
error ? h('span.error', error) : null, |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
PrivateKeyImportView.prototype.createKeyringOnEnter = function (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
event.preventDefault() |
|
||||||
this.createNewKeychain() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
PrivateKeyImportView.prototype.createNewKeychain = function () { |
|
||||||
const input = document.getElementById('private-key-box') |
|
||||||
const privateKey = input.value |
|
||||||
this.props.dispatch(actions.importNewAccount('Private Key', [ privateKey ])) |
|
||||||
// JS runtime requires caught rejections but failures are handled by Redux
|
|
||||||
.catch() |
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(SeedImportSubview) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return {} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(SeedImportSubview, Component) |
|
||||||
function SeedImportSubview () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
SeedImportSubview.prototype.render = function () { |
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
`Paste your seed phrase here!`, |
|
||||||
h('textarea'), |
|
||||||
h('br'), |
|
||||||
h('button', 'Submit'), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
@ -1,202 +0,0 @@ |
|||||||
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 |
|
||||||
} |
|
@ -1,241 +0,0 @@ |
|||||||
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 abi = require('human-standard-token-abi') |
|
||||||
const Eth = require('ethjs-query') |
|
||||||
const EthContract = require('ethjs-contract') |
|
||||||
|
|
||||||
const emptyAddr = '0x0000000000000000000000000000000000000000' |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(AddTokenScreen) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
identities: state.metamask.identities, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(AddTokenScreen, Component) |
|
||||||
function AddTokenScreen () { |
|
||||||
this.state = { |
|
||||||
warning: null, |
|
||||||
address: '', |
|
||||||
symbol: 'TOKEN', |
|
||||||
decimals: 18, |
|
||||||
} |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
AddTokenScreen.prototype.render = function () { |
|
||||||
const state = this.state |
|
||||||
const props = this.props |
|
||||||
const { warning, symbol, decimals } = state |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.flex-column.flex-grow', [ |
|
||||||
|
|
||||||
// subtitle and nav
|
|
||||||
h('.section-title.flex-row.flex-center', [ |
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { |
|
||||||
onClick: (event) => { |
|
||||||
props.dispatch(actions.goHome()) |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('h2.page-subtitle', 'Add 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('section.flex-row.flex-center', [ |
|
||||||
h('input#token-address', { |
|
||||||
name: 'address', |
|
||||||
placeholder: 'Token Contract Address', |
|
||||||
onChange: this.tokenAddressDidChange.bind(this), |
|
||||||
style: { |
|
||||||
width: 'inherit', |
|
||||||
flex: '1 0 auto', |
|
||||||
height: '30px', |
|
||||||
margin: '8px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
h('div', [ |
|
||||||
h('span', { |
|
||||||
style: { fontWeight: 'bold', paddingRight: '10px'}, |
|
||||||
}, 'Token Symbol'), |
|
||||||
]), |
|
||||||
|
|
||||||
h('div', { style: {display: 'flex'} }, [ |
|
||||||
h('input#token_symbol', { |
|
||||||
placeholder: `Like "ETH"`, |
|
||||||
value: symbol, |
|
||||||
style: { |
|
||||||
width: 'inherit', |
|
||||||
flex: '1 0 auto', |
|
||||||
height: '30px', |
|
||||||
margin: '8px', |
|
||||||
}, |
|
||||||
onChange: (event) => { |
|
||||||
var element = event.target |
|
||||||
var symbol = element.value |
|
||||||
this.setState({ symbol }) |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
h('div', [ |
|
||||||
h('span', { |
|
||||||
style: { fontWeight: 'bold', paddingRight: '10px'}, |
|
||||||
}, 'Decimals of Precision'), |
|
||||||
]), |
|
||||||
|
|
||||||
h('div', { style: {display: 'flex'} }, [ |
|
||||||
h('input#token_decimals', { |
|
||||||
value: decimals, |
|
||||||
type: 'number', |
|
||||||
min: 0, |
|
||||||
max: 36, |
|
||||||
style: { |
|
||||||
width: 'inherit', |
|
||||||
flex: '1 0 auto', |
|
||||||
height: '30px', |
|
||||||
margin: '8px', |
|
||||||
}, |
|
||||||
onChange: (event) => { |
|
||||||
var element = event.target |
|
||||||
var decimals = element.value.trim() |
|
||||||
this.setState({ decimals }) |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
h('button', { |
|
||||||
style: { |
|
||||||
alignSelf: 'center', |
|
||||||
}, |
|
||||||
onClick: (event) => { |
|
||||||
const valid = this.validateInputs() |
|
||||||
if (!valid) return |
|
||||||
|
|
||||||
const { address, symbol, decimals } = this.state |
|
||||||
this.props.dispatch(actions.addToken(address.trim(), symbol.trim(), decimals)) |
|
||||||
.then(() => { |
|
||||||
this.props.dispatch(actions.goHome()) |
|
||||||
}) |
|
||||||
}, |
|
||||||
}, 'Add'), |
|
||||||
]), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
AddTokenScreen.prototype.componentWillMount = function () { |
|
||||||
if (typeof global.ethereumProvider === 'undefined') return |
|
||||||
|
|
||||||
this.eth = new Eth(global.ethereumProvider) |
|
||||||
this.contract = new EthContract(this.eth) |
|
||||||
this.TokenContract = this.contract(abi) |
|
||||||
} |
|
||||||
|
|
||||||
AddTokenScreen.prototype.tokenAddressDidChange = function (event) { |
|
||||||
const el = event.target |
|
||||||
const address = el.value.trim() |
|
||||||
if (ethUtil.isValidAddress(address) && address !== emptyAddr) { |
|
||||||
this.setState({ address }) |
|
||||||
this.attemptToAutoFillTokenParams(address) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
AddTokenScreen.prototype.validateInputs = function () { |
|
||||||
let msg = '' |
|
||||||
const state = this.state |
|
||||||
const identitiesList = Object.keys(this.props.identities) |
|
||||||
const { address, symbol, decimals } = state |
|
||||||
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 |
|
||||||
} |
|
||||||
|
|
||||||
AddTokenScreen.prototype.attemptToAutoFillTokenParams = async function (address) { |
|
||||||
const contract = this.TokenContract.at(address) |
|
||||||
|
|
||||||
const results = await Promise.all([ |
|
||||||
contract.symbol(), |
|
||||||
contract.decimals(), |
|
||||||
]) |
|
||||||
|
|
||||||
const [ symbol, decimals ] = results |
|
||||||
if (symbol && decimals) { |
|
||||||
console.log('SETTING SYMBOL AND DECIMALS', { symbol, decimals }) |
|
||||||
this.setState({ symbol: symbol[0], decimals: decimals[0].toString() }) |
|
||||||
} |
|
||||||
} |
|
@ -1,315 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const actions = require('../../ui/app/actions') |
|
||||||
const log = require('loglevel') |
|
||||||
// mascara
|
|
||||||
const FirstTime = require('../../ui/app/components/pages/first-time-flow').default |
|
||||||
// init
|
|
||||||
const InitializeMenuScreen = require('./first-time/init-menu') |
|
||||||
const NewKeyChainScreen = require('./new-keychain') |
|
||||||
// unlock
|
|
||||||
const UnlockScreen = require('./unlock') |
|
||||||
// accounts
|
|
||||||
const AccountDetailScreen = require('./account-detail') |
|
||||||
const AccountQrScreen = require('./account-qr') |
|
||||||
const SendTransactionScreen = require('./send') |
|
||||||
const ConfirmTxScreen = require('./conf-tx') |
|
||||||
// notice
|
|
||||||
const NoticeScreen = require('./components/notice') |
|
||||||
const generateLostAccountsNotice = require('../lib/lost-accounts-notice') |
|
||||||
// other views
|
|
||||||
const ConfigScreen = require('./config') |
|
||||||
const AddTokenScreen = require('./add-token') |
|
||||||
const AddSuggestedTokenScreen = require('./add-suggested-token') |
|
||||||
const Import = require('./accounts/import') |
|
||||||
const InfoScreen = require('./info') |
|
||||||
const NewUiAnnouncement = require('./new-ui-annoucement') |
|
||||||
const AppBar = require('./components/app-bar') |
|
||||||
const Loading = require('./components/loading') |
|
||||||
const BuyView = require('./components/buy-button-subview') |
|
||||||
const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete') |
|
||||||
const HDRestoreVaultScreen = require('./keychains/hd/restore-vault') |
|
||||||
const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation') |
|
||||||
const ProviderApproval = require('./provider-approval') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(App) |
|
||||||
|
|
||||||
inherits(App, Component) |
|
||||||
function App () { Component.call(this) } |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
const { |
|
||||||
identities, |
|
||||||
accounts, |
|
||||||
address, |
|
||||||
keyrings, |
|
||||||
isInitialized, |
|
||||||
noActiveNotices, |
|
||||||
seedWords, |
|
||||||
featureFlags, |
|
||||||
providerRequests, |
|
||||||
} = state.metamask |
|
||||||
const selected = address || Object.keys(accounts)[0] |
|
||||||
|
|
||||||
return { |
|
||||||
// state from plugin
|
|
||||||
isLoading: state.appState.isLoading, |
|
||||||
loadingMessage: state.appState.loadingMessage, |
|
||||||
noActiveNotices: state.metamask.noActiveNotices, |
|
||||||
isInitialized: state.metamask.isInitialized, |
|
||||||
isUnlocked: state.metamask.isUnlocked, |
|
||||||
currentView: state.appState.currentView, |
|
||||||
selectedAddress: state.metamask.selectedAddress, |
|
||||||
transForward: state.appState.transForward, |
|
||||||
isMascara: state.metamask.isMascara, |
|
||||||
isOnboarding: Boolean(!noActiveNotices || seedWords || !isInitialized), |
|
||||||
seedWords: state.metamask.seedWords, |
|
||||||
unapprovedTxs: state.metamask.unapprovedTxs, |
|
||||||
unapprovedMsgs: state.metamask.unapprovedMsgs, |
|
||||||
menuOpen: state.appState.menuOpen, |
|
||||||
network: state.metamask.network, |
|
||||||
provider: state.metamask.provider, |
|
||||||
forgottenPassword: state.appState.forgottenPassword, |
|
||||||
nextUnreadNotice: state.metamask.nextUnreadNotice, |
|
||||||
lostAccounts: state.metamask.lostAccounts, |
|
||||||
frequentRpcListDetail: state.metamask.frequentRpcListDetail || [], |
|
||||||
featureFlags, |
|
||||||
providerRequests, |
|
||||||
suggestedTokens: state.metamask.suggestedTokens, |
|
||||||
|
|
||||||
// state needed to get account dropdown temporarily rendering from app bar
|
|
||||||
identities, |
|
||||||
selected, |
|
||||||
keyrings, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
App.prototype.render = function () { |
|
||||||
const { |
|
||||||
currentView, |
|
||||||
dispatch, |
|
||||||
isLoading, |
|
||||||
loadingMessage, |
|
||||||
transForward, |
|
||||||
network, |
|
||||||
featureFlags, |
|
||||||
} = this.props |
|
||||||
const isLoadingNetwork = network === 'loading' && currentView.name !== 'config' |
|
||||||
const loadMessage = loadingMessage || isLoadingNetwork |
|
||||||
? `Connecting to ${this.getNetworkName()}` |
|
||||||
: null |
|
||||||
log.debug('Main ui render function') |
|
||||||
|
|
||||||
if (!featureFlags.skipAnnounceBetaUI) { |
|
||||||
return ( |
|
||||||
h(NewUiAnnouncement, { |
|
||||||
dispatch, |
|
||||||
}) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.flex-column.full-height', { |
|
||||||
style: { |
|
||||||
// Windows was showing a vertical scroll bar:
|
|
||||||
overflow: 'hidden', |
|
||||||
position: 'relative', |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(AppBar, { |
|
||||||
...this.props, |
|
||||||
}), |
|
||||||
this.renderLoadingIndicator({ isLoading, isLoadingNetwork, loadMessage }), |
|
||||||
|
|
||||||
// panel content
|
|
||||||
h('.app-primary' + (transForward ? '.from-right' : '.from-left'), { |
|
||||||
style: { |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
this.renderPrimary(), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
App.prototype.renderLoadingIndicator = function ({ isLoading, isLoadingNetwork, loadMessage }) { |
|
||||||
const { isMascara } = this.props |
|
||||||
|
|
||||||
return isMascara |
|
||||||
? null |
|
||||||
: h(Loading, { |
|
||||||
isLoading: isLoading || isLoadingNetwork, |
|
||||||
loadingMessage: loadMessage, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
App.prototype.renderPrimary = function () { |
|
||||||
log.debug('rendering primary') |
|
||||||
var props = this.props |
|
||||||
const {isMascara, isOnboarding, providerRequests} = props |
|
||||||
|
|
||||||
if (isMascara && isOnboarding) { |
|
||||||
return h(FirstTime) |
|
||||||
} |
|
||||||
|
|
||||||
// notices
|
|
||||||
if (!props.noActiveNotices) { |
|
||||||
log.debug('rendering notice screen for unread notices.') |
|
||||||
return h('div', { |
|
||||||
style: { width: '100%' }, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h(NoticeScreen, { |
|
||||||
notice: props.nextUnreadNotice, |
|
||||||
key: 'NoticeScreen', |
|
||||||
onConfirm: () => props.dispatch(actions.markNoticeRead(props.nextUnreadNotice)), |
|
||||||
}), |
|
||||||
]) |
|
||||||
} else if (props.lostAccounts && props.lostAccounts.length > 0) { |
|
||||||
log.debug('rendering notice screen for lost accounts view.') |
|
||||||
return h(NoticeScreen, { |
|
||||||
notice: generateLostAccountsNotice(props.lostAccounts), |
|
||||||
key: 'LostAccountsNotice', |
|
||||||
onConfirm: () => props.dispatch(actions.markAccountsFound()), |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
// show initialize screen
|
|
||||||
if (!props.isInitialized || props.forgottenPassword) { |
|
||||||
// show current view
|
|
||||||
log.debug('rendering an initialize screen') |
|
||||||
switch (props.currentView.name) { |
|
||||||
|
|
||||||
case 'restoreVault': |
|
||||||
log.debug('rendering restore vault screen') |
|
||||||
return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'}) |
|
||||||
|
|
||||||
default: |
|
||||||
log.debug('rendering menu screen') |
|
||||||
return h(InitializeMenuScreen, {key: 'menuScreenInit'}) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// show unlock screen
|
|
||||||
if (!props.isUnlocked) { |
|
||||||
switch (props.currentView.name) { |
|
||||||
|
|
||||||
case 'restoreVault': |
|
||||||
log.debug('rendering restore vault screen') |
|
||||||
return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'}) |
|
||||||
|
|
||||||
case 'config': |
|
||||||
log.debug('rendering config screen from unlock screen.') |
|
||||||
return h(ConfigScreen, {key: 'config'}) |
|
||||||
|
|
||||||
default: |
|
||||||
log.debug('rendering locked screen') |
|
||||||
return h(UnlockScreen, {key: 'locked'}) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// show seed words screen
|
|
||||||
if (props.seedWords) { |
|
||||||
log.debug('rendering seed words') |
|
||||||
return h(HDCreateVaultComplete, {key: 'HDCreateVaultComplete'}) |
|
||||||
} |
|
||||||
|
|
||||||
if (providerRequests && providerRequests.length > 0) { |
|
||||||
log.debug('rendering provider API approval screen') |
|
||||||
return h(ProviderApproval, { origin: providerRequests[0].origin, tabID: providerRequests[0].tabID }) |
|
||||||
} |
|
||||||
|
|
||||||
// show current view
|
|
||||||
switch (props.currentView.name) { |
|
||||||
|
|
||||||
case 'accountDetail': |
|
||||||
log.debug('rendering account detail screen') |
|
||||||
return h(AccountDetailScreen, {key: 'account-detail'}) |
|
||||||
|
|
||||||
case 'sendTransaction': |
|
||||||
log.debug('rendering send tx screen') |
|
||||||
return h(SendTransactionScreen, {key: 'send-transaction'}) |
|
||||||
|
|
||||||
case 'newKeychain': |
|
||||||
log.debug('rendering new keychain screen') |
|
||||||
return h(NewKeyChainScreen, {key: 'new-keychain'}) |
|
||||||
|
|
||||||
case 'confTx': |
|
||||||
log.debug('rendering confirm tx screen') |
|
||||||
return h(ConfirmTxScreen, {key: 'confirm-tx'}) |
|
||||||
|
|
||||||
case 'add-token': |
|
||||||
log.debug('rendering add-token screen from unlock screen.') |
|
||||||
return h(AddTokenScreen, {key: 'add-token'}) |
|
||||||
|
|
||||||
case 'add-suggested-token': |
|
||||||
log.debug('rendering add-suggested-token screen from unlock screen.') |
|
||||||
return h(AddSuggestedTokenScreen, {key: 'add-suggested-token'}) |
|
||||||
|
|
||||||
case 'config': |
|
||||||
log.debug('rendering config screen') |
|
||||||
return h(ConfigScreen, {key: 'config'}) |
|
||||||
|
|
||||||
case 'import-menu': |
|
||||||
log.debug('rendering import screen') |
|
||||||
return h(Import, {key: 'import-menu'}) |
|
||||||
|
|
||||||
case 'reveal-seed-conf': |
|
||||||
log.debug('rendering reveal seed confirmation screen') |
|
||||||
return h(RevealSeedConfirmation, {key: 'reveal-seed-conf'}) |
|
||||||
|
|
||||||
case 'info': |
|
||||||
log.debug('rendering info screen') |
|
||||||
return h(InfoScreen, {key: 'info'}) |
|
||||||
|
|
||||||
case 'buyEth': |
|
||||||
log.debug('rendering buy ether screen') |
|
||||||
return h(BuyView, {key: 'buyEthView'}) |
|
||||||
|
|
||||||
case 'qr': |
|
||||||
log.debug('rendering show qr screen') |
|
||||||
return h(AccountQrScreen, { |
|
||||||
key: 'account-qr', |
|
||||||
selectedAddress: props.selectedAddress, |
|
||||||
}) |
|
||||||
|
|
||||||
default: |
|
||||||
log.debug('rendering default, account detail screen') |
|
||||||
return h(AccountDetailScreen, {key: 'account-detail'}) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
App.prototype.toggleMetamaskActive = function () { |
|
||||||
if (!this.props.isUnlocked) { |
|
||||||
// currently inactive: redirect to password box
|
|
||||||
var passwordBox = document.querySelector('input[type=password]') |
|
||||||
if (!passwordBox) return |
|
||||||
passwordBox.focus() |
|
||||||
} else { |
|
||||||
// currently active: deactivate
|
|
||||||
this.props.dispatch(actions.lockMetamask(false)) |
|
||||||
} |
|
||||||
} |
|
||||||
App.prototype.getNetworkName = function () { |
|
||||||
const { provider } = this.props |
|
||||||
const providerName = provider.type |
|
||||||
|
|
||||||
let name |
|
||||||
|
|
||||||
if (providerName === 'mainnet') { |
|
||||||
name = 'Main Ethereum Network' |
|
||||||
} else if (providerName === 'ropsten') { |
|
||||||
name = 'Ropsten Test Network' |
|
||||||
} else if (providerName === 'kovan') { |
|
||||||
name = 'Kovan Test Network' |
|
||||||
} else if (providerName === 'rinkeby') { |
|
||||||
name = 'Rinkeby Test Network' |
|
||||||
} else { |
|
||||||
name = 'Unknown Private Network' |
|
||||||
} |
|
||||||
|
|
||||||
return name |
|
||||||
} |
|
@ -1,321 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const PropTypes = require('prop-types') |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const actions = require('../../../ui/app/actions') |
|
||||||
const genAccountLink = require('etherscan-link').createAccountLink |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const Dropdown = require('./dropdown').Dropdown |
|
||||||
const DropdownMenuItem = require('./dropdown').DropdownMenuItem |
|
||||||
const Identicon = require('./identicon') |
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const copyToClipboard = require('copy-to-clipboard') |
|
||||||
|
|
||||||
class AccountDropdowns extends Component { |
|
||||||
constructor (props) { |
|
||||||
super(props) |
|
||||||
this.state = { |
|
||||||
accountSelectorActive: false, |
|
||||||
optionsMenuActive: false, |
|
||||||
} |
|
||||||
this.accountSelectorToggleClassName = 'accounts-selector' |
|
||||||
this.optionsMenuToggleClassName = 'fa-ellipsis-h' |
|
||||||
} |
|
||||||
|
|
||||||
renderAccounts () { |
|
||||||
const { identities, selected, keyrings } = this.props |
|
||||||
const accountOrder = keyrings.reduce((list, keyring) => list.concat(keyring.accounts), []) |
|
||||||
|
|
||||||
return accountOrder.map((address, index) => { |
|
||||||
const identity = identities[address] |
|
||||||
const isSelected = identity.address === selected |
|
||||||
|
|
||||||
const simpleAddress = identity.address.substring(2).toLowerCase() |
|
||||||
|
|
||||||
const keyring = keyrings.find((kr) => { |
|
||||||
return kr.accounts.includes(simpleAddress) || |
|
||||||
kr.accounts.includes(identity.address) |
|
||||||
}) |
|
||||||
|
|
||||||
return h( |
|
||||||
DropdownMenuItem, |
|
||||||
{ |
|
||||||
closeMenu: () => {}, |
|
||||||
onClick: () => { |
|
||||||
this.props.actions.showAccountDetail(identity.address) |
|
||||||
}, |
|
||||||
style: { |
|
||||||
marginTop: index === 0 ? '5px' : '', |
|
||||||
fontSize: '24px', |
|
||||||
}, |
|
||||||
}, |
|
||||||
[ |
|
||||||
h( |
|
||||||
Identicon, |
|
||||||
{ |
|
||||||
address: identity.address, |
|
||||||
diameter: 32, |
|
||||||
style: { |
|
||||||
marginLeft: '10px', |
|
||||||
}, |
|
||||||
}, |
|
||||||
), |
|
||||||
this.indicateIfLoose(keyring), |
|
||||||
h('span', { |
|
||||||
style: { |
|
||||||
marginLeft: '20px', |
|
||||||
fontSize: '24px', |
|
||||||
maxWidth: '145px', |
|
||||||
whiteSpace: 'nowrap', |
|
||||||
overflow: 'hidden', |
|
||||||
textOverflow: 'ellipsis', |
|
||||||
}, |
|
||||||
}, identity.name || ''), |
|
||||||
h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, isSelected ? h('.check', '✓') : null), |
|
||||||
] |
|
||||||
) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
indicateIfLoose (keyring) { |
|
||||||
try { // Sometimes keyrings aren't loaded yet:
|
|
||||||
const type = keyring.type |
|
||||||
const isLoose = type !== 'HD Key Tree' |
|
||||||
return isLoose ? h('.keyring-label', 'IMPORTED') : null |
|
||||||
} catch (e) { return } |
|
||||||
} |
|
||||||
|
|
||||||
renderAccountSelector () { |
|
||||||
const { actions } = this.props |
|
||||||
const { accountSelectorActive } = this.state |
|
||||||
|
|
||||||
return h( |
|
||||||
Dropdown, |
|
||||||
{ |
|
||||||
useCssTransition: true, // Hardcoded because account selector is temporarily in app-header
|
|
||||||
style: { |
|
||||||
marginLeft: '-238px', |
|
||||||
marginTop: '38px', |
|
||||||
minWidth: '180px', |
|
||||||
overflowY: 'auto', |
|
||||||
maxHeight: '300px', |
|
||||||
width: '300px', |
|
||||||
}, |
|
||||||
innerStyle: { |
|
||||||
padding: '8px 25px', |
|
||||||
}, |
|
||||||
isOpen: accountSelectorActive, |
|
||||||
onClickOutside: (event) => { |
|
||||||
const { classList } = event.target |
|
||||||
const isNotToggleElement = !classList.contains(this.accountSelectorToggleClassName) |
|
||||||
if (accountSelectorActive && isNotToggleElement) { |
|
||||||
this.setState({ accountSelectorActive: false }) |
|
||||||
} |
|
||||||
}, |
|
||||||
}, |
|
||||||
[ |
|
||||||
...this.renderAccounts(), |
|
||||||
h( |
|
||||||
DropdownMenuItem, |
|
||||||
{ |
|
||||||
closeMenu: () => {}, |
|
||||||
onClick: () => actions.addNewAccount(), |
|
||||||
}, |
|
||||||
[ |
|
||||||
h( |
|
||||||
Identicon, |
|
||||||
{ |
|
||||||
style: { |
|
||||||
marginLeft: '10px', |
|
||||||
}, |
|
||||||
diameter: 32, |
|
||||||
}, |
|
||||||
), |
|
||||||
h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, 'Create Account'), |
|
||||||
], |
|
||||||
), |
|
||||||
h( |
|
||||||
DropdownMenuItem, |
|
||||||
{ |
|
||||||
closeMenu: () => {}, |
|
||||||
onClick: () => actions.showImportPage(), |
|
||||||
}, |
|
||||||
[ |
|
||||||
h( |
|
||||||
Identicon, |
|
||||||
{ |
|
||||||
style: { |
|
||||||
marginLeft: '10px', |
|
||||||
}, |
|
||||||
diameter: 32, |
|
||||||
}, |
|
||||||
), |
|
||||||
h('span', { |
|
||||||
style: { |
|
||||||
marginLeft: '20px', |
|
||||||
fontSize: '24px', |
|
||||||
marginBottom: '5px', |
|
||||||
}, |
|
||||||
}, 'Import Account'), |
|
||||||
] |
|
||||||
), |
|
||||||
] |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
renderAccountOptions () { |
|
||||||
const { actions } = this.props |
|
||||||
const { optionsMenuActive } = this.state |
|
||||||
|
|
||||||
return h( |
|
||||||
Dropdown, |
|
||||||
{ |
|
||||||
style: { |
|
||||||
marginLeft: '-215px', |
|
||||||
minWidth: '180px', |
|
||||||
}, |
|
||||||
isOpen: optionsMenuActive, |
|
||||||
onClickOutside: (event) => { |
|
||||||
const { classList } = event.target |
|
||||||
const isNotToggleElement = !classList.contains(this.optionsMenuToggleClassName) |
|
||||||
if (optionsMenuActive && isNotToggleElement) { |
|
||||||
this.setState({ optionsMenuActive: false }) |
|
||||||
} |
|
||||||
}, |
|
||||||
}, |
|
||||||
[ |
|
||||||
h( |
|
||||||
DropdownMenuItem, |
|
||||||
{ |
|
||||||
closeMenu: () => {}, |
|
||||||
onClick: () => { |
|
||||||
const { selected, network } = this.props |
|
||||||
const url = genAccountLink(selected, network) |
|
||||||
global.platform.openWindow({ url }) |
|
||||||
}, |
|
||||||
}, |
|
||||||
'View account on Etherscan', |
|
||||||
), |
|
||||||
h( |
|
||||||
DropdownMenuItem, |
|
||||||
{ |
|
||||||
closeMenu: () => {}, |
|
||||||
onClick: () => { |
|
||||||
const { selected, identities } = this.props |
|
||||||
var identity = identities[selected] |
|
||||||
actions.showQrView(selected, identity ? identity.name : '') |
|
||||||
}, |
|
||||||
}, |
|
||||||
'Show QR Code', |
|
||||||
), |
|
||||||
h( |
|
||||||
DropdownMenuItem, |
|
||||||
{ |
|
||||||
closeMenu: () => {}, |
|
||||||
onClick: () => { |
|
||||||
const { selected } = this.props |
|
||||||
const checkSumAddress = selected && ethUtil.toChecksumAddress(selected) |
|
||||||
copyToClipboard(checkSumAddress) |
|
||||||
}, |
|
||||||
}, |
|
||||||
'Copy Address to clipboard', |
|
||||||
), |
|
||||||
h( |
|
||||||
DropdownMenuItem, |
|
||||||
{ |
|
||||||
closeMenu: () => {}, |
|
||||||
onClick: () => { |
|
||||||
actions.requestAccountExport() |
|
||||||
}, |
|
||||||
}, |
|
||||||
'Export Private Key', |
|
||||||
), |
|
||||||
] |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
render () { |
|
||||||
const { style, enableAccountsSelector, enableAccountOptions } = this.props |
|
||||||
const { optionsMenuActive, accountSelectorActive } = this.state |
|
||||||
|
|
||||||
return h( |
|
||||||
'span', |
|
||||||
{ |
|
||||||
style: style, |
|
||||||
}, |
|
||||||
[ |
|
||||||
enableAccountsSelector && h( |
|
||||||
// 'i.fa.fa-angle-down',
|
|
||||||
'div.cursor-pointer.color-orange.accounts-selector', |
|
||||||
{ |
|
||||||
style: { |
|
||||||
// fontSize: '1.8em',
|
|
||||||
background: 'url(images/switch_acc.svg) white center center no-repeat', |
|
||||||
height: '25px', |
|
||||||
width: '25px', |
|
||||||
transform: 'scale(0.75)', |
|
||||||
marginRight: '3px', |
|
||||||
}, |
|
||||||
onClick: (event) => { |
|
||||||
event.stopPropagation() |
|
||||||
this.setState({ |
|
||||||
accountSelectorActive: !accountSelectorActive, |
|
||||||
optionsMenuActive: false, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}, |
|
||||||
this.renderAccountSelector(), |
|
||||||
), |
|
||||||
enableAccountOptions && h( |
|
||||||
'i.fa.fa-ellipsis-h', |
|
||||||
{ |
|
||||||
style: { |
|
||||||
margin: '0.5em', |
|
||||||
fontSize: '1.8em', |
|
||||||
}, |
|
||||||
onClick: (event) => { |
|
||||||
event.stopPropagation() |
|
||||||
this.setState({ |
|
||||||
accountSelectorActive: false, |
|
||||||
optionsMenuActive: !optionsMenuActive, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}, |
|
||||||
this.renderAccountOptions() |
|
||||||
), |
|
||||||
] |
|
||||||
) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
AccountDropdowns.defaultProps = { |
|
||||||
enableAccountsSelector: false, |
|
||||||
enableAccountOptions: false, |
|
||||||
} |
|
||||||
|
|
||||||
AccountDropdowns.propTypes = { |
|
||||||
identities: PropTypes.objectOf(PropTypes.object), |
|
||||||
selected: PropTypes.string, |
|
||||||
keyrings: PropTypes.array, |
|
||||||
actions: PropTypes.objectOf(PropTypes.func), |
|
||||||
network: PropTypes.string, |
|
||||||
style: PropTypes.object, |
|
||||||
enableAccountOptions: PropTypes.bool, |
|
||||||
enableAccountsSelector: PropTypes.bool, |
|
||||||
} |
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => { |
|
||||||
return { |
|
||||||
actions: { |
|
||||||
showConfigPage: () => dispatch(actions.showConfigPage()), |
|
||||||
requestAccountExport: () => dispatch(actions.requestExportAccount()), |
|
||||||
showAccountDetail: (address) => dispatch(actions.showAccountDetail(address)), |
|
||||||
addNewAccount: () => dispatch(actions.addNewAccount()), |
|
||||||
showImportPage: () => dispatch(actions.showImportPage()), |
|
||||||
showQrView: (selected, identity) => dispatch(actions.showQrView(selected, identity)), |
|
||||||
}, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = { |
|
||||||
AccountDropdowns: connect(null, mapDispatchToProps)(AccountDropdowns), |
|
||||||
} |
|
@ -1,132 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const exportAsFile = require('../util').exportAsFile |
|
||||||
const copyToClipboard = require('copy-to-clipboard') |
|
||||||
const actions = require('../../../ui/app/actions') |
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(ExportAccountView) |
|
||||||
|
|
||||||
inherits(ExportAccountView, Component) |
|
||||||
function ExportAccountView () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
warning: state.appState.warning, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ExportAccountView.prototype.render = function () { |
|
||||||
const state = this.props |
|
||||||
const accountDetail = state.accountDetail |
|
||||||
const nickname = state.identities[state.address].name |
|
||||||
|
|
||||||
if (!accountDetail) return h('div') |
|
||||||
const accountExport = accountDetail.accountExport |
|
||||||
|
|
||||||
const notExporting = accountExport === 'none' |
|
||||||
const exportRequested = accountExport === 'requested' |
|
||||||
const accountExported = accountExport === 'completed' |
|
||||||
|
|
||||||
if (notExporting) return h('div') |
|
||||||
|
|
||||||
if (exportRequested) { |
|
||||||
const warning = `Export private keys at your own risk.` |
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
display: 'inline-block', |
|
||||||
textAlign: 'center', |
|
||||||
}, |
|
||||||
}, |
|
||||||
[ |
|
||||||
h('div', { |
|
||||||
key: 'exporting', |
|
||||||
style: { |
|
||||||
margin: '0 20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('p.error', warning), |
|
||||||
h('input#exportAccount.sizing-input', { |
|
||||||
type: 'password', |
|
||||||
placeholder: 'confirm password', |
|
||||||
onKeyPress: this.onExportKeyPress.bind(this), |
|
||||||
style: { |
|
||||||
position: 'relative', |
|
||||||
top: '1.5px', |
|
||||||
marginBottom: '7px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
h('div', { |
|
||||||
key: 'buttons', |
|
||||||
style: { |
|
||||||
margin: '0 20px', |
|
||||||
}, |
|
||||||
}, |
|
||||||
[ |
|
||||||
h('button', { |
|
||||||
onClick: () => this.onExportKeyPress({ key: 'Enter', preventDefault: () => {} }), |
|
||||||
style: { |
|
||||||
marginRight: '10px', |
|
||||||
}, |
|
||||||
}, 'Submit'), |
|
||||||
h('button', { |
|
||||||
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), |
|
||||||
}, 'Cancel'), |
|
||||||
]), |
|
||||||
(this.props.warning) && ( |
|
||||||
h('span.error', { |
|
||||||
style: { |
|
||||||
margin: '20px', |
|
||||||
}, |
|
||||||
}, this.props.warning.split('-')) |
|
||||||
), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
if (accountExported) { |
|
||||||
const plainKey = ethUtil.stripHexPrefix(accountDetail.privateKey) |
|
||||||
|
|
||||||
return h('div.privateKey', { |
|
||||||
style: { |
|
||||||
margin: '0 20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('label', 'Your private key (click to copy):'), |
|
||||||
h('p.error.cursor-pointer', { |
|
||||||
style: { |
|
||||||
textOverflow: 'ellipsis', |
|
||||||
overflow: 'hidden', |
|
||||||
webkitUserSelect: 'text', |
|
||||||
maxWidth: '275px', |
|
||||||
}, |
|
||||||
onClick: function (event) { |
|
||||||
copyToClipboard(ethUtil.stripHexPrefix(accountDetail.privateKey)) |
|
||||||
}, |
|
||||||
}, plainKey), |
|
||||||
h('button', { |
|
||||||
onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), |
|
||||||
}, 'Done'), |
|
||||||
h('button', { |
|
||||||
style: { |
|
||||||
marginLeft: '10px', |
|
||||||
}, |
|
||||||
onClick: () => exportAsFile(`MetaMask ${nickname} Private Key`, plainKey), |
|
||||||
}, 'Save as File'), |
|
||||||
]) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ExportAccountView.prototype.onExportKeyPress = function (event) { |
|
||||||
if (event.key !== 'Enter') return |
|
||||||
event.preventDefault() |
|
||||||
|
|
||||||
const input = document.getElementById('exportAccount').value |
|
||||||
this.props.dispatch(actions.exportAccount(input, this.props.address)) |
|
||||||
} |
|
@ -1,86 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const Identicon = require('./identicon') |
|
||||||
const formatBalance = require('../util').formatBalance |
|
||||||
const addressSummary = require('../util').addressSummary |
|
||||||
|
|
||||||
module.exports = AccountPanel |
|
||||||
|
|
||||||
|
|
||||||
inherits(AccountPanel, Component) |
|
||||||
function AccountPanel () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
AccountPanel.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
var identity = state.identity || {} |
|
||||||
var account = state.account || {} |
|
||||||
var isFauceting = state.isFauceting |
|
||||||
|
|
||||||
var panelState = { |
|
||||||
key: `accountPanel${identity.address}`, |
|
||||||
identiconKey: identity.address, |
|
||||||
identiconLabel: identity.name || '', |
|
||||||
attributes: [ |
|
||||||
{ |
|
||||||
key: 'ADDRESS', |
|
||||||
value: addressSummary(identity.address), |
|
||||||
}, |
|
||||||
balanceOrFaucetingIndication(account, isFauceting), |
|
||||||
], |
|
||||||
} |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.identity-panel.flex-row.flex-space-between', { |
|
||||||
style: { |
|
||||||
flex: '1 0 auto', |
|
||||||
cursor: panelState.onClick ? 'pointer' : undefined, |
|
||||||
}, |
|
||||||
onClick: panelState.onClick, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// account identicon
|
|
||||||
h('.identicon-wrapper.flex-column.select-none', [ |
|
||||||
h(Identicon, { |
|
||||||
address: panelState.identiconKey, |
|
||||||
imageify: state.imageifyIdenticons, |
|
||||||
}), |
|
||||||
h('span.font-small', panelState.identiconLabel.substring(0, 7) + '...'), |
|
||||||
]), |
|
||||||
|
|
||||||
// account address, balance
|
|
||||||
h('.identity-data.flex-column.flex-justify-center.flex-grow.select-none', [ |
|
||||||
|
|
||||||
panelState.attributes.map((attr) => { |
|
||||||
return h('.flex-row.flex-space-between', { |
|
||||||
key: '' + Math.round(Math.random() * 1000000), |
|
||||||
}, [ |
|
||||||
h('label.font-small.no-select', attr.key), |
|
||||||
h('span.font-small', attr.value), |
|
||||||
]) |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
function balanceOrFaucetingIndication (account, isFauceting) { |
|
||||||
// Temporarily deactivating isFauceting indication
|
|
||||||
// because it shows fauceting for empty restored accounts.
|
|
||||||
if (/* isFauceting*/ false) { |
|
||||||
return { |
|
||||||
key: 'Account is auto-funding.', |
|
||||||
value: 'Please wait.', |
|
||||||
} |
|
||||||
} else { |
|
||||||
return { |
|
||||||
key: 'BALANCE', |
|
||||||
value: formatBalance(account.balance), |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,436 +0,0 @@ |
|||||||
const PropTypes = require('prop-types') |
|
||||||
const {Component} = require('react') |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const actions = require('../../../ui/app/actions') |
|
||||||
const SandwichExpando = require('sandwich-expando') |
|
||||||
const {Dropdown} = require('./dropdown') |
|
||||||
const {DropdownMenuItem} = require('./dropdown') |
|
||||||
const NetworkIndicator = require('./network') |
|
||||||
const {AccountDropdowns} = require('./account-dropdowns') |
|
||||||
|
|
||||||
const LOCALHOST_RPC_URL = 'http://localhost:8545' |
|
||||||
|
|
||||||
module.exports = class AppBar extends Component { |
|
||||||
static defaultProps = { |
|
||||||
selectedAddress: undefined, |
|
||||||
} |
|
||||||
|
|
||||||
static propTypes = { |
|
||||||
dispatch: PropTypes.func.isRequired, |
|
||||||
frequentRpcListDetail: PropTypes.array.isRequired, |
|
||||||
isMascara: PropTypes.bool.isRequired, |
|
||||||
isOnboarding: PropTypes.bool.isRequired, |
|
||||||
identities: PropTypes.any.isRequired, |
|
||||||
selectedAddress: PropTypes.string, |
|
||||||
isUnlocked: PropTypes.bool.isRequired, |
|
||||||
network: PropTypes.any.isRequired, |
|
||||||
keyrings: PropTypes.any.isRequired, |
|
||||||
provider: PropTypes.any.isRequired, |
|
||||||
} |
|
||||||
|
|
||||||
static renderSpace () { |
|
||||||
return ( |
|
||||||
h('span', { |
|
||||||
dangerouslySetInnerHTML: { |
|
||||||
__html: ' ', |
|
||||||
}, |
|
||||||
}) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
state = { |
|
||||||
isNetworkMenuOpen: false, |
|
||||||
} |
|
||||||
|
|
||||||
renderAppBar () { |
|
||||||
if (window.METAMASK_UI_TYPE === 'notification') { |
|
||||||
return null |
|
||||||
} |
|
||||||
|
|
||||||
const props = this.props |
|
||||||
const {isMascara, isOnboarding} = props |
|
||||||
|
|
||||||
// Do not render header if user is in mascara onboarding
|
|
||||||
if (isMascara && isOnboarding) { |
|
||||||
return null |
|
||||||
} |
|
||||||
|
|
||||||
// Do not render header if user is in mascara buy ether
|
|
||||||
if (isMascara && props.currentView.name === 'buyEth') { |
|
||||||
return null |
|
||||||
} |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div.app-bar', [ |
|
||||||
this.renderAppBarNewUiNotice(), |
|
||||||
this.renderAppBarAppHeader(), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
renderAppBarNewUiNotice () { |
|
||||||
const {dispatch} = this.props |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div.app-bar__new-ui-banner', { |
|
||||||
style: { |
|
||||||
height: '28px', |
|
||||||
zIndex: 12, |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'Try the New MetaMask', |
|
||||||
AppBar.renderSpace(), |
|
||||||
h('span.banner__link', { |
|
||||||
async onClick () { |
|
||||||
await dispatch(actions.setFeatureFlag('betaUI', true)) |
|
||||||
global.platform.openExtensionInBrowser() |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'Now', |
|
||||||
]), |
|
||||||
AppBar.renderSpace(), |
|
||||||
'or', |
|
||||||
AppBar.renderSpace(), |
|
||||||
h('span.banner__link', { |
|
||||||
onClick () { |
|
||||||
global.platform.openWindow({ |
|
||||||
url: 'https://medium.com/metamask/74dba32cc7f7', |
|
||||||
}) |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'Learn More', |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
renderAppBarAppHeader () { |
|
||||||
const { |
|
||||||
identities, |
|
||||||
selectedAddress, |
|
||||||
isUnlocked, |
|
||||||
network, |
|
||||||
keyrings, |
|
||||||
provider, |
|
||||||
} = this.props |
|
||||||
const { |
|
||||||
isNetworkMenuOpen, |
|
||||||
isMainMenuOpen, |
|
||||||
} = this.state |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.full-width', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
flexDirection: 'column', |
|
||||||
height: '38px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.app-header.flex-row.flex-space-between', { |
|
||||||
style: { |
|
||||||
alignItems: 'center', |
|
||||||
visibility: isUnlocked ? 'visible' : 'none', |
|
||||||
background: isUnlocked ? 'white' : 'none', |
|
||||||
height: '38px', |
|
||||||
position: 'relative', |
|
||||||
zIndex: 12, |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('div.left-menu-section', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
flexDirection: 'row', |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
// mini logo
|
|
||||||
h('img', { |
|
||||||
height: 24, |
|
||||||
width: 24, |
|
||||||
src: './images/icon-128.png', |
|
||||||
}), |
|
||||||
h(NetworkIndicator, { |
|
||||||
network: network, |
|
||||||
provider: provider, |
|
||||||
onClick: (event) => { |
|
||||||
event.preventDefault() |
|
||||||
event.stopPropagation() |
|
||||||
this.setState({ isNetworkMenuOpen: !isNetworkMenuOpen }) |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
isUnlocked && h('div', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
flexDirection: 'row', |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(AccountDropdowns, { |
|
||||||
style: {}, |
|
||||||
enableAccountsSelector: true, |
|
||||||
identities: identities, |
|
||||||
selected: selectedAddress, |
|
||||||
network, |
|
||||||
keyrings, |
|
||||||
}, []), |
|
||||||
h(SandwichExpando, { |
|
||||||
className: 'sandwich-expando', |
|
||||||
width: 16, |
|
||||||
barHeight: 2, |
|
||||||
padding: 0, |
|
||||||
isOpen: isMainMenuOpen, |
|
||||||
color: 'rgb(247,146,30)', |
|
||||||
onClick: () => { |
|
||||||
this.setState({ |
|
||||||
isMainMenuOpen: !isMainMenuOpen, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
renderNetworkDropdown () { |
|
||||||
const { |
|
||||||
dispatch, |
|
||||||
frequentRpcListDetail: rpcList, |
|
||||||
provider, |
|
||||||
} = this.props |
|
||||||
const { |
|
||||||
type: providerType, |
|
||||||
rpcTarget: activeNetwork, |
|
||||||
} = provider |
|
||||||
const isOpen = this.state.isNetworkMenuOpen |
|
||||||
|
|
||||||
return h(Dropdown, { |
|
||||||
useCssTransition: true, |
|
||||||
isOpen, |
|
||||||
onClickOutside: (event) => { |
|
||||||
const { classList } = event.target |
|
||||||
const isNotToggleElement = [ |
|
||||||
classList.contains('menu-icon'), |
|
||||||
classList.contains('network-name'), |
|
||||||
classList.contains('network-indicator'), |
|
||||||
].filter(bool => bool).length === 0 |
|
||||||
// classes from three constituent nodes of the toggle element
|
|
||||||
|
|
||||||
if (isNotToggleElement) { |
|
||||||
this.setState({ isNetworkMenuOpen: false }) |
|
||||||
} |
|
||||||
}, |
|
||||||
zIndex: 11, |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
left: '2px', |
|
||||||
top: '64px', |
|
||||||
}, |
|
||||||
innerStyle: { |
|
||||||
padding: '2px 16px 2px 0px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(DropdownMenuItem, { |
|
||||||
key: 'main', |
|
||||||
closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), |
|
||||||
onClick: () => dispatch(actions.setProviderType('mainnet')), |
|
||||||
style: { |
|
||||||
fontSize: '18px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.menu-icon.diamond'), |
|
||||||
'Main Ethereum Network', |
|
||||||
providerType === 'mainnet' |
|
||||||
? h('.check', '✓') |
|
||||||
: null, |
|
||||||
]), |
|
||||||
h(DropdownMenuItem, { |
|
||||||
key: 'ropsten', |
|
||||||
closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), |
|
||||||
onClick: () => dispatch(actions.setProviderType('ropsten')), |
|
||||||
style: { |
|
||||||
fontSize: '18px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.menu-icon.red-dot'), |
|
||||||
'Ropsten Test Network', |
|
||||||
providerType === 'ropsten' |
|
||||||
? h('.check', '✓') |
|
||||||
: null, |
|
||||||
]), |
|
||||||
h(DropdownMenuItem, { |
|
||||||
key: 'kovan', |
|
||||||
closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), |
|
||||||
onClick: () => dispatch(actions.setProviderType('kovan')), |
|
||||||
style: { |
|
||||||
fontSize: '18px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.menu-icon.hollow-diamond'), |
|
||||||
'Kovan Test Network', |
|
||||||
providerType === 'kovan' |
|
||||||
? h('.check', '✓') |
|
||||||
: null, |
|
||||||
]), |
|
||||||
h(DropdownMenuItem, { |
|
||||||
key: 'rinkeby', |
|
||||||
closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), |
|
||||||
onClick: () => dispatch(actions.setProviderType('rinkeby')), |
|
||||||
style: { |
|
||||||
fontSize: '18px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.menu-icon.golden-square'), |
|
||||||
'Rinkeby Test Network', |
|
||||||
providerType === 'rinkeby' |
|
||||||
? h('.check', '✓') |
|
||||||
: null, |
|
||||||
]), |
|
||||||
h(DropdownMenuItem, { |
|
||||||
key: 'default', |
|
||||||
closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), |
|
||||||
onClick: () => dispatch(actions.setProviderType('localhost')), |
|
||||||
style: { |
|
||||||
fontSize: '18px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-question-circle.fa-lg.menu-icon'), |
|
||||||
'Localhost 8545', |
|
||||||
activeNetwork === LOCALHOST_RPC_URL |
|
||||||
? h('.check', '✓') |
|
||||||
: null, |
|
||||||
]), |
|
||||||
|
|
||||||
this.renderCustomOption(provider), |
|
||||||
this.renderCommonRpc(rpcList, provider), |
|
||||||
|
|
||||||
h(DropdownMenuItem, { |
|
||||||
closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }), |
|
||||||
onClick: () => dispatch(actions.showConfigPage()), |
|
||||||
style: { |
|
||||||
fontSize: '18px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-question-circle.fa-lg.menu-icon'), |
|
||||||
'Custom RPC', |
|
||||||
activeNetwork === 'custom' |
|
||||||
? h('.check', '✓') |
|
||||||
: null, |
|
||||||
]), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
renderCustomOption ({ rpcTarget, type, ticker }) { |
|
||||||
const {dispatch, network} = this.props |
|
||||||
|
|
||||||
if (type !== 'rpc') { |
|
||||||
return null |
|
||||||
} |
|
||||||
|
|
||||||
// Concatenate long URLs
|
|
||||||
let label = rpcTarget |
|
||||||
if (rpcTarget.length > 31) { |
|
||||||
label = label.substr(0, 34) + '...' |
|
||||||
} |
|
||||||
|
|
||||||
switch (rpcTarget) { |
|
||||||
case LOCALHOST_RPC_URL: |
|
||||||
return null |
|
||||||
default: |
|
||||||
return h(DropdownMenuItem, { |
|
||||||
key: rpcTarget, |
|
||||||
onClick: () => dispatch(actions.setRpcTarget(rpcTarget, network, ticker)), |
|
||||||
closeMenu: () => this.setState({ isNetworkMenuOpen: false }), |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-question-circle.fa-lg.menu-icon'), |
|
||||||
label, |
|
||||||
h('.check', '✓'), |
|
||||||
]) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
renderCommonRpc (rpcList, provider) { |
|
||||||
const {dispatch} = this.props |
|
||||||
const reversedRpcList = rpcList.slice().reverse() |
|
||||||
|
|
||||||
return reversedRpcList.map((entry) => { |
|
||||||
const rpc = entry.rpcUrl |
|
||||||
const currentRpcTarget = provider.type === 'rpc' && rpc === provider.rpcTarget |
|
||||||
|
|
||||||
if ((rpc === LOCALHOST_RPC_URL) || currentRpcTarget) { |
|
||||||
return null |
|
||||||
} else { |
|
||||||
return h(DropdownMenuItem, { |
|
||||||
key: `common${rpc}`, |
|
||||||
closeMenu: () => this.setState({ isNetworkMenuOpen: false }), |
|
||||||
onClick: () => dispatch(actions.setRpcTarget(rpc, entry.chainId, entry.ticker)), |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-question-circle.fa-lg.menu-icon'), |
|
||||||
rpc, |
|
||||||
currentRpcTarget |
|
||||||
? h('.check', '✓') |
|
||||||
: null, |
|
||||||
]) |
|
||||||
} |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
renderDropdown () { |
|
||||||
const {dispatch} = this.props |
|
||||||
const isOpen = this.state.isMainMenuOpen |
|
||||||
|
|
||||||
return h(Dropdown, { |
|
||||||
useCssTransition: true, |
|
||||||
isOpen: isOpen, |
|
||||||
zIndex: 11, |
|
||||||
onClickOutside: (event) => { |
|
||||||
const classList = event.target.classList |
|
||||||
const parentClassList = event.target.parentElement.classList |
|
||||||
|
|
||||||
const isToggleElement = classList.contains('sandwich-expando') || |
|
||||||
parentClassList.contains('sandwich-expando') |
|
||||||
|
|
||||||
if (isOpen && !isToggleElement) { |
|
||||||
this.setState({ isMainMenuOpen: false }) |
|
||||||
} |
|
||||||
}, |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
right: '2px', |
|
||||||
top: '66px', |
|
||||||
}, |
|
||||||
innerStyle: {}, |
|
||||||
}, [ |
|
||||||
h(DropdownMenuItem, { |
|
||||||
closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }), |
|
||||||
onClick: () => { dispatch(actions.showConfigPage()) }, |
|
||||||
}, 'Settings'), |
|
||||||
|
|
||||||
h(DropdownMenuItem, { |
|
||||||
closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }), |
|
||||||
onClick: () => { dispatch(actions.lockMetamask()) }, |
|
||||||
}, 'Log Out'), |
|
||||||
|
|
||||||
h(DropdownMenuItem, { |
|
||||||
closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }), |
|
||||||
onClick: () => { dispatch(actions.showInfoPage()) }, |
|
||||||
}, 'Info/Help'), |
|
||||||
|
|
||||||
h(DropdownMenuItem, { |
|
||||||
closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }), |
|
||||||
onClick: () => { |
|
||||||
dispatch(actions.setFeatureFlag('betaUI', true, 'BETA_UI_NOTIFICATION_MODAL')) |
|
||||||
}, |
|
||||||
}, 'Try New UI!'), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
render () { |
|
||||||
return h('div.full-width', [ |
|
||||||
this.renderAppBar(), |
|
||||||
this.renderNetworkDropdown(), |
|
||||||
this.renderDropdown(), |
|
||||||
]) |
|
||||||
} |
|
||||||
} |
|
@ -1,96 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const inherits = require('util').inherits |
|
||||||
const formatBalance = require('../util').formatBalance |
|
||||||
const generateBalanceObject = require('../util').generateBalanceObject |
|
||||||
const Tooltip = require('./tooltip.js') |
|
||||||
const FiatValue = require('./fiat-value.js') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(EthBalanceComponent) |
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
ticker: state.metamask.ticker, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(EthBalanceComponent, Component) |
|
||||||
function EthBalanceComponent () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
EthBalanceComponent.prototype.render = function () { |
|
||||||
var props = this.props |
|
||||||
let { value } = props |
|
||||||
const { ticker } = props |
|
||||||
var style = props.style |
|
||||||
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true |
|
||||||
value = value ? formatBalance(value, 6, needsParse, ticker) : '...' |
|
||||||
var width = props.width |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.ether-balance.ether-balance-amount', { |
|
||||||
style: style, |
|
||||||
}, [ |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
display: 'inline', |
|
||||||
width: width, |
|
||||||
}, |
|
||||||
}, this.renderBalance(value)), |
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
||||||
EthBalanceComponent.prototype.renderBalance = function (value) { |
|
||||||
var props = this.props |
|
||||||
if (value === 'None') return value |
|
||||||
if (value === '...') return value |
|
||||||
var balanceObj = generateBalanceObject(value, props.shorten ? 1 : 3) |
|
||||||
var balance |
|
||||||
var splitBalance = value.split(' ') |
|
||||||
var ethNumber = splitBalance[0] |
|
||||||
var ethSuffix = splitBalance[1] |
|
||||||
const showFiat = 'showFiat' in props ? props.showFiat : true |
|
||||||
|
|
||||||
if (props.shorten) { |
|
||||||
balance = balanceObj.shortBalance |
|
||||||
} else { |
|
||||||
balance = balanceObj.balance |
|
||||||
} |
|
||||||
|
|
||||||
var label = balanceObj.label |
|
||||||
|
|
||||||
return ( |
|
||||||
h(Tooltip, { |
|
||||||
position: 'bottom', |
|
||||||
title: `${ethNumber} ${ethSuffix}`, |
|
||||||
}, h('div.flex-column', [ |
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
alignItems: 'flex-end', |
|
||||||
lineHeight: '13px', |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
textRendering: 'geometricPrecision', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
width: '100%', |
|
||||||
textAlign: 'right', |
|
||||||
}, |
|
||||||
}, this.props.incoming ? `+${balance}` : balance), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
color: ' #AEAEAE', |
|
||||||
fontSize: '12px', |
|
||||||
marginLeft: '5px', |
|
||||||
}, |
|
||||||
}, label), |
|
||||||
]), |
|
||||||
|
|
||||||
showFiat ? h(FiatValue, { value: props.value }) : null, |
|
||||||
])) |
|
||||||
) |
|
||||||
} |
|
@ -1,46 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const extend = require('xtend') |
|
||||||
|
|
||||||
module.exports = BinaryRenderer |
|
||||||
|
|
||||||
inherits(BinaryRenderer, Component) |
|
||||||
function BinaryRenderer () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
BinaryRenderer.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const { value, style } = props |
|
||||||
const text = this.hexToText(value) |
|
||||||
|
|
||||||
const defaultStyle = extend({ |
|
||||||
width: '315px', |
|
||||||
maxHeight: '210px', |
|
||||||
resize: 'none', |
|
||||||
border: 'none', |
|
||||||
background: 'white', |
|
||||||
padding: '3px', |
|
||||||
}, style) |
|
||||||
|
|
||||||
return ( |
|
||||||
h('textarea.font-small', { |
|
||||||
readOnly: true, |
|
||||||
style: defaultStyle, |
|
||||||
defaultValue: text, |
|
||||||
}) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
BinaryRenderer.prototype.hexToText = function (hex) { |
|
||||||
try { |
|
||||||
const stripped = ethUtil.stripHexPrefix(hex) |
|
||||||
const buff = Buffer.from(stripped, 'hex') |
|
||||||
return buff.toString('utf8') |
|
||||||
} catch (e) { |
|
||||||
return hex |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
@ -1,181 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const BN = ethUtil.BN |
|
||||||
const extend = require('xtend') |
|
||||||
|
|
||||||
module.exports = BnAsDecimalInput |
|
||||||
|
|
||||||
inherits(BnAsDecimalInput, Component) |
|
||||||
function BnAsDecimalInput () { |
|
||||||
this.state = { invalid: null } |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
/* Bn as Decimal Input |
|
||||||
* |
|
||||||
* A component for allowing easy, decimal editing |
|
||||||
* of a passed in bn string value. |
|
||||||
* |
|
||||||
* On change, calls back its `onChange` function parameter |
|
||||||
* and passes it an updated bn string. |
|
||||||
*/ |
|
||||||
|
|
||||||
BnAsDecimalInput.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const state = this.state |
|
||||||
|
|
||||||
const { value, scale, precision, onChange, min, max } = props |
|
||||||
|
|
||||||
const suffix = props.suffix |
|
||||||
const style = props.style |
|
||||||
const valueString = value.toString(10) |
|
||||||
const newMin = min && this.downsize(min.toString(10), scale) |
|
||||||
const newMax = max && this.downsize(max.toString(10), scale) |
|
||||||
const newValue = this.downsize(valueString, scale) |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.flex-column', [ |
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
alignItems: 'flex-end', |
|
||||||
lineHeight: '13px', |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
textRendering: 'geometricPrecision', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('input.hex-input', { |
|
||||||
type: 'number', |
|
||||||
step: 'any', |
|
||||||
required: true, |
|
||||||
min: newMin, |
|
||||||
max: newMax, |
|
||||||
style: extend({ |
|
||||||
display: 'block', |
|
||||||
textAlign: 'right', |
|
||||||
backgroundColor: 'transparent', |
|
||||||
border: '1px solid #bdbdbd', |
|
||||||
|
|
||||||
}, style), |
|
||||||
value: newValue, |
|
||||||
onBlur: (event) => { |
|
||||||
this.updateValidity(event) |
|
||||||
}, |
|
||||||
onChange: (event) => { |
|
||||||
this.updateValidity(event) |
|
||||||
const value = (event.target.value === '') ? '' : event.target.value |
|
||||||
|
|
||||||
|
|
||||||
const scaledNumber = this.upsize(value, scale, precision) |
|
||||||
const precisionBN = new BN(scaledNumber, 10) |
|
||||||
onChange(precisionBN, event.target.checkValidity()) |
|
||||||
}, |
|
||||||
onInvalid: (event) => { |
|
||||||
const msg = this.constructWarning() |
|
||||||
if (msg === state.invalid) { |
|
||||||
return |
|
||||||
} |
|
||||||
this.setState({ invalid: msg }) |
|
||||||
event.preventDefault() |
|
||||||
return false |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
color: ' #AEAEAE', |
|
||||||
fontSize: '12px', |
|
||||||
marginLeft: '5px', |
|
||||||
marginRight: '6px', |
|
||||||
width: '20px', |
|
||||||
}, |
|
||||||
}, suffix), |
|
||||||
]), |
|
||||||
|
|
||||||
state.invalid ? h('span.error', { |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
right: '0px', |
|
||||||
textAlign: 'right', |
|
||||||
transform: 'translateY(26px)', |
|
||||||
padding: '3px', |
|
||||||
background: 'rgba(255,255,255,0.85)', |
|
||||||
zIndex: '1', |
|
||||||
textTransform: 'capitalize', |
|
||||||
border: '2px solid #E20202', |
|
||||||
}, |
|
||||||
}, state.invalid) : null, |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
BnAsDecimalInput.prototype.setValid = function (message) { |
|
||||||
this.setState({ invalid: null }) |
|
||||||
} |
|
||||||
|
|
||||||
BnAsDecimalInput.prototype.updateValidity = function (event) { |
|
||||||
const target = event.target |
|
||||||
const value = this.props.value |
|
||||||
const newValue = target.value |
|
||||||
|
|
||||||
if (value === newValue) { |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
const valid = target.checkValidity() |
|
||||||
|
|
||||||
if (valid) { |
|
||||||
this.setState({ invalid: null }) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
BnAsDecimalInput.prototype.constructWarning = function () { |
|
||||||
const { name, min, max, scale, suffix } = this.props |
|
||||||
const newMin = min && this.downsize(min.toString(10), scale) |
|
||||||
const newMax = max && this.downsize(max.toString(10), scale) |
|
||||||
let message = name ? name + ' ' : '' |
|
||||||
|
|
||||||
if (min && max) { |
|
||||||
message += `must be greater than or equal to ${newMin} ${suffix} and less than or equal to ${newMax} ${suffix}.` |
|
||||||
} else if (min) { |
|
||||||
message += `must be greater than or equal to ${newMin} ${suffix}.` |
|
||||||
} else if (max) { |
|
||||||
message += `must be less than or equal to ${newMax} ${suffix}.` |
|
||||||
} else { |
|
||||||
message += 'Invalid input.' |
|
||||||
} |
|
||||||
|
|
||||||
return message |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
BnAsDecimalInput.prototype.downsize = function (number, scale) { |
|
||||||
// if there is no scaling, simply return the number
|
|
||||||
if (scale === 0) { |
|
||||||
return Number(number) |
|
||||||
} else { |
|
||||||
// if the scale is the same as the precision, account for this edge case.
|
|
||||||
var adjustedNumber = number |
|
||||||
while (adjustedNumber.length < scale) { |
|
||||||
adjustedNumber = '0' + adjustedNumber |
|
||||||
} |
|
||||||
return Number(adjustedNumber.slice(0, -scale) + '.' + adjustedNumber.slice(-scale)) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
BnAsDecimalInput.prototype.upsize = function (number, scale, precision) { |
|
||||||
var stringArray = number.toString().split('.') |
|
||||||
var decimalLength = stringArray[1] ? stringArray[1].length : 0 |
|
||||||
var newString = stringArray[0] |
|
||||||
|
|
||||||
// If there is scaling and decimal parts exist, integrate them in.
|
|
||||||
if ((scale !== 0) && (decimalLength !== 0)) { |
|
||||||
newString += stringArray[1].slice(0, precision) |
|
||||||
} |
|
||||||
|
|
||||||
// Add 0s to account for the upscaling.
|
|
||||||
for (var i = decimalLength; i < scale; i++) { |
|
||||||
newString += '0' |
|
||||||
} |
|
||||||
return newString |
|
||||||
} |
|
@ -1,261 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const actions = require('../../../ui/app/actions') |
|
||||||
const CoinbaseForm = require('./coinbase-form') |
|
||||||
const ShapeshiftForm = require('./shapeshift-form') |
|
||||||
const Loading = require('./loading') |
|
||||||
const AccountPanel = require('./account-panel') |
|
||||||
const RadioList = require('./custom-radio-list') |
|
||||||
const { getNetworkDisplayName } = require('../../../app/scripts/controllers/network/util') |
|
||||||
|
|
||||||
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', |
|
||||||
}, |
|
||||||
}, 'Buy Eth'), |
|
||||||
]), |
|
||||||
|
|
||||||
// loading indication
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
top: '57vh', |
|
||||||
left: '49vw', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(Loading, { isLoading }), |
|
||||||
]), |
|
||||||
|
|
||||||
// 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', |
|
||||||
}, |
|
||||||
}, 'Select Service'), |
|
||||||
]), |
|
||||||
|
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
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} Test Faucet` |
|
||||||
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', |
|
||||||
}, |
|
||||||
}, 'Borrow With Dharma (Beta)') |
|
||||||
) : null, |
|
||||||
]) |
|
||||||
) |
|
||||||
|
|
||||||
default: |
|
||||||
return ( |
|
||||||
h('h2.error', 'Unknown network ID') |
|
||||||
) |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
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': 'Crypto/FIAT (USA only)', |
|
||||||
'ShapeShift': '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(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)) |
|
||||||
} |
|
||||||
} |
|
@ -1,63 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const actions = require('../../../ui/app/actions') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(CoinbaseForm) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
warning: state.appState.warning, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(CoinbaseForm, Component) |
|
||||||
|
|
||||||
function CoinbaseForm () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
CoinbaseForm.prototype.render = function () { |
|
||||||
var props = this.props |
|
||||||
|
|
||||||
return h('.flex-column', { |
|
||||||
style: { |
|
||||||
marginTop: '35px', |
|
||||||
padding: '25px', |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
justifyContent: 'space-around', |
|
||||||
margin: '33px', |
|
||||||
marginTop: '0px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('button.btn-green', { |
|
||||||
onClick: this.toCoinbase.bind(this), |
|
||||||
}, 'Continue to Coinbase'), |
|
||||||
|
|
||||||
h('button.btn-red', { |
|
||||||
onClick: () => props.dispatch(actions.goHome()), |
|
||||||
}, 'Cancel'), |
|
||||||
]), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
CoinbaseForm.prototype.toCoinbase = function () { |
|
||||||
const props = this.props |
|
||||||
const address = props.buyView.buyAddress |
|
||||||
props.dispatch(actions.buyEth({ network: '1', address, amount: 0 })) |
|
||||||
} |
|
||||||
|
|
||||||
CoinbaseForm.prototype.renderLoading = function () { |
|
||||||
return h('img', { |
|
||||||
style: { |
|
||||||
width: '27px', |
|
||||||
marginRight: '-27px', |
|
||||||
}, |
|
||||||
src: 'images/loading.svg', |
|
||||||
}) |
|
||||||
} |
|
@ -1,59 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const copyToClipboard = require('copy-to-clipboard') |
|
||||||
|
|
||||||
const Tooltip = require('./tooltip') |
|
||||||
|
|
||||||
module.exports = CopyButton |
|
||||||
|
|
||||||
inherits(CopyButton, Component) |
|
||||||
function CopyButton () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
// As parameters, accepts:
|
|
||||||
// "value", which is the value to copy (mandatory)
|
|
||||||
// "title", which is the text to show on hover (optional, defaults to 'Copy')
|
|
||||||
CopyButton.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const state = this.state || {} |
|
||||||
|
|
||||||
const value = props.value |
|
||||||
const copied = state.copied |
|
||||||
|
|
||||||
const message = copied ? 'Copied' : props.title || ' Copy ' |
|
||||||
|
|
||||||
return h('.copy-button', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h(Tooltip, { |
|
||||||
title: message, |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-clipboard.cursor-pointer.color-orange', { |
|
||||||
style: { |
|
||||||
margin: '5px', |
|
||||||
}, |
|
||||||
onClick: (event) => { |
|
||||||
event.preventDefault() |
|
||||||
event.stopPropagation() |
|
||||||
copyToClipboard(value) |
|
||||||
this.debounceRestore() |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
CopyButton.prototype.debounceRestore = function () { |
|
||||||
this.setState({ copied: true }) |
|
||||||
clearTimeout(this.timeout) |
|
||||||
this.timeout = setTimeout(() => { |
|
||||||
this.setState({ copied: false }) |
|
||||||
}, 850) |
|
||||||
} |
|
@ -1,46 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
const Tooltip = require('./tooltip') |
|
||||||
const copyToClipboard = require('copy-to-clipboard') |
|
||||||
|
|
||||||
module.exports = Copyable |
|
||||||
|
|
||||||
inherits(Copyable, Component) |
|
||||||
function Copyable () { |
|
||||||
Component.call(this) |
|
||||||
this.state = { |
|
||||||
copied: false, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Copyable.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const state = this.state |
|
||||||
const { value, children } = props |
|
||||||
const { copied } = state |
|
||||||
|
|
||||||
return h(Tooltip, { |
|
||||||
title: copied ? 'Copied!' : 'Copy', |
|
||||||
position: 'bottom', |
|
||||||
}, h('span', { |
|
||||||
style: { |
|
||||||
cursor: 'pointer', |
|
||||||
}, |
|
||||||
onClick: (event) => { |
|
||||||
event.preventDefault() |
|
||||||
event.stopPropagation() |
|
||||||
copyToClipboard(value) |
|
||||||
this.debounceRestore() |
|
||||||
}, |
|
||||||
}, children)) |
|
||||||
} |
|
||||||
|
|
||||||
Copyable.prototype.debounceRestore = function () { |
|
||||||
this.setState({ copied: true }) |
|
||||||
clearTimeout(this.timeout) |
|
||||||
this.timeout = setTimeout(() => { |
|
||||||
this.setState({ copied: false }) |
|
||||||
}, 850) |
|
||||||
} |
|
@ -1,60 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
module.exports = RadioList |
|
||||||
|
|
||||||
inherits(RadioList, Component) |
|
||||||
function RadioList () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
RadioList.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const activeClass = '.custom-radio-selected' |
|
||||||
const inactiveClass = '.custom-radio-inactive' |
|
||||||
const { |
|
||||||
labels, |
|
||||||
defaultFocus, |
|
||||||
} = props |
|
||||||
|
|
||||||
|
|
||||||
return ( |
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
fontSize: '12px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.flex-column.custom-radios', { |
|
||||||
style: { |
|
||||||
marginRight: '5px', |
|
||||||
}, |
|
||||||
}, |
|
||||||
labels.map((lable, i) => { |
|
||||||
let isSelcted = (this.state !== null) |
|
||||||
isSelcted = isSelcted ? (this.state.selected === lable) : (defaultFocus === lable) |
|
||||||
return h(isSelcted ? activeClass : inactiveClass, { |
|
||||||
title: lable, |
|
||||||
onClick: (event) => { |
|
||||||
this.setState({selected: event.target.title}) |
|
||||||
props.onClick(event) |
|
||||||
}, |
|
||||||
}) |
|
||||||
}) |
|
||||||
), |
|
||||||
h('.text', {}, |
|
||||||
labels.map((lable) => { |
|
||||||
if (props.subtext) { |
|
||||||
return h('.flex-row', {}, [ |
|
||||||
h('.radio-titles', lable), |
|
||||||
h('.radio-titles-subtext', `- ${props.subtext[lable]}`), |
|
||||||
]) |
|
||||||
} else { |
|
||||||
return h('.radio-titles', lable) |
|
||||||
} |
|
||||||
}) |
|
||||||
), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
@ -1,98 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const PropTypes = require('prop-types') |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const MenuDroppo = require('./menu-droppo') |
|
||||||
const extend = require('xtend') |
|
||||||
|
|
||||||
const noop = () => {} |
|
||||||
|
|
||||||
class Dropdown extends Component { |
|
||||||
render () { |
|
||||||
const { isOpen, onClickOutside, style, innerStyle, children, useCssTransition } = this.props |
|
||||||
|
|
||||||
const innerStyleDefaults = extend({ |
|
||||||
borderRadius: '4px', |
|
||||||
padding: '8px 16px', |
|
||||||
background: 'rgba(0, 0, 0, 0.8)', |
|
||||||
boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px', |
|
||||||
}, innerStyle) |
|
||||||
|
|
||||||
return h( |
|
||||||
MenuDroppo, |
|
||||||
{ |
|
||||||
useCssTransition, |
|
||||||
isOpen, |
|
||||||
zIndex: 11, |
|
||||||
onClickOutside, |
|
||||||
style, |
|
||||||
innerStyle: innerStyleDefaults, |
|
||||||
}, |
|
||||||
[ |
|
||||||
h( |
|
||||||
'style', |
|
||||||
` |
|
||||||
li.dropdown-menu-item:hover { color:rgb(225, 225, 225); } |
|
||||||
li.dropdown-menu-item { color: rgb(185, 185, 185); position: relative } |
|
||||||
` |
|
||||||
), |
|
||||||
...children, |
|
||||||
] |
|
||||||
) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Dropdown.defaultProps = { |
|
||||||
isOpen: false, |
|
||||||
onClick: noop, |
|
||||||
useCssTransition: false, |
|
||||||
} |
|
||||||
|
|
||||||
Dropdown.propTypes = { |
|
||||||
isOpen: PropTypes.bool.isRequired, |
|
||||||
onClick: PropTypes.func.isRequired, |
|
||||||
children: PropTypes.node, |
|
||||||
style: PropTypes.object.isRequired, |
|
||||||
onClickOutside: PropTypes.func, |
|
||||||
innerStyle: PropTypes.object, |
|
||||||
useCssTransition: PropTypes.bool, |
|
||||||
} |
|
||||||
|
|
||||||
class DropdownMenuItem extends Component { |
|
||||||
render () { |
|
||||||
const { onClick, closeMenu, children, style } = this.props |
|
||||||
|
|
||||||
return h( |
|
||||||
'li.dropdown-menu-item', |
|
||||||
{ |
|
||||||
onClick: () => { |
|
||||||
onClick() |
|
||||||
closeMenu() |
|
||||||
}, |
|
||||||
style: Object.assign({ |
|
||||||
listStyle: 'none', |
|
||||||
padding: '8px 0px 8px 0px', |
|
||||||
fontSize: '18px', |
|
||||||
fontStyle: 'normal', |
|
||||||
fontFamily: 'Montserrat Regular', |
|
||||||
cursor: 'pointer', |
|
||||||
display: 'flex', |
|
||||||
justifyContent: 'flex-start', |
|
||||||
alignItems: 'center', |
|
||||||
}, style), |
|
||||||
}, |
|
||||||
children |
|
||||||
) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
DropdownMenuItem.propTypes = { |
|
||||||
closeMenu: PropTypes.func.isRequired, |
|
||||||
onClick: PropTypes.func.isRequired, |
|
||||||
children: PropTypes.node, |
|
||||||
style: PropTypes.object, |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = { |
|
||||||
Dropdown, |
|
||||||
DropdownMenuItem, |
|
||||||
} |
|
@ -1,57 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const findDOMNode = require('react-dom').findDOMNode |
|
||||||
|
|
||||||
module.exports = EditableLabel |
|
||||||
|
|
||||||
inherits(EditableLabel, Component) |
|
||||||
function EditableLabel () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
EditableLabel.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const state = this.state |
|
||||||
|
|
||||||
if (state && state.isEditingLabel) { |
|
||||||
return h('div.editable-label', [ |
|
||||||
h('input.sizing-input', { |
|
||||||
defaultValue: props.textValue, |
|
||||||
maxLength: '20', |
|
||||||
onKeyPress: (event) => { |
|
||||||
this.saveIfEnter(event) |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('button.editable-button', { |
|
||||||
onClick: () => this.saveText(), |
|
||||||
}, 'Save'), |
|
||||||
]) |
|
||||||
} else { |
|
||||||
return h('div.name-label', { |
|
||||||
onClick: (event) => { |
|
||||||
const nameAttribute = event.target.getAttribute('name') |
|
||||||
// checks for class to handle smaller CTA above the account name
|
|
||||||
const classAttribute = event.target.getAttribute('class') |
|
||||||
if (nameAttribute === 'edit' || classAttribute === 'edit-text') { |
|
||||||
this.setState({ isEditingLabel: true }) |
|
||||||
} |
|
||||||
}, |
|
||||||
}, this.props.children) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
EditableLabel.prototype.saveIfEnter = function (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
this.saveText() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
EditableLabel.prototype.saveText = function () { |
|
||||||
// eslint-disable-next-line react/no-find-dom-node
|
|
||||||
var container = findDOMNode(this) |
|
||||||
var text = container.querySelector('.editable-label input').value |
|
||||||
var truncatedText = text.substring(0, 20) |
|
||||||
this.props.saveText(truncatedText) |
|
||||||
this.setState({ isEditingLabel: false, textLabel: truncatedText }) |
|
||||||
} |
|
@ -1,176 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const debounce = require('debounce') |
|
||||||
const copyToClipboard = require('copy-to-clipboard') |
|
||||||
const ENS = require('ethjs-ens') |
|
||||||
const networkMap = require('ethjs-ens/lib/network-map.json') |
|
||||||
const ensRE = /.+\..+$/ |
|
||||||
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' |
|
||||||
const log = require('loglevel') |
|
||||||
|
|
||||||
|
|
||||||
module.exports = EnsInput |
|
||||||
|
|
||||||
inherits(EnsInput, Component) |
|
||||||
function EnsInput () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
EnsInput.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
|
|
||||||
function onInputChange () { |
|
||||||
const network = this.props.network |
|
||||||
const networkHasEnsSupport = getNetworkEnsSupport(network) |
|
||||||
if (!networkHasEnsSupport) return |
|
||||||
|
|
||||||
const recipient = document.querySelector('input[name="address"]').value |
|
||||||
if (recipient.match(ensRE) === null) { |
|
||||||
return this.setState({ |
|
||||||
loadingEns: false, |
|
||||||
ensResolution: null, |
|
||||||
ensFailure: null, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
this.setState({ |
|
||||||
loadingEns: true, |
|
||||||
}) |
|
||||||
this.checkName() |
|
||||||
} |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
style: { width: '100%' }, |
|
||||||
}, [ |
|
||||||
h('input.large-input', { |
|
||||||
name: props.name, |
|
||||||
placeholder: props.placeholder, |
|
||||||
list: 'addresses', |
|
||||||
onChange: onInputChange.bind(this), |
|
||||||
}), |
|
||||||
// The address book functionality.
|
|
||||||
h('datalist#addresses', |
|
||||||
[ |
|
||||||
// Corresponds to the addresses owned.
|
|
||||||
Object.keys(props.identities).map((key) => { |
|
||||||
const identity = props.identities[key] |
|
||||||
return h('option', { |
|
||||||
value: identity.address, |
|
||||||
label: identity.name, |
|
||||||
key: identity.address, |
|
||||||
}) |
|
||||||
}), |
|
||||||
// Corresponds to previously sent-to addresses.
|
|
||||||
props.addressBook.map((identity) => { |
|
||||||
return h('option', { |
|
||||||
value: identity.address, |
|
||||||
label: identity.name, |
|
||||||
key: identity.address, |
|
||||||
}) |
|
||||||
}), |
|
||||||
]), |
|
||||||
this.ensIcon(), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
EnsInput.prototype.componentDidMount = function () { |
|
||||||
const network = this.props.network |
|
||||||
const networkHasEnsSupport = getNetworkEnsSupport(network) |
|
||||||
this.setState({ ensResolution: ZERO_ADDRESS }) |
|
||||||
|
|
||||||
if (networkHasEnsSupport) { |
|
||||||
const provider = global.ethereumProvider |
|
||||||
this.ens = new ENS({ provider, network }) |
|
||||||
this.checkName = debounce(this.lookupEnsName.bind(this), 200) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
EnsInput.prototype.lookupEnsName = function () { |
|
||||||
const recipient = document.querySelector('input[name="address"]').value |
|
||||||
const { ensResolution } = this.state |
|
||||||
|
|
||||||
log.info(`ENS attempting to resolve name: ${recipient}`) |
|
||||||
this.ens.lookup(recipient.trim()) |
|
||||||
.then((address) => { |
|
||||||
if (address === ZERO_ADDRESS) throw new Error('No address has been set for this name.') |
|
||||||
if (address !== ensResolution) { |
|
||||||
this.setState({ |
|
||||||
loadingEns: false, |
|
||||||
ensResolution: address, |
|
||||||
nickname: recipient.trim(), |
|
||||||
hoverText: address + '\nClick to Copy', |
|
||||||
ensFailure: false, |
|
||||||
}) |
|
||||||
} |
|
||||||
}) |
|
||||||
.catch((reason) => { |
|
||||||
log.error(reason) |
|
||||||
return this.setState({ |
|
||||||
loadingEns: false, |
|
||||||
ensResolution: ZERO_ADDRESS, |
|
||||||
ensFailure: true, |
|
||||||
hoverText: reason.message, |
|
||||||
}) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
EnsInput.prototype.componentDidUpdate = function (prevProps, prevState) { |
|
||||||
const state = this.state || {} |
|
||||||
const ensResolution = state.ensResolution |
|
||||||
// If an address is sent without a nickname, meaning not from ENS or from
|
|
||||||
// the user's own accounts, a default of a one-space string is used.
|
|
||||||
const nickname = state.nickname || ' ' |
|
||||||
if (prevState && ensResolution && this.props.onChange && |
|
||||||
ensResolution !== prevState.ensResolution) { |
|
||||||
this.props.onChange(ensResolution, nickname) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
EnsInput.prototype.ensIcon = function (recipient) { |
|
||||||
const { hoverText } = this.state || {} |
|
||||||
return h('span', { |
|
||||||
title: hoverText, |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
padding: '9px', |
|
||||||
transform: 'translatex(-40px)', |
|
||||||
}, |
|
||||||
}, this.ensIconContents(recipient)) |
|
||||||
} |
|
||||||
|
|
||||||
EnsInput.prototype.ensIconContents = function (recipient) { |
|
||||||
const { loadingEns, ensFailure, ensResolution } = this.state || { ensResolution: ZERO_ADDRESS} |
|
||||||
|
|
||||||
if (loadingEns) { |
|
||||||
return h('img', { |
|
||||||
src: 'images/loading.svg', |
|
||||||
style: { |
|
||||||
width: '30px', |
|
||||||
height: '30px', |
|
||||||
transform: 'translateY(-6px)', |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
if (ensFailure) { |
|
||||||
return h('i.fa.fa-warning.fa-lg.warning') |
|
||||||
} |
|
||||||
|
|
||||||
if (ensResolution && (ensResolution !== ZERO_ADDRESS)) { |
|
||||||
return h('i.fa.fa-check-circle.fa-lg.cursor-pointer', { |
|
||||||
style: { color: 'green' }, |
|
||||||
onClick: (event) => { |
|
||||||
event.preventDefault() |
|
||||||
event.stopPropagation() |
|
||||||
copyToClipboard(ensResolution) |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
function getNetworkEnsSupport (network) { |
|
||||||
return Boolean(networkMap[network]) |
|
||||||
} |
|
@ -1,95 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const inherits = require('util').inherits |
|
||||||
const formatBalance = require('../util').formatBalance |
|
||||||
const generateBalanceObject = require('../util').generateBalanceObject |
|
||||||
const Tooltip = require('./tooltip.js') |
|
||||||
const FiatValue = require('./fiat-value.js') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(EthBalanceComponent) |
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
ticker: state.metamask.ticker, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(EthBalanceComponent, Component) |
|
||||||
function EthBalanceComponent () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
EthBalanceComponent.prototype.render = function () { |
|
||||||
var props = this.props |
|
||||||
let { value } = props |
|
||||||
const { ticker, style, width } = props |
|
||||||
var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true |
|
||||||
value = value ? formatBalance(value, 6, needsParse, ticker) : '...' |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.ether-balance.ether-balance-amount', { |
|
||||||
style, |
|
||||||
}, [ |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
display: 'inline', |
|
||||||
width, |
|
||||||
}, |
|
||||||
}, this.renderBalance(value)), |
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
||||||
EthBalanceComponent.prototype.renderBalance = function (value) { |
|
||||||
var props = this.props |
|
||||||
const { conversionRate, shorten, incoming, currentCurrency } = props |
|
||||||
if (value === 'None') return value |
|
||||||
if (value === '...') return value |
|
||||||
var balanceObj = generateBalanceObject(value, shorten ? 1 : 3) |
|
||||||
var balance |
|
||||||
var splitBalance = value.split(' ') |
|
||||||
var ethNumber = splitBalance[0] |
|
||||||
var ethSuffix = splitBalance[1] |
|
||||||
const showFiat = 'showFiat' in props ? props.showFiat : true |
|
||||||
|
|
||||||
if (shorten) { |
|
||||||
balance = balanceObj.shortBalance |
|
||||||
} else { |
|
||||||
balance = balanceObj.balance |
|
||||||
} |
|
||||||
|
|
||||||
var label = balanceObj.label |
|
||||||
|
|
||||||
return ( |
|
||||||
h(Tooltip, { |
|
||||||
position: 'bottom', |
|
||||||
title: `${ethNumber} ${ethSuffix}`, |
|
||||||
}, h('div.flex-column', [ |
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
alignItems: 'flex-end', |
|
||||||
lineHeight: '13px', |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
textRendering: 'geometricPrecision', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
width: '100%', |
|
||||||
textAlign: 'right', |
|
||||||
}, |
|
||||||
}, incoming ? `+${balance}` : balance), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
color: ' #AEAEAE', |
|
||||||
fontSize: '12px', |
|
||||||
marginLeft: '5px', |
|
||||||
}, |
|
||||||
}, label), |
|
||||||
]), |
|
||||||
|
|
||||||
showFiat ? h(FiatValue, { value: props.value, conversionRate, currentCurrency }) : null, |
|
||||||
])) |
|
||||||
) |
|
||||||
} |
|
@ -1,64 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const formatBalance = require('../util').formatBalance |
|
||||||
|
|
||||||
module.exports = FiatValue |
|
||||||
|
|
||||||
inherits(FiatValue, Component) |
|
||||||
function FiatValue () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
FiatValue.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const { conversionRate, currentCurrency } = props |
|
||||||
const renderedCurrency = currentCurrency || '' |
|
||||||
|
|
||||||
const value = formatBalance(props.value, 6) |
|
||||||
|
|
||||||
if (value === 'None') return value |
|
||||||
var fiatDisplayNumber, fiatTooltipNumber |
|
||||||
var splitBalance = value.split(' ') |
|
||||||
|
|
||||||
if (conversionRate !== 0) { |
|
||||||
fiatTooltipNumber = Number(splitBalance[0]) * conversionRate |
|
||||||
fiatDisplayNumber = fiatTooltipNumber.toFixed(2) |
|
||||||
} else { |
|
||||||
fiatDisplayNumber = 'N/A' |
|
||||||
fiatTooltipNumber = 'Unknown' |
|
||||||
} |
|
||||||
|
|
||||||
return fiatDisplay(fiatDisplayNumber, renderedCurrency.toUpperCase()) |
|
||||||
} |
|
||||||
|
|
||||||
function fiatDisplay (fiatDisplayNumber, fiatSuffix) { |
|
||||||
if (fiatDisplayNumber !== 'N/A') { |
|
||||||
return h('.flex-row', { |
|
||||||
style: { |
|
||||||
alignItems: 'flex-end', |
|
||||||
lineHeight: '13px', |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
textRendering: 'geometricPrecision', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
width: '100%', |
|
||||||
textAlign: 'right', |
|
||||||
fontSize: '12px', |
|
||||||
color: '#333333', |
|
||||||
}, |
|
||||||
}, fiatDisplayNumber), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
color: '#AEAEAE', |
|
||||||
marginLeft: '5px', |
|
||||||
fontSize: '12px', |
|
||||||
}, |
|
||||||
}, fiatSuffix), |
|
||||||
]) |
|
||||||
} else { |
|
||||||
return h('div') |
|
||||||
} |
|
||||||
} |
|
@ -1,154 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const BN = ethUtil.BN |
|
||||||
const extend = require('xtend') |
|
||||||
|
|
||||||
module.exports = HexAsDecimalInput |
|
||||||
|
|
||||||
inherits(HexAsDecimalInput, Component) |
|
||||||
function HexAsDecimalInput () { |
|
||||||
this.state = { invalid: null } |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
/* Hex as Decimal Input |
|
||||||
* |
|
||||||
* A component for allowing easy, decimal editing |
|
||||||
* of a passed in hex string value. |
|
||||||
* |
|
||||||
* On change, calls back its `onChange` function parameter |
|
||||||
* and passes it an updated hex string. |
|
||||||
*/ |
|
||||||
|
|
||||||
HexAsDecimalInput.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const state = this.state |
|
||||||
|
|
||||||
const { value, onChange, min, max } = props |
|
||||||
|
|
||||||
const toEth = props.toEth |
|
||||||
const suffix = props.suffix |
|
||||||
const decimalValue = decimalize(value, toEth) |
|
||||||
const style = props.style |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.flex-column', [ |
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
alignItems: 'flex-end', |
|
||||||
lineHeight: '13px', |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
textRendering: 'geometricPrecision', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('input.hex-input', { |
|
||||||
type: 'number', |
|
||||||
required: true, |
|
||||||
min: min, |
|
||||||
max: max, |
|
||||||
style: extend({ |
|
||||||
display: 'block', |
|
||||||
textAlign: 'right', |
|
||||||
backgroundColor: 'transparent', |
|
||||||
border: '1px solid #bdbdbd', |
|
||||||
|
|
||||||
}, style), |
|
||||||
value: parseInt(decimalValue), |
|
||||||
onBlur: (event) => { |
|
||||||
this.updateValidity(event) |
|
||||||
}, |
|
||||||
onChange: (event) => { |
|
||||||
this.updateValidity(event) |
|
||||||
const hexString = (event.target.value === '') ? '' : hexify(event.target.value) |
|
||||||
onChange(hexString) |
|
||||||
}, |
|
||||||
onInvalid: (event) => { |
|
||||||
const msg = this.constructWarning() |
|
||||||
if (msg === state.invalid) { |
|
||||||
return |
|
||||||
} |
|
||||||
this.setState({ invalid: msg }) |
|
||||||
event.preventDefault() |
|
||||||
return false |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
color: ' #AEAEAE', |
|
||||||
fontSize: '12px', |
|
||||||
marginLeft: '5px', |
|
||||||
marginRight: '6px', |
|
||||||
width: '20px', |
|
||||||
}, |
|
||||||
}, suffix), |
|
||||||
]), |
|
||||||
|
|
||||||
state.invalid ? h('span.error', { |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
right: '0px', |
|
||||||
textAlign: 'right', |
|
||||||
transform: 'translateY(26px)', |
|
||||||
padding: '3px', |
|
||||||
background: 'rgba(255,255,255,0.85)', |
|
||||||
zIndex: '1', |
|
||||||
textTransform: 'capitalize', |
|
||||||
border: '2px solid #E20202', |
|
||||||
}, |
|
||||||
}, state.invalid) : null, |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
HexAsDecimalInput.prototype.setValid = function (message) { |
|
||||||
this.setState({ invalid: null }) |
|
||||||
} |
|
||||||
|
|
||||||
HexAsDecimalInput.prototype.updateValidity = function (event) { |
|
||||||
const target = event.target |
|
||||||
const value = this.props.value |
|
||||||
const newValue = target.value |
|
||||||
|
|
||||||
if (value === newValue) { |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
const valid = target.checkValidity() |
|
||||||
if (valid) { |
|
||||||
this.setState({ invalid: null }) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
HexAsDecimalInput.prototype.constructWarning = function () { |
|
||||||
const { name, min, max } = this.props |
|
||||||
let message = name ? name + ' ' : '' |
|
||||||
|
|
||||||
if (min && max) { |
|
||||||
message += `must be greater than or equal to ${min} and less than or equal to ${max}.` |
|
||||||
} else if (min) { |
|
||||||
message += `must be greater than or equal to ${min}.` |
|
||||||
} else if (max) { |
|
||||||
message += `must be less than or equal to ${max}.` |
|
||||||
} else { |
|
||||||
message += 'Invalid input.' |
|
||||||
} |
|
||||||
|
|
||||||
return message |
|
||||||
} |
|
||||||
|
|
||||||
function hexify (decimalString) { |
|
||||||
const hexBN = new BN(parseInt(decimalString), 10) |
|
||||||
return '0x' + hexBN.toString('hex') |
|
||||||
} |
|
||||||
|
|
||||||
function decimalize (input, toEth) { |
|
||||||
if (input === '') { |
|
||||||
return '' |
|
||||||
} else { |
|
||||||
const strippedInput = ethUtil.stripHexPrefix(input) |
|
||||||
const inputBN = new BN(strippedInput, 'hex') |
|
||||||
return inputBN.toString(10) |
|
||||||
} |
|
||||||
} |
|
@ -1,74 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const isNode = require('detect-node') |
|
||||||
const findDOMNode = require('react-dom').findDOMNode |
|
||||||
const jazzicon = require('jazzicon') |
|
||||||
const iconFactoryGen = require('../../lib/icon-factory') |
|
||||||
const iconFactory = iconFactoryGen(jazzicon) |
|
||||||
|
|
||||||
module.exports = IdenticonComponent |
|
||||||
|
|
||||||
inherits(IdenticonComponent, Component) |
|
||||||
function IdenticonComponent () { |
|
||||||
Component.call(this) |
|
||||||
|
|
||||||
this.defaultDiameter = 46 |
|
||||||
} |
|
||||||
|
|
||||||
IdenticonComponent.prototype.render = function () { |
|
||||||
var props = this.props |
|
||||||
var diameter = props.diameter || this.defaultDiameter |
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
key: 'identicon-' + this.props.address, |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
alignItems: 'center', |
|
||||||
justifyContent: 'center', |
|
||||||
height: diameter, |
|
||||||
width: diameter, |
|
||||||
borderRadius: diameter / 2, |
|
||||||
overflow: 'hidden', |
|
||||||
}, |
|
||||||
}) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
IdenticonComponent.prototype.componentDidMount = function () { |
|
||||||
var props = this.props |
|
||||||
const { address } = props |
|
||||||
|
|
||||||
if (!address) return |
|
||||||
|
|
||||||
// eslint-disable-next-line react/no-find-dom-node
|
|
||||||
var container = findDOMNode(this) |
|
||||||
|
|
||||||
var diameter = props.diameter || this.defaultDiameter |
|
||||||
if (!isNode) { |
|
||||||
var img = iconFactory.iconForAddress(address, diameter) |
|
||||||
container.appendChild(img) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
IdenticonComponent.prototype.componentDidUpdate = function () { |
|
||||||
var props = this.props |
|
||||||
const { address } = props |
|
||||||
|
|
||||||
if (!address) return |
|
||||||
|
|
||||||
// eslint-disable-next-line react/no-find-dom-node
|
|
||||||
var container = findDOMNode(this) |
|
||||||
|
|
||||||
var children = container.children |
|
||||||
for (var i = 0; i < children.length; i++) { |
|
||||||
container.removeChild(children[i]) |
|
||||||
} |
|
||||||
|
|
||||||
var diameter = props.diameter || this.defaultDiameter |
|
||||||
if (!isNode) { |
|
||||||
var img = iconFactory.iconForAddress(address, diameter) |
|
||||||
container.appendChild(img) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
@ -1,55 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
|
|
||||||
|
|
||||||
inherits(LoadingIndicator, Component) |
|
||||||
module.exports = LoadingIndicator |
|
||||||
|
|
||||||
function LoadingIndicator () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
LoadingIndicator.prototype.render = function () { |
|
||||||
const { isLoading, loadingMessage, canBypass, bypass } = this.props |
|
||||||
|
|
||||||
return ( |
|
||||||
isLoading ? h('.full-flex-height', { |
|
||||||
style: { |
|
||||||
left: '0px', |
|
||||||
zIndex: 10, |
|
||||||
position: 'absolute', |
|
||||||
flexDirection: 'column', |
|
||||||
display: 'flex', |
|
||||||
justifyContent: 'center', |
|
||||||
alignItems: 'center', |
|
||||||
height: '100%', |
|
||||||
width: '100%', |
|
||||||
background: 'rgba(255, 255, 255, 0.8)', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
canBypass ? h('i.fa.fa-close.cursor-pointer.close-loading', { |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
top: '1px', |
|
||||||
right: '15px', |
|
||||||
color: '#AEAEAE', |
|
||||||
}, |
|
||||||
onClick: bypass, |
|
||||||
}) : null, |
|
||||||
|
|
||||||
h('img', { |
|
||||||
src: 'images/loading.svg', |
|
||||||
}), |
|
||||||
|
|
||||||
h('br'), |
|
||||||
|
|
||||||
showMessageIfAny(loadingMessage), |
|
||||||
]) : null |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
function showMessageIfAny (loadingMessage) { |
|
||||||
if (!loadingMessage) return null |
|
||||||
return h('span', loadingMessage) |
|
||||||
} |
|
@ -1,59 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const metamaskLogo = require('metamask-logo') |
|
||||||
const debounce = require('debounce') |
|
||||||
|
|
||||||
module.exports = Mascot |
|
||||||
|
|
||||||
inherits(Mascot, Component) |
|
||||||
function Mascot () { |
|
||||||
Component.call(this) |
|
||||||
this.logo = metamaskLogo({ |
|
||||||
followMouse: true, |
|
||||||
pxNotRatio: true, |
|
||||||
width: 200, |
|
||||||
height: 200, |
|
||||||
}) |
|
||||||
|
|
||||||
this.refollowMouse = debounce(this.logo.setFollowMouse.bind(this.logo, true), 1000) |
|
||||||
this.unfollowMouse = this.logo.setFollowMouse.bind(this.logo, false) |
|
||||||
} |
|
||||||
|
|
||||||
Mascot.prototype.render = function () { |
|
||||||
// this is a bit hacky
|
|
||||||
// the event emitter is on `this.props`
|
|
||||||
// and we dont get that until render
|
|
||||||
this.handleAnimationEvents() |
|
||||||
|
|
||||||
return h('#metamask-mascot-container', { |
|
||||||
style: { zIndex: 0 }, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
Mascot.prototype.componentDidMount = function () { |
|
||||||
var targetDivId = 'metamask-mascot-container' |
|
||||||
var container = document.getElementById(targetDivId) |
|
||||||
container.appendChild(this.logo.container) |
|
||||||
} |
|
||||||
|
|
||||||
Mascot.prototype.componentWillUnmount = function () { |
|
||||||
this.animations = this.props.animationEventEmitter |
|
||||||
this.animations.removeAllListeners() |
|
||||||
this.logo.container.remove() |
|
||||||
this.logo.stopAnimation() |
|
||||||
} |
|
||||||
|
|
||||||
Mascot.prototype.handleAnimationEvents = function () { |
|
||||||
// only setup listeners once
|
|
||||||
if (this.animations) return |
|
||||||
this.animations = this.props.animationEventEmitter |
|
||||||
this.animations.on('point', this.lookAt.bind(this)) |
|
||||||
this.animations.on('setFollowMouse', this.logo.setFollowMouse.bind(this.logo)) |
|
||||||
} |
|
||||||
|
|
||||||
Mascot.prototype.lookAt = function (target) { |
|
||||||
this.unfollowMouse() |
|
||||||
this.logo.lookAt(target) |
|
||||||
this.refollowMouse() |
|
||||||
} |
|
@ -1,132 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const findDOMNode = require('react-dom').findDOMNode |
|
||||||
const ReactCSSTransitionGroup = require('react-addons-css-transition-group') |
|
||||||
|
|
||||||
module.exports = MenuDroppoComponent |
|
||||||
|
|
||||||
|
|
||||||
inherits(MenuDroppoComponent, Component) |
|
||||||
function MenuDroppoComponent () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
MenuDroppoComponent.prototype.render = function () { |
|
||||||
const speed = this.props.speed || '300ms' |
|
||||||
const useCssTransition = this.props.useCssTransition |
|
||||||
const zIndex = ('zIndex' in this.props) ? this.props.zIndex : 0 |
|
||||||
|
|
||||||
this.manageListeners() |
|
||||||
|
|
||||||
const style = this.props.style || {} |
|
||||||
if (!('position' in style)) { |
|
||||||
style.position = 'fixed' |
|
||||||
} |
|
||||||
style.zIndex = zIndex |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.menu-droppo-container', { |
|
||||||
style, |
|
||||||
}, [ |
|
||||||
h('style', ` |
|
||||||
.menu-droppo-enter { |
|
||||||
transition: transform ${speed} ease-in-out; |
|
||||||
transform: translateY(-200%); |
|
||||||
} |
|
||||||
|
|
||||||
.menu-droppo-enter.menu-droppo-enter-active { |
|
||||||
transition: transform ${speed} ease-in-out; |
|
||||||
transform: translateY(0%); |
|
||||||
} |
|
||||||
|
|
||||||
.menu-droppo-leave { |
|
||||||
transition: transform ${speed} ease-in-out; |
|
||||||
transform: translateY(0%); |
|
||||||
} |
|
||||||
|
|
||||||
.menu-droppo-leave.menu-droppo-leave-active { |
|
||||||
transition: transform ${speed} ease-in-out; |
|
||||||
transform: translateY(-200%); |
|
||||||
} |
|
||||||
`),
|
|
||||||
|
|
||||||
useCssTransition |
|
||||||
? h(ReactCSSTransitionGroup, { |
|
||||||
className: 'css-transition-group', |
|
||||||
transitionName: 'menu-droppo', |
|
||||||
transitionEnterTimeout: parseInt(speed), |
|
||||||
transitionLeaveTimeout: parseInt(speed), |
|
||||||
}, this.renderPrimary()) |
|
||||||
: this.renderPrimary(), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
MenuDroppoComponent.prototype.renderPrimary = function () { |
|
||||||
const isOpen = this.props.isOpen |
|
||||||
if (!isOpen) { |
|
||||||
return null |
|
||||||
} |
|
||||||
|
|
||||||
const innerStyle = this.props.innerStyle || {} |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.menu-droppo', { |
|
||||||
key: 'menu-droppo-drawer', |
|
||||||
style: innerStyle, |
|
||||||
}, |
|
||||||
[ this.props.children ]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
MenuDroppoComponent.prototype.manageListeners = function () { |
|
||||||
const isOpen = this.props.isOpen |
|
||||||
const onClickOutside = this.props.onClickOutside |
|
||||||
|
|
||||||
if (isOpen) { |
|
||||||
this.outsideClickHandler = onClickOutside |
|
||||||
} else if (isOpen) { |
|
||||||
this.outsideClickHandler = null |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
MenuDroppoComponent.prototype.componentDidMount = function () { |
|
||||||
if (this && document.body) { |
|
||||||
this.globalClickHandler = this.globalClickOccurred.bind(this) |
|
||||||
document.body.addEventListener('click', this.globalClickHandler) |
|
||||||
// eslint-disable-next-line react/no-find-dom-node
|
|
||||||
var container = findDOMNode(this) |
|
||||||
this.container = container |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
MenuDroppoComponent.prototype.componentWillUnmount = function () { |
|
||||||
if (this && document.body) { |
|
||||||
document.body.removeEventListener('click', this.globalClickHandler) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
MenuDroppoComponent.prototype.globalClickOccurred = function (event) { |
|
||||||
const target = event.target |
|
||||||
// eslint-disable-next-line react/no-find-dom-node
|
|
||||||
const container = findDOMNode(this) |
|
||||||
|
|
||||||
if (target !== container && |
|
||||||
!isDescendant(this.container, event.target) && |
|
||||||
this.outsideClickHandler) { |
|
||||||
this.outsideClickHandler(event) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
function isDescendant (parent, child) { |
|
||||||
var node = child.parentNode |
|
||||||
while (node !== null) { |
|
||||||
if (node === parent) { |
|
||||||
return true |
|
||||||
} |
|
||||||
node = node.parentNode |
|
||||||
} |
|
||||||
|
|
||||||
return false |
|
||||||
} |
|
@ -1,74 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const Identicon = require('./identicon') |
|
||||||
|
|
||||||
module.exports = AccountPanel |
|
||||||
|
|
||||||
|
|
||||||
inherits(AccountPanel, Component) |
|
||||||
function AccountPanel () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
AccountPanel.prototype.render = function () { |
|
||||||
var props = this.props |
|
||||||
var picOrder = props.picOrder || 'left' |
|
||||||
const { imageSeed } = props |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.identity-panel.flex-row.flex-left', { |
|
||||||
style: { |
|
||||||
cursor: props.onClick ? 'pointer' : undefined, |
|
||||||
}, |
|
||||||
onClick: props.onClick, |
|
||||||
}, [ |
|
||||||
|
|
||||||
this.genIcon(imageSeed, picOrder), |
|
||||||
|
|
||||||
h('div.flex-column.flex-justify-center', { |
|
||||||
style: { |
|
||||||
lineHeight: '15px', |
|
||||||
order: 2, |
|
||||||
display: 'flex', |
|
||||||
alignItems: picOrder === 'left' ? 'flex-begin' : 'flex-end', |
|
||||||
}, |
|
||||||
}, this.props.children), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
AccountPanel.prototype.genIcon = function (seed, picOrder) { |
|
||||||
const props = this.props |
|
||||||
|
|
||||||
// When there is no seed value, this is a contract creation.
|
|
||||||
// We then show the contract icon.
|
|
||||||
if (!seed) { |
|
||||||
return h('.identicon-wrapper.flex-column.select-none', { |
|
||||||
style: { |
|
||||||
order: picOrder === 'left' ? 1 : 3, |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-file-text-o.fa-lg', { |
|
||||||
style: { |
|
||||||
fontSize: '42px', |
|
||||||
transform: 'translate(0px, -16px)', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
// If there was a seed, we return an identicon for that address.
|
|
||||||
return h('.identicon-wrapper.flex-column.select-none', { |
|
||||||
style: { |
|
||||||
order: picOrder === 'left' ? 1 : 3, |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(Identicon, { |
|
||||||
address: seed, |
|
||||||
imageify: props.imageifyIdenticons, |
|
||||||
}), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
@ -1,131 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
module.exports = Network |
|
||||||
|
|
||||||
inherits(Network, Component) |
|
||||||
|
|
||||||
function Network () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
Network.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const networkNumber = props.network |
|
||||||
let providerName |
|
||||||
try { |
|
||||||
providerName = props.provider.type |
|
||||||
} catch (e) { |
|
||||||
providerName = null |
|
||||||
} |
|
||||||
let iconName, hoverText |
|
||||||
|
|
||||||
if (networkNumber === 'loading') { |
|
||||||
return h('span.pointer', { |
|
||||||
className: props.onClick && 'pointer', |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
alignItems: 'center', |
|
||||||
flexDirection: 'row', |
|
||||||
}, |
|
||||||
onClick: (event) => props.onClick && props.onClick(event), |
|
||||||
}, [ |
|
||||||
props.onClick && h('img', { |
|
||||||
title: 'Attempting to connect to blockchain.', |
|
||||||
style: { |
|
||||||
width: '27px', |
|
||||||
}, |
|
||||||
src: 'images/loading.svg', |
|
||||||
}), |
|
||||||
h('i.fa.fa-caret-down'), |
|
||||||
]) |
|
||||||
} else if (providerName === 'mainnet') { |
|
||||||
hoverText = 'Main Ethereum Network' |
|
||||||
iconName = 'ethereum-network' |
|
||||||
} else if (providerName === 'ropsten') { |
|
||||||
hoverText = 'Ropsten Test Network' |
|
||||||
iconName = 'ropsten-test-network' |
|
||||||
} else if (parseInt(networkNumber) === 3) { |
|
||||||
hoverText = 'Ropsten Test Network' |
|
||||||
iconName = 'ropsten-test-network' |
|
||||||
} else if (providerName === 'kovan') { |
|
||||||
hoverText = 'Kovan Test Network' |
|
||||||
iconName = 'kovan-test-network' |
|
||||||
} else if (providerName === 'rinkeby') { |
|
||||||
hoverText = 'Rinkeby Test Network' |
|
||||||
iconName = 'rinkeby-test-network' |
|
||||||
} else { |
|
||||||
hoverText = 'Unknown Private Network' |
|
||||||
iconName = 'unknown-private-network' |
|
||||||
} |
|
||||||
|
|
||||||
return ( |
|
||||||
h('#network_component', { |
|
||||||
className: props.onClick && 'pointer', |
|
||||||
title: hoverText, |
|
||||||
onClick: (event) => props.onClick && props.onClick(event), |
|
||||||
}, [ |
|
||||||
(function () { |
|
||||||
switch (iconName) { |
|
||||||
case 'ethereum-network': |
|
||||||
return h('.network-indicator', [ |
|
||||||
h('.menu-icon.diamond'), |
|
||||||
h('.network-name', { |
|
||||||
style: { |
|
||||||
color: '#039396', |
|
||||||
}}, |
|
||||||
'Main Network'), |
|
||||||
props.onClick && h('i.fa.fa-caret-down.fa-lg'), |
|
||||||
]) |
|
||||||
case 'ropsten-test-network': |
|
||||||
return h('.network-indicator', [ |
|
||||||
h('.menu-icon.red-dot'), |
|
||||||
h('.network-name', { |
|
||||||
style: { |
|
||||||
color: '#ff6666', |
|
||||||
}}, |
|
||||||
'Ropsten Test Net'), |
|
||||||
props.onClick && h('i.fa.fa-caret-down.fa-lg'), |
|
||||||
]) |
|
||||||
case 'kovan-test-network': |
|
||||||
return h('.network-indicator', [ |
|
||||||
h('.menu-icon.hollow-diamond'), |
|
||||||
h('.network-name', { |
|
||||||
style: { |
|
||||||
color: '#690496', |
|
||||||
}}, |
|
||||||
'Kovan Test Net'), |
|
||||||
props.onClick && h('i.fa.fa-caret-down.fa-lg'), |
|
||||||
]) |
|
||||||
case 'rinkeby-test-network': |
|
||||||
return h('.network-indicator', [ |
|
||||||
h('.menu-icon.golden-square'), |
|
||||||
h('.network-name', { |
|
||||||
style: { |
|
||||||
color: '#e7a218', |
|
||||||
}}, |
|
||||||
'Rinkeby Test Net'), |
|
||||||
props.onClick && h('i.fa.fa-caret-down.fa-lg'), |
|
||||||
]) |
|
||||||
default: |
|
||||||
return h('.network-indicator', [ |
|
||||||
h('i.fa.fa-question-circle.fa-lg', { |
|
||||||
style: { |
|
||||||
margin: '10px', |
|
||||||
color: 'rgb(125, 128, 130)', |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
h('.network-name', { |
|
||||||
style: { |
|
||||||
color: '#AEAEAE', |
|
||||||
}}, |
|
||||||
'Private Network'), |
|
||||||
props.onClick && h('i.fa.fa-caret-down.fa-lg'), |
|
||||||
]) |
|
||||||
} |
|
||||||
})(), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
@ -1,145 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const ReactMarkdown = require('react-markdown') |
|
||||||
const linker = require('extension-link-enabler') |
|
||||||
const findDOMNode = require('react-dom').findDOMNode |
|
||||||
|
|
||||||
module.exports = Notice |
|
||||||
|
|
||||||
inherits(Notice, Component) |
|
||||||
function Notice () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
Notice.prototype.render = function () { |
|
||||||
const { notice, onConfirm } = this.props |
|
||||||
const { title, date, body } = notice |
|
||||||
const state = this.state || { disclaimerDisabled: true } |
|
||||||
const disabled = state.disclaimerDisabled |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.flex-column.flex-center.flex-grow', { |
|
||||||
style: { |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('h3.flex-center.text-transform-uppercase.terms-header', { |
|
||||||
style: { |
|
||||||
background: '#EBEBEB', |
|
||||||
color: '#AEAEAE', |
|
||||||
width: '100%', |
|
||||||
fontSize: '20px', |
|
||||||
textAlign: 'center', |
|
||||||
padding: 6, |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
title, |
|
||||||
]), |
|
||||||
|
|
||||||
h('h5.flex-center.text-transform-uppercase.terms-header', { |
|
||||||
style: { |
|
||||||
background: '#EBEBEB', |
|
||||||
color: '#AEAEAE', |
|
||||||
marginBottom: 24, |
|
||||||
width: '100%', |
|
||||||
fontSize: '20px', |
|
||||||
textAlign: 'center', |
|
||||||
padding: 6, |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
date, |
|
||||||
]), |
|
||||||
|
|
||||||
h('style', ` |
|
||||||
|
|
||||||
.markdown { |
|
||||||
overflow-x: hidden; |
|
||||||
} |
|
||||||
|
|
||||||
.markdown h1, .markdown h2, .markdown h3 { |
|
||||||
margin: 10px 0; |
|
||||||
font-weight: bold; |
|
||||||
} |
|
||||||
|
|
||||||
.markdown strong { |
|
||||||
font-weight: bold; |
|
||||||
} |
|
||||||
.markdown em { |
|
||||||
font-style: italic; |
|
||||||
} |
|
||||||
|
|
||||||
.markdown p { |
|
||||||
margin: 10px 0; |
|
||||||
} |
|
||||||
|
|
||||||
.markdown a { |
|
||||||
color: #df6b0e; |
|
||||||
} |
|
||||||
|
|
||||||
`),
|
|
||||||
|
|
||||||
h('div.markdown', { |
|
||||||
onScroll: (e) => { |
|
||||||
var object = e.currentTarget |
|
||||||
if (object.offsetHeight + object.scrollTop + 100 >= object.scrollHeight) { |
|
||||||
this.setState({disclaimerDisabled: false}) |
|
||||||
} |
|
||||||
}, |
|
||||||
style: { |
|
||||||
background: 'rgb(235, 235, 235)', |
|
||||||
height: '310px', |
|
||||||
padding: '6px', |
|
||||||
width: '90%', |
|
||||||
overflowY: 'scroll', |
|
||||||
scroll: 'auto', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(ReactMarkdown, { |
|
||||||
className: 'notice-box', |
|
||||||
source: body, |
|
||||||
skipHtml: true, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
h('button', { |
|
||||||
disabled, |
|
||||||
onClick: () => { |
|
||||||
this.setState({disclaimerDisabled: true}) |
|
||||||
onConfirm() |
|
||||||
}, |
|
||||||
style: { |
|
||||||
marginTop: '18px', |
|
||||||
}, |
|
||||||
}, 'Accept'), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
Notice.prototype.setInitialDisclaimerState = function () { |
|
||||||
if (document.getElementsByClassName('notice-box')[0].clientHeight < 310) { |
|
||||||
this.setState({disclaimerDisabled: false}) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Notice.prototype.componentDidMount = function () { |
|
||||||
// eslint-disable-next-line react/no-find-dom-node
|
|
||||||
var node = findDOMNode(this) |
|
||||||
linker.setupListener(node) |
|
||||||
this.setInitialDisclaimerState() |
|
||||||
} |
|
||||||
|
|
||||||
Notice.prototype.componentDidUpdate = function (prevProps) { |
|
||||||
const { notice: { id } = {} } = this.props |
|
||||||
const { notice: { id: prevNoticeId } = {} } = prevProps |
|
||||||
|
|
||||||
if (id !== prevNoticeId) { |
|
||||||
this.setInitialDisclaimerState() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Notice.prototype.componentWillUnmount = function () { |
|
||||||
// eslint-disable-next-line react/no-find-dom-node
|
|
||||||
var node = findDOMNode(this) |
|
||||||
linker.teardownListener(node) |
|
||||||
} |
|
@ -1,50 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
const AccountPanel = require('./account-panel') |
|
||||||
|
|
||||||
module.exports = PendingMsgDetails |
|
||||||
|
|
||||||
inherits(PendingMsgDetails, Component) |
|
||||||
function PendingMsgDetails () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
PendingMsgDetails.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
var msgData = state.txData |
|
||||||
|
|
||||||
var msgParams = msgData.msgParams || {} |
|
||||||
var address = msgParams.from || state.selectedAddress |
|
||||||
var identity = state.identities[address] || { address: address } |
|
||||||
var account = state.accounts[address] || { address: address } |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
key: msgData.id, |
|
||||||
style: { |
|
||||||
margin: '10px 20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// account that will sign
|
|
||||||
h(AccountPanel, { |
|
||||||
showFullAddress: true, |
|
||||||
identity: identity, |
|
||||||
account: account, |
|
||||||
imageifyIdenticons: state.imageifyIdenticons, |
|
||||||
}), |
|
||||||
|
|
||||||
// message data
|
|
||||||
h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [ |
|
||||||
h('.flex-column.flex-space-between', [ |
|
||||||
h('label.font-small', 'MESSAGE'), |
|
||||||
h('span.font-small', msgParams.data), |
|
||||||
]), |
|
||||||
]), |
|
||||||
|
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
@ -1,70 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const PendingTxDetails = require('./pending-msg-details') |
|
||||||
|
|
||||||
module.exports = PendingMsg |
|
||||||
|
|
||||||
inherits(PendingMsg, Component) |
|
||||||
function PendingMsg () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
PendingMsg.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
var msgData = state.txData |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('div', { |
|
||||||
key: msgData.id, |
|
||||||
style: { |
|
||||||
maxWidth: '350px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// header
|
|
||||||
h('h3', { |
|
||||||
style: { |
|
||||||
fontWeight: 'bold', |
|
||||||
textAlign: 'center', |
|
||||||
}, |
|
||||||
}, 'Sign Message'), |
|
||||||
|
|
||||||
h('.error', { |
|
||||||
style: { |
|
||||||
margin: '10px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
`Signing this message can have
|
|
||||||
dangerous side effects. Only sign messages from |
|
||||||
sites you fully trust with your entire account. |
|
||||||
This dangerous method will be removed in a future version. `,
|
|
||||||
h('a', { |
|
||||||
href: 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527', |
|
||||||
style: { color: 'rgb(247, 134, 28)' }, |
|
||||||
onClick: (event) => { |
|
||||||
event.preventDefault() |
|
||||||
const url = 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527' |
|
||||||
global.platform.openWindow({ url }) |
|
||||||
}, |
|
||||||
}, 'Read more here.'), |
|
||||||
]), |
|
||||||
|
|
||||||
// message details
|
|
||||||
h(PendingTxDetails, state), |
|
||||||
|
|
||||||
// sign + cancel
|
|
||||||
h('.flex-row.flex-space-around', [ |
|
||||||
h('button', { |
|
||||||
onClick: state.cancelMessage, |
|
||||||
}, 'Cancel'), |
|
||||||
h('button', { |
|
||||||
onClick: state.signMessage, |
|
||||||
}, 'Sign'), |
|
||||||
]), |
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
||||||
|
|
@ -1,60 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
const AccountPanel = require('./account-panel') |
|
||||||
const BinaryRenderer = require('./binary-renderer') |
|
||||||
|
|
||||||
module.exports = PendingMsgDetails |
|
||||||
|
|
||||||
inherits(PendingMsgDetails, Component) |
|
||||||
function PendingMsgDetails () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
PendingMsgDetails.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
var msgData = state.txData |
|
||||||
|
|
||||||
var msgParams = msgData.msgParams || {} |
|
||||||
var address = msgParams.from || state.selectedAddress |
|
||||||
var identity = state.identities[address] || { address: address } |
|
||||||
var account = state.accounts[address] || { address: address } |
|
||||||
|
|
||||||
var { data } = msgParams |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
key: msgData.id, |
|
||||||
style: { |
|
||||||
margin: '10px 20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// account that will sign
|
|
||||||
h(AccountPanel, { |
|
||||||
showFullAddress: true, |
|
||||||
identity: identity, |
|
||||||
account: account, |
|
||||||
imageifyIdenticons: state.imageifyIdenticons, |
|
||||||
}), |
|
||||||
|
|
||||||
// message data
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
height: '260px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('label.font-small', { style: { display: 'block' } }, 'MESSAGE'), |
|
||||||
h(BinaryRenderer, { |
|
||||||
value: data, |
|
||||||
style: { |
|
||||||
height: '215px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
@ -1,47 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const PendingTxDetails = require('./pending-personal-msg-details') |
|
||||||
|
|
||||||
module.exports = PendingMsg |
|
||||||
|
|
||||||
inherits(PendingMsg, Component) |
|
||||||
function PendingMsg () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
PendingMsg.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
var msgData = state.txData |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('div', { |
|
||||||
key: msgData.id, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// header
|
|
||||||
h('h3', { |
|
||||||
style: { |
|
||||||
fontWeight: 'bold', |
|
||||||
textAlign: 'center', |
|
||||||
}, |
|
||||||
}, 'Sign Message'), |
|
||||||
|
|
||||||
// message details
|
|
||||||
h(PendingTxDetails, state), |
|
||||||
|
|
||||||
// sign + cancel
|
|
||||||
h('.flex-row.flex-space-around', [ |
|
||||||
h('button', { |
|
||||||
onClick: state.cancelPersonalMessage, |
|
||||||
}, 'Cancel'), |
|
||||||
h('button', { |
|
||||||
onClick: state.signPersonalMessage, |
|
||||||
}, 'Sign'), |
|
||||||
]), |
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
||||||
|
|
@ -1,519 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const actions = require('../../../ui/app/actions') |
|
||||||
const clone = require('clone') |
|
||||||
const log = require('loglevel') |
|
||||||
|
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
const BN = ethUtil.BN |
|
||||||
const hexToBn = require('../../../app/scripts/lib/hex-to-bn') |
|
||||||
const util = require('../util') |
|
||||||
const MiniAccountPanel = require('./mini-account-panel') |
|
||||||
const Copyable = require('./copyable') |
|
||||||
const EthBalance = require('./eth-balance') |
|
||||||
const addressSummary = util.addressSummary |
|
||||||
const nameForAddress = require('../../lib/contract-namer') |
|
||||||
const BNInput = require('./bn-as-decimal-input') |
|
||||||
|
|
||||||
const MIN_GAS_PRICE_BN = new BN('0') |
|
||||||
const MIN_GAS_LIMIT_BN = new BN('21000') |
|
||||||
|
|
||||||
module.exports = connect()(PendingTx) |
|
||||||
|
|
||||||
|
|
||||||
inherits(PendingTx, Component) |
|
||||||
function PendingTx () { |
|
||||||
Component.call(this) |
|
||||||
this.state = { |
|
||||||
valid: true, |
|
||||||
txData: null, |
|
||||||
submitting: false, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const { currentCurrency, blockGasLimit } = props |
|
||||||
|
|
||||||
const conversionRate = props.conversionRate |
|
||||||
const txMeta = this.gatherTxMeta() |
|
||||||
const txParams = txMeta.txParams || {} |
|
||||||
|
|
||||||
// Allow retry txs
|
|
||||||
const { lastGasPrice } = txMeta |
|
||||||
let forceGasMin |
|
||||||
if (lastGasPrice) { |
|
||||||
const stripped = ethUtil.stripHexPrefix(lastGasPrice) |
|
||||||
const lastGas = new BN(stripped, 16) |
|
||||||
const priceBump = lastGas.divn('10') |
|
||||||
forceGasMin = lastGas.add(priceBump) |
|
||||||
} |
|
||||||
|
|
||||||
// Account Details
|
|
||||||
const address = txParams.from || props.selectedAddress |
|
||||||
const identity = props.identities[address] || { address: address } |
|
||||||
const account = props.accounts[address] |
|
||||||
const balance = account ? account.balance : '0x0' |
|
||||||
|
|
||||||
// recipient check
|
|
||||||
const isValidAddress = !txParams.to || util.isValidAddress(txParams.to) |
|
||||||
|
|
||||||
// Gas
|
|
||||||
const gas = txParams.gas |
|
||||||
const gasBn = hexToBn(gas) |
|
||||||
// default to 8MM gas limit
|
|
||||||
const gasLimit = new BN(parseInt(blockGasLimit) || '8000000') |
|
||||||
const safeGasLimitBN = this.bnMultiplyByFraction(gasLimit, 99, 100) |
|
||||||
const saferGasLimitBN = this.bnMultiplyByFraction(gasLimit, 98, 100) |
|
||||||
const safeGasLimit = safeGasLimitBN.toString(10) |
|
||||||
|
|
||||||
// Gas Price
|
|
||||||
const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_BN.toString(16) |
|
||||||
const gasPriceBn = hexToBn(gasPrice) |
|
||||||
|
|
||||||
const txFeeBn = gasBn.mul(gasPriceBn) |
|
||||||
const valueBn = hexToBn(txParams.value) |
|
||||||
const maxCost = txFeeBn.add(valueBn) |
|
||||||
|
|
||||||
const dataLength = txParams.data ? (txParams.data.length - 2) / 2 : 0 |
|
||||||
|
|
||||||
const balanceBn = hexToBn(balance) |
|
||||||
const insufficientBalance = balanceBn.lt(maxCost) |
|
||||||
const dangerousGasLimit = gasBn.gte(saferGasLimitBN) |
|
||||||
const gasLimitSpecified = txMeta.gasLimitSpecified |
|
||||||
const buyDisabled = insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting |
|
||||||
const showRejectAll = props.unconfTxListLength > 1 |
|
||||||
|
|
||||||
this.inputs = [] |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('div', { |
|
||||||
key: txMeta.id, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('form#pending-tx-form', { |
|
||||||
onSubmit: this.onSubmit.bind(this), |
|
||||||
|
|
||||||
}, [ |
|
||||||
|
|
||||||
// tx info
|
|
||||||
h('div', [ |
|
||||||
|
|
||||||
h('.flex-row.flex-center', { |
|
||||||
style: { |
|
||||||
maxWidth: '100%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h(MiniAccountPanel, { |
|
||||||
imageSeed: address, |
|
||||||
picOrder: 'right', |
|
||||||
}, [ |
|
||||||
h('span.font-small', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Bold, Montserrat, sans-serif', |
|
||||||
}, |
|
||||||
}, identity.name), |
|
||||||
|
|
||||||
h(Copyable, { |
|
||||||
value: ethUtil.toChecksumAddress(address), |
|
||||||
}, [ |
|
||||||
h('span.font-small', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Light, Montserrat, sans-serif', |
|
||||||
}, |
|
||||||
}, addressSummary(address, 6, 4, false)), |
|
||||||
]), |
|
||||||
|
|
||||||
h('span.font-small', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Light, Montserrat, sans-serif', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(EthBalance, { |
|
||||||
value: balance, |
|
||||||
conversionRate, |
|
||||||
currentCurrency, |
|
||||||
inline: true, |
|
||||||
labelColor: '#F7861C', |
|
||||||
}), |
|
||||||
]), |
|
||||||
]), |
|
||||||
|
|
||||||
forwardCarrat(), |
|
||||||
|
|
||||||
this.miniAccountPanelForRecipient(), |
|
||||||
]), |
|
||||||
|
|
||||||
h('style', ` |
|
||||||
.table-box { |
|
||||||
margin: 7px 0px 0px 0px; |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
.table-box .row { |
|
||||||
margin: 0px; |
|
||||||
background: rgb(236,236,236); |
|
||||||
display: flex; |
|
||||||
justify-content: space-between; |
|
||||||
font-family: Montserrat Light, sans-serif; |
|
||||||
font-size: 13px; |
|
||||||
padding: 5px 25px; |
|
||||||
} |
|
||||||
.table-box .row .value { |
|
||||||
font-family: Montserrat Regular; |
|
||||||
} |
|
||||||
`),
|
|
||||||
|
|
||||||
h('.table-box', [ |
|
||||||
|
|
||||||
// Ether Value
|
|
||||||
// Currently not customizable, but easily modified
|
|
||||||
// in the way that gas and gasLimit currently are.
|
|
||||||
h('.row', [ |
|
||||||
h('.cell.label', 'Amount'), |
|
||||||
h(EthBalance, { value: txParams.value, currentCurrency, conversionRate }), |
|
||||||
]), |
|
||||||
|
|
||||||
// Gas Limit (customizable)
|
|
||||||
h('.cell.row', [ |
|
||||||
h('.cell.label', 'Gas Limit'), |
|
||||||
h('.cell.value', { |
|
||||||
}, [ |
|
||||||
h(BNInput, { |
|
||||||
name: 'Gas Limit', |
|
||||||
value: gasBn, |
|
||||||
precision: 0, |
|
||||||
scale: 0, |
|
||||||
// The hard lower limit for gas.
|
|
||||||
min: MIN_GAS_LIMIT_BN, |
|
||||||
max: safeGasLimit, |
|
||||||
suffix: 'UNITS', |
|
||||||
style: { |
|
||||||
position: 'relative', |
|
||||||
top: '5px', |
|
||||||
}, |
|
||||||
onChange: this.gasLimitChanged.bind(this), |
|
||||||
|
|
||||||
ref: (hexInput) => { this.inputs.push(hexInput) }, |
|
||||||
}), |
|
||||||
]), |
|
||||||
]), |
|
||||||
|
|
||||||
// Gas Price (customizable)
|
|
||||||
h('.cell.row', [ |
|
||||||
h('.cell.label', 'Gas Price'), |
|
||||||
h('.cell.value', { |
|
||||||
}, [ |
|
||||||
h(BNInput, { |
|
||||||
name: 'Gas Price', |
|
||||||
value: gasPriceBn, |
|
||||||
precision: 9, |
|
||||||
scale: 9, |
|
||||||
suffix: 'GWEI', |
|
||||||
min: forceGasMin || MIN_GAS_PRICE_BN, |
|
||||||
style: { |
|
||||||
position: 'relative', |
|
||||||
top: '5px', |
|
||||||
}, |
|
||||||
onChange: this.gasPriceChanged.bind(this), |
|
||||||
ref: (hexInput) => { this.inputs.push(hexInput) }, |
|
||||||
}), |
|
||||||
]), |
|
||||||
]), |
|
||||||
|
|
||||||
// Max Transaction Fee (calculated)
|
|
||||||
h('.cell.row', [ |
|
||||||
h('.cell.label', 'Max Transaction Fee'), |
|
||||||
h(EthBalance, { value: txFeeBn.toString(16), currentCurrency, conversionRate }), |
|
||||||
]), |
|
||||||
|
|
||||||
h('.cell.row', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Regular', |
|
||||||
background: 'white', |
|
||||||
padding: '10px 25px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.cell.label', 'Max Total'), |
|
||||||
h('.cell.value', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(EthBalance, { |
|
||||||
value: maxCost.toString(16), |
|
||||||
currentCurrency, |
|
||||||
conversionRate, |
|
||||||
inline: true, |
|
||||||
labelColor: 'black', |
|
||||||
fontSize: '16px', |
|
||||||
}), |
|
||||||
]), |
|
||||||
]), |
|
||||||
|
|
||||||
// Data size row:
|
|
||||||
h('.cell.row', { |
|
||||||
style: { |
|
||||||
background: '#f7f7f7', |
|
||||||
paddingBottom: '0px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.cell.label'), |
|
||||||
h('.cell.value', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
fontSize: '11px', |
|
||||||
}, |
|
||||||
}, `Data included: ${dataLength} bytes`), |
|
||||||
]), |
|
||||||
]), // End of Table
|
|
||||||
|
|
||||||
]), |
|
||||||
|
|
||||||
h('style', ` |
|
||||||
.conf-buttons button { |
|
||||||
margin-left: 10px; |
|
||||||
text-transform: uppercase; |
|
||||||
} |
|
||||||
`),
|
|
||||||
h('.cell.row', { |
|
||||||
style: { |
|
||||||
textAlign: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
txMeta.simulationFails ? |
|
||||||
h('.error', { |
|
||||||
style: { |
|
||||||
fontSize: '0.9em', |
|
||||||
}, |
|
||||||
}, 'Transaction Error. Exception thrown in contract code.') |
|
||||||
: null, |
|
||||||
|
|
||||||
!isValidAddress ? |
|
||||||
h('.error', { |
|
||||||
style: { |
|
||||||
fontSize: '0.9em', |
|
||||||
}, |
|
||||||
}, 'Recipient address is invalid. Sending this transaction will result in a loss of ETH.') |
|
||||||
: null, |
|
||||||
|
|
||||||
insufficientBalance ? |
|
||||||
h('span.error', { |
|
||||||
style: { |
|
||||||
fontSize: '0.9em', |
|
||||||
}, |
|
||||||
}, 'Insufficient balance for transaction') |
|
||||||
: null, |
|
||||||
|
|
||||||
(dangerousGasLimit && !gasLimitSpecified) ? |
|
||||||
h('span.error', { |
|
||||||
style: { |
|
||||||
fontSize: '0.9em', |
|
||||||
}, |
|
||||||
}, 'Gas limit set dangerously high. Approving this transaction is liable to fail.') |
|
||||||
: null, |
|
||||||
]), |
|
||||||
|
|
||||||
|
|
||||||
// send + cancel
|
|
||||||
h('.flex-row.flex-space-around.conf-buttons', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
justifyContent: 'flex-end', |
|
||||||
margin: '14px 25px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('button', { |
|
||||||
onClick: (event) => { |
|
||||||
this.resetGasFields() |
|
||||||
event.preventDefault() |
|
||||||
}, |
|
||||||
}, 'Reset'), |
|
||||||
|
|
||||||
// Accept Button or Buy Button
|
|
||||||
insufficientBalance ? h('button.btn-green', { onClick: props.buyEth }, 'Buy Ether') : |
|
||||||
h('input.confirm.btn-green', { |
|
||||||
type: 'submit', |
|
||||||
value: 'SUBMIT', |
|
||||||
style: { marginLeft: '10px' }, |
|
||||||
disabled: buyDisabled, |
|
||||||
}), |
|
||||||
|
|
||||||
h('button.cancel.btn-red', { |
|
||||||
onClick: props.cancelTransaction, |
|
||||||
}, 'Reject'), |
|
||||||
]), |
|
||||||
showRejectAll ? h('.flex-row.flex-space-around.conf-buttons', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
justifyContent: 'flex-end', |
|
||||||
margin: '14px 25px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('button.cancel.btn-red', { |
|
||||||
onClick: props.cancelAllTransactions, |
|
||||||
}, 'Reject All'), |
|
||||||
]) : null, |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype.miniAccountPanelForRecipient = function () { |
|
||||||
const props = this.props |
|
||||||
const txData = props.txData |
|
||||||
const txParams = txData.txParams || {} |
|
||||||
const isContractDeploy = !('to' in txParams) |
|
||||||
|
|
||||||
// If it's not a contract deploy, send to the account
|
|
||||||
if (!isContractDeploy) { |
|
||||||
return h(MiniAccountPanel, { |
|
||||||
imageSeed: txParams.to, |
|
||||||
picOrder: 'left', |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('span.font-small', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Bold, Montserrat, sans-serif', |
|
||||||
}, |
|
||||||
}, nameForAddress(txParams.to, props.identities)), |
|
||||||
|
|
||||||
h(Copyable, { |
|
||||||
value: ethUtil.toChecksumAddress(txParams.to), |
|
||||||
}, [ |
|
||||||
h('span.font-small', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Light, Montserrat, sans-serif', |
|
||||||
}, |
|
||||||
}, addressSummary(txParams.to, 6, 4, false)), |
|
||||||
]), |
|
||||||
|
|
||||||
]) |
|
||||||
} else { |
|
||||||
return h(MiniAccountPanel, { |
|
||||||
picOrder: 'left', |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('span.font-small', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Bold, Montserrat, sans-serif', |
|
||||||
}, |
|
||||||
}, 'New Contract'), |
|
||||||
|
|
||||||
]) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype.gasPriceChanged = function (newBN, valid) { |
|
||||||
log.info(`Gas price changed to: ${newBN.toString(10)}`) |
|
||||||
const txMeta = this.gatherTxMeta() |
|
||||||
txMeta.txParams.gasPrice = '0x' + newBN.toString('hex') |
|
||||||
this.setState({ |
|
||||||
txData: clone(txMeta), |
|
||||||
valid, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype.gasLimitChanged = function (newBN, valid) { |
|
||||||
log.info(`Gas limit changed to ${newBN.toString(10)}`) |
|
||||||
const txMeta = this.gatherTxMeta() |
|
||||||
txMeta.txParams.gas = '0x' + newBN.toString('hex') |
|
||||||
this.setState({ |
|
||||||
txData: clone(txMeta), |
|
||||||
valid, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype.resetGasFields = function () { |
|
||||||
log.debug(`pending-tx resetGasFields`) |
|
||||||
|
|
||||||
this.inputs.forEach((hexInput) => { |
|
||||||
if (hexInput) { |
|
||||||
hexInput.setValid() |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
this.setState({ |
|
||||||
txData: null, |
|
||||||
valid: true, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype.onSubmit = function (event) { |
|
||||||
event.preventDefault() |
|
||||||
const txMeta = this.gatherTxMeta() |
|
||||||
const valid = this.checkValidity() |
|
||||||
this.setState({ valid, submitting: true }) |
|
||||||
const validGasParams = this.verifyGasParams() |
|
||||||
if (valid && validGasParams) { |
|
||||||
this.props.sendTransaction(txMeta, event) |
|
||||||
} else { |
|
||||||
this.props.dispatch(actions.displayWarning('Invalid Gas Parameters')) |
|
||||||
this.setState({ submitting: false }) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype.checkValidity = function () { |
|
||||||
const form = this.getFormEl() |
|
||||||
const valid = form.checkValidity() |
|
||||||
return valid |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype.getFormEl = function () { |
|
||||||
const form = document.querySelector('form#pending-tx-form') |
|
||||||
// Stub out form for unit tests:
|
|
||||||
if (!form) { |
|
||||||
return { checkValidity () { return true } } |
|
||||||
} |
|
||||||
return form |
|
||||||
} |
|
||||||
|
|
||||||
// After a customizable state value has been updated,
|
|
||||||
PendingTx.prototype.gatherTxMeta = function () { |
|
||||||
log.debug(`pending-tx gatherTxMeta`) |
|
||||||
const props = this.props |
|
||||||
const state = this.state |
|
||||||
const txData = clone(state.txData) || clone(props.txData) |
|
||||||
|
|
||||||
log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`) |
|
||||||
return txData |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype.verifyGasParams = function () { |
|
||||||
// We call this in case the gas has not been modified at all
|
|
||||||
if (!this.state) { return true } |
|
||||||
return ( |
|
||||||
this._notZeroOrEmptyString(this.state.gas) && |
|
||||||
this._notZeroOrEmptyString(this.state.gasPrice) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype._notZeroOrEmptyString = function (value) { |
|
||||||
// allow undefined values
|
|
||||||
if (value === undefined) return true |
|
||||||
// Geth will return '0x', and ganache-core v2.2.1 will return '0x0'
|
|
||||||
const valueIsEmpty = !value || value === '0x' || value === '0x0' |
|
||||||
return !valueIsEmpty |
|
||||||
} |
|
||||||
|
|
||||||
PendingTx.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) { |
|
||||||
const numBN = new BN(numerator) |
|
||||||
const denomBN = new BN(denominator) |
|
||||||
return targetBN.mul(numBN).div(denomBN) |
|
||||||
} |
|
||||||
|
|
||||||
function forwardCarrat () { |
|
||||||
return ( |
|
||||||
h('img', { |
|
||||||
src: 'images/forward-carrat.svg', |
|
||||||
style: { |
|
||||||
padding: '5px 6px 0px 10px', |
|
||||||
height: '37px', |
|
||||||
}, |
|
||||||
}) |
|
||||||
) |
|
||||||
} |
|
@ -1,60 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
const AccountPanel = require('./account-panel') |
|
||||||
const TypedMessageRenderer = require('./typed-message-renderer') |
|
||||||
|
|
||||||
module.exports = PendingMsgDetails |
|
||||||
|
|
||||||
inherits(PendingMsgDetails, Component) |
|
||||||
function PendingMsgDetails () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
PendingMsgDetails.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
var msgData = state.txData |
|
||||||
|
|
||||||
var msgParams = msgData.msgParams || {} |
|
||||||
var address = msgParams.from || state.selectedAddress |
|
||||||
var identity = state.identities[address] || { address: address } |
|
||||||
var account = state.accounts[address] || { address: address } |
|
||||||
|
|
||||||
var { data, version } = msgParams |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
key: msgData.id, |
|
||||||
style: { |
|
||||||
margin: '10px 20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// account that will sign
|
|
||||||
h(AccountPanel, { |
|
||||||
showFullAddress: true, |
|
||||||
identity: identity, |
|
||||||
account: account, |
|
||||||
imageifyIdenticons: state.imageifyIdenticons, |
|
||||||
}), |
|
||||||
|
|
||||||
// message data
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
height: '260px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('label.font-small', { style: { display: 'block' } }, 'YOU ARE SIGNING'), |
|
||||||
h(TypedMessageRenderer, { |
|
||||||
value: data, |
|
||||||
version, |
|
||||||
style: { |
|
||||||
height: '215px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
@ -1,46 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const PendingTxDetails = require('./pending-typed-msg-details') |
|
||||||
|
|
||||||
module.exports = PendingMsg |
|
||||||
|
|
||||||
inherits(PendingMsg, Component) |
|
||||||
function PendingMsg () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
PendingMsg.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
var msgData = state.txData |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('div', { |
|
||||||
key: msgData.id, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// header
|
|
||||||
h('h3', { |
|
||||||
style: { |
|
||||||
fontWeight: 'bold', |
|
||||||
textAlign: 'center', |
|
||||||
}, |
|
||||||
}, 'Sign Message'), |
|
||||||
|
|
||||||
// message details
|
|
||||||
h(PendingTxDetails, state), |
|
||||||
|
|
||||||
// sign + cancel
|
|
||||||
h('.flex-row.flex-space-around', [ |
|
||||||
h('button', { |
|
||||||
onClick: state.cancelTypedMessage, |
|
||||||
}, 'Cancel'), |
|
||||||
h('button', { |
|
||||||
onClick: state.signTypedMessage, |
|
||||||
}, 'Sign'), |
|
||||||
]), |
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
@ -1,58 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
module.exports = RangeSlider |
|
||||||
|
|
||||||
inherits(RangeSlider, Component) |
|
||||||
function RangeSlider () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
RangeSlider.prototype.render = function () { |
|
||||||
const state = this.state || {} |
|
||||||
const props = this.props |
|
||||||
const onInput = props.onInput || function () {} |
|
||||||
const name = props.name |
|
||||||
const { |
|
||||||
min = 0, |
|
||||||
max = 100, |
|
||||||
increment = 1, |
|
||||||
defaultValue = 50, |
|
||||||
mirrorInput = false, |
|
||||||
} = this.props.options |
|
||||||
const {container, input, range} = props.style |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.flex-row', { |
|
||||||
style: container, |
|
||||||
}, [ |
|
||||||
h('input', { |
|
||||||
type: 'range', |
|
||||||
name: name, |
|
||||||
min: min, |
|
||||||
max: max, |
|
||||||
step: increment, |
|
||||||
style: range, |
|
||||||
value: state.value || defaultValue, |
|
||||||
onChange: mirrorInput ? this.mirrorInputs.bind(this) : onInput, |
|
||||||
}), |
|
||||||
|
|
||||||
// Mirrored input for range
|
|
||||||
mirrorInput ? h('input.large-input', { |
|
||||||
type: 'number', |
|
||||||
name: `${name}Mirror`, |
|
||||||
min: min, |
|
||||||
max: max, |
|
||||||
value: state.value || defaultValue, |
|
||||||
step: increment, |
|
||||||
style: input, |
|
||||||
onChange: this.mirrorInputs.bind(this), |
|
||||||
}) : null, |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
RangeSlider.prototype.mirrorInputs = function (event) { |
|
||||||
this.setState({value: event.target.value}) |
|
||||||
} |
|
@ -1,306 +0,0 @@ |
|||||||
const PersistentForm = require('../../lib/persistent-form') |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const actions = require('../../../ui/app/actions') |
|
||||||
const isValidAddress = require('../util').isValidAddress |
|
||||||
module.exports = connect(mapStateToProps)(ShapeshiftForm) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
warning: state.appState.warning, |
|
||||||
isSubLoading: state.appState.isSubLoading, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(ShapeshiftForm, PersistentForm) |
|
||||||
|
|
||||||
function ShapeshiftForm () { |
|
||||||
PersistentForm.call(this) |
|
||||||
this.persistentFormParentId = 'shapeshift-buy-form' |
|
||||||
} |
|
||||||
|
|
||||||
ShapeshiftForm.prototype.render = function () { |
|
||||||
return this.renderMain() |
|
||||||
} |
|
||||||
|
|
||||||
ShapeshiftForm.prototype.renderMain = function () { |
|
||||||
const marketinfo = this.props.buyView.formView.marketinfo |
|
||||||
const coinOptions = this.props.buyView.formView.coinOptions |
|
||||||
var coin = marketinfo.pair.split('_')[0].toUpperCase() |
|
||||||
|
|
||||||
return h('.flex-column', { |
|
||||||
style: { |
|
||||||
position: 'relative', |
|
||||||
padding: '25px', |
|
||||||
paddingTop: '5px', |
|
||||||
width: '90%', |
|
||||||
minHeight: '215px', |
|
||||||
alignItems: 'center', |
|
||||||
overflowY: 'auto', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.flex-row', { |
|
||||||
style: { |
|
||||||
justifyContent: 'center', |
|
||||||
alignItems: 'baseline', |
|
||||||
height: '42px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('img', { |
|
||||||
src: coinOptions[coin].image, |
|
||||||
width: '25px', |
|
||||||
height: '25px', |
|
||||||
style: { |
|
||||||
marginRight: '5px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
h('.input-container', { |
|
||||||
position: 'relative', |
|
||||||
}, [ |
|
||||||
h('input#fromCoin.buy-inputs.ex-coins', { |
|
||||||
type: 'text', |
|
||||||
list: 'coinList', |
|
||||||
autoFocus: true, |
|
||||||
dataset: { |
|
||||||
persistentFormId: 'input-coin', |
|
||||||
}, |
|
||||||
style: { |
|
||||||
boxSizing: 'border-box', |
|
||||||
}, |
|
||||||
onChange: this.handleLiveInput.bind(this), |
|
||||||
defaultValue: 'BTC', |
|
||||||
}), |
|
||||||
|
|
||||||
this.renderCoinList(), |
|
||||||
|
|
||||||
h('i.fa.fa-pencil-square-o.edit-text', { |
|
||||||
style: { |
|
||||||
fontSize: '12px', |
|
||||||
color: '#F7861C', |
|
||||||
position: 'absolute', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
h('.icon-control', { |
|
||||||
style: { |
|
||||||
position: 'relative', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
// Not visible on the screen, can't see it on master.
|
|
||||||
|
|
||||||
// h('i.fa.fa-refresh.fa-4.orange', {
|
|
||||||
// style: {
|
|
||||||
// bottom: '5px',
|
|
||||||
// left: '5px',
|
|
||||||
// color: '#F7861C',
|
|
||||||
// },
|
|
||||||
// onClick: this.updateCoin.bind(this),
|
|
||||||
// }),
|
|
||||||
h('i.fa.fa-chevron-right.fa-4.orange', { |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
bottom: '35%', |
|
||||||
left: '0%', |
|
||||||
color: '#F7861C', |
|
||||||
}, |
|
||||||
onClick: this.updateCoin.bind(this), |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
h('#toCoin.ex-coins', marketinfo.pair.split('_')[1].toUpperCase()), |
|
||||||
|
|
||||||
h('img', { |
|
||||||
src: coinOptions[marketinfo.pair.split('_')[1].toUpperCase()].image, |
|
||||||
width: '25px', |
|
||||||
height: '25px', |
|
||||||
style: { |
|
||||||
marginLeft: '5px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
h('.flex-column', { |
|
||||||
style: { |
|
||||||
marginTop: '1%', |
|
||||||
alignItems: 'flex-start', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
this.props.warning ? |
|
||||||
this.props.warning && |
|
||||||
h('span.error.flex-center', { |
|
||||||
style: { |
|
||||||
textAlign: 'center', |
|
||||||
width: '229px', |
|
||||||
height: '82px', |
|
||||||
}, |
|
||||||
}, this.props.warning + '') |
|
||||||
: this.renderInfo(), |
|
||||||
|
|
||||||
this.renderRefundAddressForCoin(coin), |
|
||||||
]), |
|
||||||
|
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
ShapeshiftForm.prototype.renderRefundAddressForCoin = function (coin) { |
|
||||||
return h(this.activeToggle('.input-container'), { |
|
||||||
style: { |
|
||||||
marginTop: '1%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('div', `${coin} Address:`), |
|
||||||
|
|
||||||
h('input#fromCoinAddress.buy-inputs', { |
|
||||||
type: 'text', |
|
||||||
placeholder: `Your ${coin} Refund Address`, |
|
||||||
dataset: { |
|
||||||
persistentFormId: 'refund-address', |
|
||||||
|
|
||||||
}, |
|
||||||
style: { |
|
||||||
boxSizing: 'border-box', |
|
||||||
width: '227px', |
|
||||||
height: '30px', |
|
||||||
padding: ' 5px ', |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
h('i.fa.fa-pencil-square-o.edit-text', { |
|
||||||
style: { |
|
||||||
fontSize: '12px', |
|
||||||
color: '#F7861C', |
|
||||||
position: 'absolute', |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('div.flex-row', { |
|
||||||
style: { |
|
||||||
justifyContent: 'flex-start', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('button', { |
|
||||||
onClick: this.shift.bind(this), |
|
||||||
style: { |
|
||||||
marginTop: '1%', |
|
||||||
}, |
|
||||||
}, |
|
||||||
'Submit'), |
|
||||||
]), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
ShapeshiftForm.prototype.shift = function () { |
|
||||||
var props = this.props |
|
||||||
var withdrawal = this.props.buyView.buyAddress |
|
||||||
var returnAddress = document.getElementById('fromCoinAddress').value |
|
||||||
var pair = this.props.buyView.formView.marketinfo.pair |
|
||||||
var data = { |
|
||||||
'withdrawal': withdrawal, |
|
||||||
'pair': pair, |
|
||||||
'returnAddress': returnAddress, |
|
||||||
// Public api key
|
|
||||||
'apiKey': '803d1f5df2ed1b1476e4b9e6bcd089e34d8874595dda6a23b67d93c56ea9cc2445e98a6748b219b2b6ad654d9f075f1f1db139abfa93158c04e825db122c14b6', |
|
||||||
} |
|
||||||
var message = [ |
|
||||||
`Deposit Limit: ${props.buyView.formView.marketinfo.limit}`, |
|
||||||
`Deposit Minimum:${props.buyView.formView.marketinfo.minimum}`, |
|
||||||
] |
|
||||||
if (isValidAddress(withdrawal)) { |
|
||||||
this.props.dispatch(actions.coinShiftRquest(data, message)) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ShapeshiftForm.prototype.renderCoinList = function () { |
|
||||||
var list = Object.keys(this.props.buyView.formView.coinOptions).map((item) => { |
|
||||||
return h('option', { |
|
||||||
value: item, |
|
||||||
}, item) |
|
||||||
}) |
|
||||||
|
|
||||||
return h('datalist#coinList', { |
|
||||||
onClick: (event) => { |
|
||||||
event.preventDefault() |
|
||||||
}, |
|
||||||
}, list) |
|
||||||
} |
|
||||||
|
|
||||||
ShapeshiftForm.prototype.updateCoin = function (event) { |
|
||||||
event.preventDefault() |
|
||||||
const props = this.props |
|
||||||
var coinOptions = this.props.buyView.formView.coinOptions |
|
||||||
var coin = document.getElementById('fromCoin').value |
|
||||||
|
|
||||||
if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') { |
|
||||||
var message = 'Not a valid coin' |
|
||||||
return props.dispatch(actions.displayWarning(message)) |
|
||||||
} else { |
|
||||||
return props.dispatch(actions.pairUpdate(coin)) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ShapeshiftForm.prototype.handleLiveInput = function () { |
|
||||||
const props = this.props |
|
||||||
var coinOptions = this.props.buyView.formView.coinOptions |
|
||||||
var coin = document.getElementById('fromCoin').value |
|
||||||
|
|
||||||
if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') { |
|
||||||
return null |
|
||||||
} else { |
|
||||||
return props.dispatch(actions.pairUpdate(coin)) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ShapeshiftForm.prototype.renderInfo = function () { |
|
||||||
const marketinfo = this.props.buyView.formView.marketinfo |
|
||||||
const coinOptions = this.props.buyView.formView.coinOptions |
|
||||||
var coin = marketinfo.pair.split('_')[0].toUpperCase() |
|
||||||
|
|
||||||
return h('span', { |
|
||||||
style: { |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('h3.flex-row.text-transform-uppercase', { |
|
||||||
style: { |
|
||||||
color: '#868686', |
|
||||||
paddingTop: '4px', |
|
||||||
justifyContent: 'space-around', |
|
||||||
textAlign: 'center', |
|
||||||
fontSize: '17px', |
|
||||||
}, |
|
||||||
}, `Market Info for ${marketinfo.pair.replace('_', ' to ').toUpperCase()}:`), |
|
||||||
h('.marketinfo', ['Status : ', `${coinOptions[coin].status}`]), |
|
||||||
h('.marketinfo', ['Exchange Rate: ', `${marketinfo.rate}`]), |
|
||||||
h('.marketinfo', ['Limit: ', `${marketinfo.limit}`]), |
|
||||||
h('.marketinfo', ['Minimum : ', `${marketinfo.minimum}`]), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
ShapeshiftForm.prototype.activeToggle = function (elementType) { |
|
||||||
if (!this.props.buyView.formView.response || this.props.warning) return elementType |
|
||||||
return `${elementType}.inactive` |
|
||||||
} |
|
||||||
|
|
||||||
ShapeshiftForm.prototype.renderLoading = function () { |
|
||||||
return h('span', { |
|
||||||
style: { |
|
||||||
position: 'absolute', |
|
||||||
left: '70px', |
|
||||||
bottom: '194px', |
|
||||||
background: 'transparent', |
|
||||||
width: '229px', |
|
||||||
height: '82px', |
|
||||||
display: 'flex', |
|
||||||
justifyContent: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('img', { |
|
||||||
style: { |
|
||||||
width: '60px', |
|
||||||
}, |
|
||||||
src: 'images/loading.svg', |
|
||||||
}), |
|
||||||
]) |
|
||||||
} |
|
@ -1,204 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const { DateTime } = require('luxon') |
|
||||||
const explorerLink = require('etherscan-link').createExplorerLink |
|
||||||
const actions = require('../../../ui/app/actions') |
|
||||||
const addressSummary = require('../util').addressSummary |
|
||||||
|
|
||||||
const CopyButton = require('./copyButton') |
|
||||||
const EthBalance = require('./eth-balance') |
|
||||||
const Tooltip = require('./tooltip') |
|
||||||
|
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(ShiftListItem) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
conversionRate: state.metamask.conversionRate, |
|
||||||
currentCurrency: state.metamask.currentCurrency, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(ShiftListItem, Component) |
|
||||||
|
|
||||||
function ShiftListItem () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
ShiftListItem.prototype.render = function () { |
|
||||||
return ( |
|
||||||
h('.transaction-list-item.flex-row', { |
|
||||||
style: { |
|
||||||
paddingTop: '20px', |
|
||||||
paddingBottom: '20px', |
|
||||||
justifyContent: 'space-around', |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
width: '0px', |
|
||||||
position: 'relative', |
|
||||||
bottom: '19px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('img', { |
|
||||||
src: 'https://info.shapeshift.io/sites/default/files/logo.png', |
|
||||||
style: { |
|
||||||
height: '35px', |
|
||||||
width: '132px', |
|
||||||
position: 'absolute', |
|
||||||
clip: 'rect(0px,23px,34px,0px)', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
this.renderInfo(), |
|
||||||
this.renderUtilComponents(), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
function formatDate (date) { |
|
||||||
return DateTime.fromMillis(date).toFormat('MMMM d y T') |
|
||||||
} |
|
||||||
|
|
||||||
ShiftListItem.prototype.renderUtilComponents = function () { |
|
||||||
var props = this.props |
|
||||||
const { conversionRate, currentCurrency } = props |
|
||||||
|
|
||||||
switch (props.response.status) { |
|
||||||
case 'no_deposits': |
|
||||||
return h('.flex-row', [ |
|
||||||
h(CopyButton, { |
|
||||||
value: this.props.depositAddress, |
|
||||||
}), |
|
||||||
h(Tooltip, { |
|
||||||
title: 'QR Code', |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-qrcode.pointer.pop-hover', { |
|
||||||
onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)), |
|
||||||
style: { |
|
||||||
margin: '5px', |
|
||||||
marginLeft: '23px', |
|
||||||
marginRight: '12px', |
|
||||||
fontSize: '20px', |
|
||||||
color: '#F7861C', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
]) |
|
||||||
case 'received': |
|
||||||
return h('.flex-row') |
|
||||||
|
|
||||||
case 'complete': |
|
||||||
return h('.flex-row', [ |
|
||||||
h(CopyButton, { |
|
||||||
value: this.props.response.transaction, |
|
||||||
}), |
|
||||||
h(EthBalance, { |
|
||||||
value: `${props.response.outgoingCoin}`, |
|
||||||
conversionRate, |
|
||||||
currentCurrency, |
|
||||||
width: '55px', |
|
||||||
shorten: true, |
|
||||||
needsParse: false, |
|
||||||
incoming: true, |
|
||||||
style: { |
|
||||||
fontSize: '15px', |
|
||||||
color: '#01888C', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]) |
|
||||||
|
|
||||||
case 'failed': |
|
||||||
return '' |
|
||||||
default: |
|
||||||
return '' |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ShiftListItem.prototype.renderInfo = function () { |
|
||||||
var props = this.props |
|
||||||
switch (props.response.status) { |
|
||||||
case 'no_deposits': |
|
||||||
return h('.flex-column', { |
|
||||||
style: { |
|
||||||
width: '200px', |
|
||||||
overflow: 'hidden', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
fontSize: 'x-small', |
|
||||||
color: '#ABA9AA', |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, `${props.depositType} to ETH via ShapeShift`), |
|
||||||
h('div', 'No deposits received'), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
fontSize: 'x-small', |
|
||||||
color: '#ABA9AA', |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, formatDate(props.time)), |
|
||||||
]) |
|
||||||
case 'received': |
|
||||||
return h('.flex-column', { |
|
||||||
style: { |
|
||||||
width: '200px', |
|
||||||
overflow: 'hidden', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
fontSize: 'x-small', |
|
||||||
color: '#ABA9AA', |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, `${props.depositType} to ETH via ShapeShift`), |
|
||||||
h('div', 'Conversion in progress'), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
fontSize: 'x-small', |
|
||||||
color: '#ABA9AA', |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, formatDate(props.time)), |
|
||||||
]) |
|
||||||
case 'complete': |
|
||||||
var url = explorerLink(props.response.transaction, parseInt('1')) |
|
||||||
|
|
||||||
return h('.flex-column.pointer', { |
|
||||||
style: { |
|
||||||
width: '200px', |
|
||||||
overflow: 'hidden', |
|
||||||
}, |
|
||||||
onClick: () => global.platform.openWindow({ url }), |
|
||||||
}, [ |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
fontSize: 'x-small', |
|
||||||
color: '#ABA9AA', |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, 'From ShapeShift'), |
|
||||||
h('div', formatDate(props.time)), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
fontSize: 'x-small', |
|
||||||
color: '#ABA9AA', |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, addressSummary(props.response.transaction)), |
|
||||||
]) |
|
||||||
|
|
||||||
case 'failed': |
|
||||||
return h('span.error', '(Failed)') |
|
||||||
default: |
|
||||||
return '' |
|
||||||
} |
|
||||||
} |
|
@ -1,37 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
module.exports = TabBar |
|
||||||
|
|
||||||
inherits(TabBar, Component) |
|
||||||
function TabBar () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
TabBar.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const state = this.state || {} |
|
||||||
const { tabs = [], defaultTab, tabSelected } = props |
|
||||||
const { subview = defaultTab } = state |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.flex-row.space-around.text-transform-uppercase', { |
|
||||||
style: { |
|
||||||
background: '#EBEBEB', |
|
||||||
color: '#AEAEAE', |
|
||||||
paddingTop: '4px', |
|
||||||
minHeight: '30px', |
|
||||||
}, |
|
||||||
}, tabs.map((tab) => { |
|
||||||
const { key, content } = tab |
|
||||||
return h(subview === key ? '.activeForm' : '.inactiveForm.pointer', { |
|
||||||
onClick: () => { |
|
||||||
this.setState({ subview: key }) |
|
||||||
tabSelected(key) |
|
||||||
}, |
|
||||||
}, content) |
|
||||||
})) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
@ -1,18 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
module.exports = NewComponent |
|
||||||
|
|
||||||
inherits(NewComponent, Component) |
|
||||||
function NewComponent () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
NewComponent.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
|
|
||||||
return ( |
|
||||||
h('span', props.message) |
|
||||||
) |
|
||||||
} |
|
@ -1,72 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const Identicon = require('./identicon') |
|
||||||
const prefixForNetwork = require('../../lib/etherscan-prefix-for-network') |
|
||||||
|
|
||||||
module.exports = TokenCell |
|
||||||
|
|
||||||
inherits(TokenCell, Component) |
|
||||||
function TokenCell () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
TokenCell.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const { address, symbol, string, network, userAddress } = props |
|
||||||
|
|
||||||
return ( |
|
||||||
h('li.token-cell', { |
|
||||||
style: { cursor: network === '1' ? 'pointer' : 'default' }, |
|
||||||
onClick: this.view.bind(this, address, userAddress, network), |
|
||||||
}, [ |
|
||||||
|
|
||||||
h(Identicon, { |
|
||||||
diameter: 50, |
|
||||||
address, |
|
||||||
network, |
|
||||||
}), |
|
||||||
|
|
||||||
h('h3', `${string || 0} ${symbol}`), |
|
||||||
|
|
||||||
h('span', { style: { flex: '1 0 auto' } }), |
|
||||||
|
|
||||||
/* |
|
||||||
h('button', { |
|
||||||
onClick: this.send.bind(this, address), |
|
||||||
}, 'SEND'), |
|
||||||
*/ |
|
||||||
|
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
TokenCell.prototype.send = function (address, event) { |
|
||||||
event.preventDefault() |
|
||||||
event.stopPropagation() |
|
||||||
const url = tokenFactoryFor(address) |
|
||||||
if (url) { |
|
||||||
navigateTo(url) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
TokenCell.prototype.view = function (address, userAddress, network, event) { |
|
||||||
const url = etherscanLinkFor(address, userAddress, network) |
|
||||||
if (url) { |
|
||||||
navigateTo(url) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
function navigateTo (url) { |
|
||||||
global.platform.openWindow({ url }) |
|
||||||
} |
|
||||||
|
|
||||||
function etherscanLinkFor (tokenAddress, address, network) { |
|
||||||
const prefix = prefixForNetwork(network) |
|
||||||
return `https://${prefix}etherscan.io/token/${tokenAddress}?a=${address}` |
|
||||||
} |
|
||||||
|
|
||||||
function tokenFactoryFor (tokenAddress) { |
|
||||||
return `https://tokenfactory.surge.sh/#/token/${tokenAddress}` |
|
||||||
} |
|
||||||
|
|
@ -1,205 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const TokenTracker = require('eth-token-tracker') |
|
||||||
const TokenCell = require('./token-cell.js') |
|
||||||
const log = require('loglevel') |
|
||||||
|
|
||||||
module.exports = TokenList |
|
||||||
|
|
||||||
inherits(TokenList, Component) |
|
||||||
function TokenList () { |
|
||||||
this.state = { |
|
||||||
tokens: [], |
|
||||||
isLoading: true, |
|
||||||
network: null, |
|
||||||
} |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
TokenList.prototype.render = function () { |
|
||||||
const state = this.state |
|
||||||
const { tokens, isLoading, error } = state |
|
||||||
const { userAddress, network } = this.props |
|
||||||
|
|
||||||
if (isLoading) { |
|
||||||
return this.message('Loading') |
|
||||||
} |
|
||||||
|
|
||||||
if (error) { |
|
||||||
log.error(error) |
|
||||||
return h('.hotFix', { |
|
||||||
style: { |
|
||||||
padding: '80px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'We had trouble loading your token balances. You can view them ', |
|
||||||
h('span.hotFix', { |
|
||||||
style: { |
|
||||||
color: 'rgba(247, 134, 28, 1)', |
|
||||||
cursor: 'pointer', |
|
||||||
}, |
|
||||||
onClick: () => { |
|
||||||
global.platform.openWindow({ |
|
||||||
url: `https://ethplorer.io/address/${userAddress}`, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}, 'here'), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
const tokenViews = tokens.map((tokenData) => { |
|
||||||
tokenData.network = network |
|
||||||
tokenData.userAddress = userAddress |
|
||||||
return h(TokenCell, tokenData) |
|
||||||
}) |
|
||||||
|
|
||||||
return h('.full-flex-height', [ |
|
||||||
this.renderTokenStatusBar(), |
|
||||||
|
|
||||||
h('ol.full-flex-height.flex-column', { |
|
||||||
style: { |
|
||||||
overflowY: 'auto', |
|
||||||
display: 'flex', |
|
||||||
flexDirection: 'column', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('style', ` |
|
||||||
|
|
||||||
li.token-cell { |
|
||||||
display: flex; |
|
||||||
flex-direction: row; |
|
||||||
align-items: center; |
|
||||||
padding: 10px; |
|
||||||
min-height: 50px; |
|
||||||
} |
|
||||||
|
|
||||||
li.token-cell > h3 { |
|
||||||
margin-left: 12px; |
|
||||||
} |
|
||||||
|
|
||||||
li.token-cell:hover { |
|
||||||
background: white; |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
|
|
||||||
`),
|
|
||||||
...tokenViews, |
|
||||||
h('.flex-grow'), |
|
||||||
]), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
TokenList.prototype.renderTokenStatusBar = function () { |
|
||||||
const { tokens } = this.state |
|
||||||
|
|
||||||
let msg |
|
||||||
if (tokens.length === 1) { |
|
||||||
msg = `You own 1 token` |
|
||||||
} else if (tokens.length > 1) { |
|
||||||
msg = `You own ${tokens.length} tokens` |
|
||||||
} else { |
|
||||||
msg = `No tokens found` |
|
||||||
} |
|
||||||
|
|
||||||
return h('div', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
justifyContent: 'space-between', |
|
||||||
alignItems: 'center', |
|
||||||
minHeight: '70px', |
|
||||||
padding: '10px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('span', msg), |
|
||||||
h('button', { |
|
||||||
key: 'reveal-account-bar', |
|
||||||
onClick: (event) => { |
|
||||||
event.preventDefault() |
|
||||||
this.props.addToken() |
|
||||||
}, |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
height: '40px', |
|
||||||
padding: '10px', |
|
||||||
justifyContent: 'center', |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'ADD TOKEN', |
|
||||||
]), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
TokenList.prototype.message = function (body) { |
|
||||||
return h('div', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
height: '250px', |
|
||||||
alignItems: 'center', |
|
||||||
justifyContent: 'center', |
|
||||||
padding: '30px', |
|
||||||
}, |
|
||||||
}, body) |
|
||||||
} |
|
||||||
|
|
||||||
TokenList.prototype.componentDidMount = function () { |
|
||||||
this.createFreshTokenTracker() |
|
||||||
} |
|
||||||
|
|
||||||
TokenList.prototype.createFreshTokenTracker = function () { |
|
||||||
if (this.tracker) { |
|
||||||
// Clean up old trackers when refreshing:
|
|
||||||
this.tracker.stop() |
|
||||||
this.tracker.removeListener('update', this.balanceUpdater) |
|
||||||
this.tracker.removeListener('error', this.showError) |
|
||||||
} |
|
||||||
|
|
||||||
if (!global.ethereumProvider) return |
|
||||||
const { userAddress } = this.props |
|
||||||
this.tracker = new TokenTracker({ |
|
||||||
userAddress, |
|
||||||
provider: global.ethereumProvider, |
|
||||||
tokens: this.props.tokens, |
|
||||||
pollingInterval: 8000, |
|
||||||
}) |
|
||||||
|
|
||||||
|
|
||||||
// Set up listener instances for cleaning up
|
|
||||||
this.balanceUpdater = this.updateBalances.bind(this) |
|
||||||
this.showError = (error) => { |
|
||||||
this.setState({ error, isLoading: false }) |
|
||||||
} |
|
||||||
this.tracker.on('update', this.balanceUpdater) |
|
||||||
this.tracker.on('error', this.showError) |
|
||||||
|
|
||||||
this.tracker.updateBalances() |
|
||||||
.then(() => { |
|
||||||
this.updateBalances(this.tracker.serialize()) |
|
||||||
}) |
|
||||||
.catch((reason) => { |
|
||||||
log.error(`Problem updating balances`, reason) |
|
||||||
this.setState({ isLoading: false }) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
TokenList.prototype.componentWillUpdate = function (nextProps) { |
|
||||||
if (nextProps.network === 'loading') return |
|
||||||
const oldNet = this.props.network |
|
||||||
const newNet = nextProps.network |
|
||||||
|
|
||||||
if (oldNet && newNet && newNet !== oldNet) { |
|
||||||
this.setState({ isLoading: true }) |
|
||||||
this.createFreshTokenTracker() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
TokenList.prototype.updateBalances = function (tokens) { |
|
||||||
this.setState({ tokens, isLoading: false }) |
|
||||||
} |
|
||||||
|
|
||||||
TokenList.prototype.componentWillUnmount = function () { |
|
||||||
if (!this.tracker) return |
|
||||||
this.tracker.stop() |
|
||||||
} |
|
||||||
|
|
@ -1,22 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const ReactTooltip = require('react-tooltip-component') |
|
||||||
|
|
||||||
module.exports = Tooltip |
|
||||||
|
|
||||||
inherits(Tooltip, Component) |
|
||||||
function Tooltip () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
Tooltip.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const { position, title, children } = props |
|
||||||
|
|
||||||
return h(ReactTooltip, { |
|
||||||
position: position || 'left', |
|
||||||
title, |
|
||||||
fixed: true, |
|
||||||
}, children) |
|
||||||
} |
|
@ -1,68 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const Tooltip = require('./tooltip') |
|
||||||
|
|
||||||
const Identicon = require('./identicon') |
|
||||||
|
|
||||||
module.exports = TransactionIcon |
|
||||||
|
|
||||||
inherits(TransactionIcon, Component) |
|
||||||
function TransactionIcon () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
TransactionIcon.prototype.render = function () { |
|
||||||
const { transaction, txParams, isMsg } = this.props |
|
||||||
switch (transaction.status) { |
|
||||||
case 'unapproved': |
|
||||||
return h(!isMsg ? '.unapproved-tx-icon' : 'i.fa.fa-certificate.fa-lg') |
|
||||||
|
|
||||||
case 'rejected': |
|
||||||
return h('i.fa.fa-exclamation-triangle.fa-lg.warning', { |
|
||||||
style: { |
|
||||||
width: '24px', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
case 'failed': |
|
||||||
return h('i.fa.fa-exclamation-triangle.fa-lg.error', { |
|
||||||
style: { |
|
||||||
width: '24px', |
|
||||||
}, |
|
||||||
}) |
|
||||||
|
|
||||||
case 'submitted': |
|
||||||
return h(Tooltip, { |
|
||||||
title: 'Pending', |
|
||||||
position: 'right', |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-ellipsis-h', { |
|
||||||
style: { |
|
||||||
fontSize: '27px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
if (isMsg) { |
|
||||||
return h('i.fa.fa-certificate.fa-lg', { |
|
||||||
style: { |
|
||||||
width: '24px', |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
if (txParams.to) { |
|
||||||
return h(Identicon, { |
|
||||||
diameter: 24, |
|
||||||
address: txParams.to || transaction.hash, |
|
||||||
}) |
|
||||||
} else { |
|
||||||
return h('i.fa.fa-file-text-o.fa-lg', { |
|
||||||
style: { |
|
||||||
width: '24px', |
|
||||||
}, |
|
||||||
}) |
|
||||||
} |
|
||||||
} |
|
@ -1,258 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const connect = require('react-redux').connect |
|
||||||
|
|
||||||
const EthBalance = require('./eth-balance') |
|
||||||
const addressSummary = require('../util').addressSummary |
|
||||||
const explorerLink = require('etherscan-link').createExplorerLink |
|
||||||
const CopyButton = require('./copyButton') |
|
||||||
const { DateTime } = require('luxon') |
|
||||||
const Tooltip = require('./tooltip') |
|
||||||
const numberToBN = require('number-to-bn') |
|
||||||
const actions = require('../../../ui/app/actions') |
|
||||||
|
|
||||||
const TransactionIcon = require('./transaction-list-item-icon') |
|
||||||
const ShiftListItem = require('./shift-list-item') |
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => { |
|
||||||
return { |
|
||||||
retryTransaction: transactionId => dispatch(actions.retryTransaction(transactionId)), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = connect(null, mapDispatchToProps)(TransactionListItem) |
|
||||||
|
|
||||||
inherits(TransactionListItem, Component) |
|
||||||
function TransactionListItem () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
TransactionListItem.prototype.showRetryButton = function () { |
|
||||||
const { transaction = {}, transactions } = this.props |
|
||||||
const { submittedTime, txParams } = transaction |
|
||||||
|
|
||||||
if (!txParams) { |
|
||||||
return false |
|
||||||
} |
|
||||||
|
|
||||||
let currentTxSharesEarliestNonce = false |
|
||||||
const currentNonce = txParams.nonce |
|
||||||
const currentNonceTxs = transactions.filter(tx => tx.txParams.nonce === currentNonce) |
|
||||||
const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted') |
|
||||||
const currentSubmittedTxs = transactions.filter(tx => tx.status === 'submitted') |
|
||||||
const lastSubmittedTxWithCurrentNonce = currentNonceSubmittedTxs[0] |
|
||||||
const currentTxIsLatestWithNonce = lastSubmittedTxWithCurrentNonce && |
|
||||||
lastSubmittedTxWithCurrentNonce.id === transaction.id |
|
||||||
if (currentSubmittedTxs.length > 0) { |
|
||||||
const earliestSubmitted = currentSubmittedTxs.reduce((tx1, tx2) => { |
|
||||||
if (tx1.submittedTime < tx2.submittedTime) return tx1 |
|
||||||
return tx2 |
|
||||||
}) |
|
||||||
currentTxSharesEarliestNonce = currentNonce === earliestSubmitted.txParams.nonce |
|
||||||
} |
|
||||||
|
|
||||||
return currentTxSharesEarliestNonce && currentTxIsLatestWithNonce && Date.now() - submittedTime > 30000 |
|
||||||
} |
|
||||||
|
|
||||||
TransactionListItem.prototype.render = function () { |
|
||||||
const { transaction, network, conversionRate, currentCurrency } = this.props |
|
||||||
const { status } = transaction |
|
||||||
if (transaction.key === 'shapeshift') { |
|
||||||
if (network === '1') return h(ShiftListItem, transaction) |
|
||||||
} |
|
||||||
var date = formatDate(transaction.time) |
|
||||||
|
|
||||||
let isLinkable = false |
|
||||||
const numericNet = parseInt(network) |
|
||||||
isLinkable = numericNet === 1 || numericNet === 3 || numericNet === 4 || numericNet === 42 |
|
||||||
|
|
||||||
var isMsg = ('msgParams' in transaction) |
|
||||||
var isTx = ('txParams' in transaction) |
|
||||||
var isPending = status === 'unapproved' |
|
||||||
let txParams |
|
||||||
if (isTx) { |
|
||||||
txParams = transaction.txParams |
|
||||||
} else if (isMsg) { |
|
||||||
txParams = transaction.msgParams |
|
||||||
} |
|
||||||
|
|
||||||
const nonce = txParams.nonce ? numberToBN(txParams.nonce).toString(10) : '' |
|
||||||
|
|
||||||
const isClickable = ('hash' in transaction && isLinkable) || isPending |
|
||||||
return ( |
|
||||||
h('.transaction-list-item.flex-column', { |
|
||||||
onClick: (event) => { |
|
||||||
if (isPending) { |
|
||||||
this.props.showTx(transaction.id) |
|
||||||
} |
|
||||||
event.stopPropagation() |
|
||||||
if (!transaction.hash || !isLinkable) return |
|
||||||
var url = explorerLink(transaction.hash, parseInt(network)) |
|
||||||
global.platform.openWindow({ url }) |
|
||||||
}, |
|
||||||
style: { |
|
||||||
padding: '20px 0', |
|
||||||
alignItems: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h(`.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, { |
|
||||||
style: { |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.identicon-wrapper.flex-column.flex-center.select-none', [ |
|
||||||
h(TransactionIcon, { txParams, transaction, isTx, isMsg }), |
|
||||||
]), |
|
||||||
|
|
||||||
h(Tooltip, { |
|
||||||
title: 'Transaction Number', |
|
||||||
position: 'right', |
|
||||||
}, [ |
|
||||||
h('span', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
cursor: 'normal', |
|
||||||
flexDirection: 'column', |
|
||||||
alignItems: 'center', |
|
||||||
justifyContent: 'center', |
|
||||||
padding: '10px', |
|
||||||
}, |
|
||||||
}, nonce), |
|
||||||
]), |
|
||||||
|
|
||||||
h('.flex-column', {style: {width: '200px', overflow: 'hidden'}}, [ |
|
||||||
domainField(txParams), |
|
||||||
h('div', date), |
|
||||||
recipientField(txParams, transaction, isTx, isMsg), |
|
||||||
]), |
|
||||||
|
|
||||||
// Places a copy button if tx is successful, else places a placeholder empty div.
|
|
||||||
transaction.hash ? h(CopyButton, { value: transaction.hash }) : h('div', {style: { display: 'flex', alignItems: 'center', width: '26px' }}), |
|
||||||
|
|
||||||
isTx ? h(EthBalance, { |
|
||||||
value: txParams.value, |
|
||||||
conversionRate, |
|
||||||
currentCurrency, |
|
||||||
width: '55px', |
|
||||||
shorten: true, |
|
||||||
showFiat: false, |
|
||||||
style: {fontSize: '15px'}, |
|
||||||
}) : h('.flex-column'), |
|
||||||
]), |
|
||||||
|
|
||||||
this.showRetryButton() && h('.transition-list-item__retry.grow-on-hover', { |
|
||||||
onClick: event => { |
|
||||||
event.stopPropagation() |
|
||||||
this.resubmit() |
|
||||||
}, |
|
||||||
style: { |
|
||||||
height: '22px', |
|
||||||
borderRadius: '22px', |
|
||||||
color: '#F9881B', |
|
||||||
padding: '0 20px', |
|
||||||
backgroundColor: '#FFE3C9', |
|
||||||
display: 'flex', |
|
||||||
justifyContent: 'center', |
|
||||||
alignItems: 'center', |
|
||||||
fontSize: '8px', |
|
||||||
cursor: 'pointer', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
paddingRight: '2px', |
|
||||||
}, |
|
||||||
}, 'Taking too long?'), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
textDecoration: 'underline', |
|
||||||
}, |
|
||||||
}, 'Retry with a higher gas price here'), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
TransactionListItem.prototype.resubmit = function () { |
|
||||||
const { transaction } = this.props |
|
||||||
this.props.retryTransaction(transaction.id) |
|
||||||
} |
|
||||||
|
|
||||||
function domainField (txParams) { |
|
||||||
return h('div', { |
|
||||||
style: { |
|
||||||
fontSize: 'x-small', |
|
||||||
color: '#ABA9AA', |
|
||||||
overflow: 'hidden', |
|
||||||
textOverflow: 'ellipsis', |
|
||||||
width: '100%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
txParams.origin, |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
function recipientField (txParams, transaction, isTx, isMsg) { |
|
||||||
let message |
|
||||||
|
|
||||||
if (isMsg) { |
|
||||||
message = 'Signature Requested' |
|
||||||
} else if (txParams.to) { |
|
||||||
message = addressSummary(txParams.to) |
|
||||||
} else { |
|
||||||
message = 'Contract Deployment' |
|
||||||
} |
|
||||||
|
|
||||||
return h('div', { |
|
||||||
style: { |
|
||||||
fontSize: 'x-small', |
|
||||||
color: '#ABA9AA', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
message, |
|
||||||
renderErrorOrWarning(transaction), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
function formatDate (date) { |
|
||||||
return DateTime.fromMillis(date).toFormat('MMMM d y T') |
|
||||||
} |
|
||||||
|
|
||||||
function renderErrorOrWarning (transaction) { |
|
||||||
const { status, err, warning } = transaction |
|
||||||
|
|
||||||
// show dropped
|
|
||||||
if (status === 'dropped') { |
|
||||||
return h('span.dropped', ' (Dropped)') |
|
||||||
} |
|
||||||
|
|
||||||
// show rejected
|
|
||||||
if (status === 'rejected') { |
|
||||||
return h('span.error', ' (Rejected)') |
|
||||||
} |
|
||||||
|
|
||||||
// show error
|
|
||||||
if (err) { |
|
||||||
const message = err.message || '' |
|
||||||
return ( |
|
||||||
h(Tooltip, { |
|
||||||
title: message, |
|
||||||
position: 'bottom', |
|
||||||
}, [ |
|
||||||
h(`span.error`, ` (Failed)`), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
// show warning
|
|
||||||
if (warning) { |
|
||||||
const message = warning.message |
|
||||||
return h(Tooltip, { |
|
||||||
title: message, |
|
||||||
position: 'bottom', |
|
||||||
}, [ |
|
||||||
h(`span.warning`, ` (Warning)`), |
|
||||||
]) |
|
||||||
} |
|
||||||
} |
|
@ -1,87 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
const TransactionListItem = require('./transaction-list-item') |
|
||||||
|
|
||||||
module.exports = TransactionList |
|
||||||
|
|
||||||
|
|
||||||
inherits(TransactionList, Component) |
|
||||||
function TransactionList () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
TransactionList.prototype.render = function () { |
|
||||||
const { transactions, network, unapprovedMsgs, conversionRate } = this.props |
|
||||||
|
|
||||||
var shapeShiftTxList |
|
||||||
if (network === '1') { |
|
||||||
shapeShiftTxList = this.props.shapeShiftTxList |
|
||||||
} |
|
||||||
const txsToRender = !shapeShiftTxList ? transactions.concat(unapprovedMsgs) : transactions.concat(unapprovedMsgs, shapeShiftTxList) |
|
||||||
.sort((a, b) => b.time - a.time) |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('section.transaction-list.full-flex-height', { |
|
||||||
style: { |
|
||||||
justifyContent: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('style', ` |
|
||||||
.transaction-list .transaction-list-item:not(:last-of-type) { |
|
||||||
border-bottom: 1px solid #D4D4D4; |
|
||||||
} |
|
||||||
.transaction-list .transaction-list-item .ether-balance-label { |
|
||||||
display: block !important; |
|
||||||
font-size: small; |
|
||||||
} |
|
||||||
`),
|
|
||||||
|
|
||||||
h('.tx-list', { |
|
||||||
style: { |
|
||||||
overflowY: 'auto', |
|
||||||
height: '100%', |
|
||||||
padding: '0 25px 0 15px', |
|
||||||
textAlign: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
txsToRender.length |
|
||||||
? txsToRender.map((transaction, i) => { |
|
||||||
let key |
|
||||||
switch (transaction.key) { |
|
||||||
case 'shapeshift': |
|
||||||
const { depositAddress, time } = transaction |
|
||||||
key = `shift-tx-${depositAddress}-${time}-${i}` |
|
||||||
break |
|
||||||
default: |
|
||||||
key = `tx-${transaction.id}-${i}` |
|
||||||
} |
|
||||||
return h(TransactionListItem, { |
|
||||||
transaction, i, network, key, |
|
||||||
conversionRate, transactions, |
|
||||||
showTx: (txId) => { |
|
||||||
this.props.viewPendingTx(txId) |
|
||||||
}, |
|
||||||
}) |
|
||||||
}) |
|
||||||
: h('.flex-center.full-flex-height', { |
|
||||||
style: { |
|
||||||
flexDirection: 'column', |
|
||||||
justifyContent: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('p', { |
|
||||||
style: { |
|
||||||
marginTop: '50px', |
|
||||||
}, |
|
||||||
}, 'No transaction history.'), |
|
||||||
]), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
@ -1,69 +0,0 @@ |
|||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const inherits = require('util').inherits |
|
||||||
const extend = require('xtend') |
|
||||||
const { ObjectInspector } = require('react-inspector') |
|
||||||
|
|
||||||
module.exports = TypedMessageRenderer |
|
||||||
|
|
||||||
inherits(TypedMessageRenderer, Component) |
|
||||||
function TypedMessageRenderer () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
TypedMessageRenderer.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const { value, version, style } = props |
|
||||||
let text |
|
||||||
switch (version) { |
|
||||||
case 'V1': |
|
||||||
text = renderTypedData(value) |
|
||||||
break |
|
||||||
case 'V3': |
|
||||||
text = renderTypedDataV3(value) |
|
||||||
break |
|
||||||
} |
|
||||||
|
|
||||||
const defaultStyle = extend({ |
|
||||||
width: '315px', |
|
||||||
maxHeight: '210px', |
|
||||||
resize: 'none', |
|
||||||
border: 'none', |
|
||||||
background: 'white', |
|
||||||
padding: '3px', |
|
||||||
overflow: 'scroll', |
|
||||||
}, style) |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div.font-small', { |
|
||||||
style: defaultStyle, |
|
||||||
}, text) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
function renderTypedData (values) { |
|
||||||
return values.map(function (value) { |
|
||||||
let v = value.value |
|
||||||
if (typeof v === 'boolean') { |
|
||||||
v = v.toString() |
|
||||||
} |
|
||||||
return h('div', {}, [ |
|
||||||
h('strong', {style: {display: 'block', fontWeight: 'bold'}}, String(value.name) + ':'), |
|
||||||
h('div', {}, v), |
|
||||||
]) |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
function renderTypedDataV3 (values) { |
|
||||||
const { domain, message } = JSON.parse(values) |
|
||||||
return [ |
|
||||||
domain ? h('div', [ |
|
||||||
h('h1', 'Domain'), |
|
||||||
h(ObjectInspector, { data: domain, expandLevel: 1, name: 'domain' }), |
|
||||||
]) : '', |
|
||||||
message ? h('div', [ |
|
||||||
h('h1', 'Message'), |
|
||||||
h(ObjectInspector, { data: message, expandLevel: 1, name: 'message' }), |
|
||||||
]) : '', |
|
||||||
] |
|
||||||
} |
|
@ -1,247 +0,0 @@ |
|||||||
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 NetworkIndicator = require('./components/network') |
|
||||||
const LoadingIndicator = require('./components/loading') |
|
||||||
const txHelper = require('../lib/tx-helper') |
|
||||||
const log = require('loglevel') |
|
||||||
const { ENVIRONMENT_TYPE_NOTIFICATION } = require('../../app/scripts/lib/enums') |
|
||||||
const { getEnvironmentType } = require('../../app/scripts/lib/util') |
|
||||||
|
|
||||||
const PendingTx = require('./components/pending-tx') |
|
||||||
const PendingMsg = require('./components/pending-msg') |
|
||||||
const PendingPersonalMsg = require('./components/pending-personal-msg') |
|
||||||
const PendingTypedMsg = require('./components/pending-typed-msg') |
|
||||||
const Loading = require('./components/loading') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(ConfirmTxScreen) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
identities: state.metamask.identities, |
|
||||||
accounts: state.metamask.accounts, |
|
||||||
selectedAddress: state.metamask.selectedAddress, |
|
||||||
unapprovedTxs: state.metamask.unapprovedTxs, |
|
||||||
unapprovedMsgs: state.metamask.unapprovedMsgs, |
|
||||||
unapprovedPersonalMsgs: state.metamask.unapprovedPersonalMsgs, |
|
||||||
unapprovedTypedMessages: state.metamask.unapprovedTypedMessages, |
|
||||||
index: state.appState.currentView.context, |
|
||||||
warning: state.appState.warning, |
|
||||||
network: state.metamask.network, |
|
||||||
provider: state.metamask.provider, |
|
||||||
conversionRate: state.metamask.conversionRate, |
|
||||||
currentCurrency: state.metamask.currentCurrency, |
|
||||||
blockGasLimit: state.metamask.currentBlockGasLimit, |
|
||||||
computedBalances: state.metamask.computedBalances, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(ConfirmTxScreen, Component) |
|
||||||
function ConfirmTxScreen () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
const { network, provider, unapprovedTxs, currentCurrency, computedBalances, |
|
||||||
unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, conversionRate, blockGasLimit } = props |
|
||||||
|
|
||||||
var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network) |
|
||||||
|
|
||||||
var txData = unconfTxList[props.index] || {} |
|
||||||
var txParams = txData.params || {} |
|
||||||
var isNotification = getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_NOTIFICATION |
|
||||||
|
|
||||||
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`) |
|
||||||
if (unconfTxList.length === 0) return h(Loading, { isLoading: true }) |
|
||||||
|
|
||||||
const unconfTxListLength = unconfTxList.length |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.flex-column.flex-grow', [ |
|
||||||
|
|
||||||
h(LoadingIndicator, { |
|
||||||
isLoading: this.state ? !this.state.bypassLoadingScreen : txData.loadingDefaults, |
|
||||||
loadingMessage: 'Estimating transaction cost…', |
|
||||||
canBypass: true, |
|
||||||
bypass: () => { |
|
||||||
this.setState({bypassLoadingScreen: true}) |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
// subtitle and nav
|
|
||||||
h('.section-title.flex-row.flex-center', [ |
|
||||||
!isNotification ? h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { |
|
||||||
onClick: this.goHome.bind(this), |
|
||||||
}) : null, |
|
||||||
h('h2.page-subtitle', 'Confirm Transaction'), |
|
||||||
isNotification ? h(NetworkIndicator, { |
|
||||||
network: network, |
|
||||||
provider: provider, |
|
||||||
}) : null, |
|
||||||
]), |
|
||||||
|
|
||||||
h('h3', { |
|
||||||
style: { |
|
||||||
alignSelf: 'center', |
|
||||||
display: unconfTxList.length > 1 ? 'block' : 'none', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { |
|
||||||
style: { |
|
||||||
display: props.index === 0 ? 'none' : 'inline-block', |
|
||||||
}, |
|
||||||
onClick: () => props.dispatch(actions.previousTx()), |
|
||||||
}), |
|
||||||
` ${props.index + 1} of ${unconfTxList.length} `, |
|
||||||
h('i.fa.fa-arrow-right.fa-lg.cursor-pointer', { |
|
||||||
style: { |
|
||||||
display: props.index + 1 === unconfTxList.length ? 'none' : 'inline-block', |
|
||||||
}, |
|
||||||
onClick: () => props.dispatch(actions.nextTx()), |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
warningIfExists(props.warning), |
|
||||||
|
|
||||||
currentTxView({ |
|
||||||
// Properties
|
|
||||||
txData: txData, |
|
||||||
key: txData.id, |
|
||||||
selectedAddress: props.selectedAddress, |
|
||||||
accounts: props.accounts, |
|
||||||
identities: props.identities, |
|
||||||
conversionRate, |
|
||||||
currentCurrency, |
|
||||||
blockGasLimit, |
|
||||||
unconfTxListLength, |
|
||||||
computedBalances, |
|
||||||
// Actions
|
|
||||||
buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress), |
|
||||||
sendTransaction: this.sendTransaction.bind(this), |
|
||||||
cancelTransaction: this.cancelTransaction.bind(this, txData), |
|
||||||
cancelAllTransactions: this.cancelAllTransactions.bind(this, unconfTxList), |
|
||||||
signMessage: this.signMessage.bind(this, txData), |
|
||||||
signPersonalMessage: this.signPersonalMessage.bind(this, txData), |
|
||||||
signTypedMessage: this.signTypedMessage.bind(this, txData), |
|
||||||
cancelMessage: this.cancelMessage.bind(this, txData), |
|
||||||
cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData), |
|
||||||
cancelTypedMessage: this.cancelTypedMessage.bind(this, txData), |
|
||||||
}), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
function currentTxView (opts) { |
|
||||||
log.info('rendering current tx view') |
|
||||||
const { txData } = opts |
|
||||||
const { txParams, msgParams, type } = txData |
|
||||||
|
|
||||||
if (txParams) { |
|
||||||
log.debug('txParams detected, rendering pending tx') |
|
||||||
return h(PendingTx, opts) |
|
||||||
} else if (msgParams) { |
|
||||||
log.debug('msgParams detected, rendering pending msg') |
|
||||||
|
|
||||||
if (type === 'eth_sign') { |
|
||||||
log.debug('rendering eth_sign message') |
|
||||||
return h(PendingMsg, opts) |
|
||||||
} else if (type === 'personal_sign') { |
|
||||||
log.debug('rendering personal_sign message') |
|
||||||
return h(PendingPersonalMsg, opts) |
|
||||||
} else if (type === 'eth_signTypedData') { |
|
||||||
log.debug('rendering eth_signTypedData message') |
|
||||||
return h(PendingTypedMsg, opts) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.buyEth = function (address, event) { |
|
||||||
event.preventDefault() |
|
||||||
this.props.dispatch(actions.buyEthView(address)) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.sendTransaction = function (txData, event) { |
|
||||||
this.stopPropagation(event) |
|
||||||
this.props.dispatch(actions.updateAndApproveTx(txData)) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.cancelTransaction = function (txData, event) { |
|
||||||
this.stopPropagation(event) |
|
||||||
event.preventDefault() |
|
||||||
this.props.dispatch(actions.cancelTx(txData)) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.cancelAllTransactions = function (unconfTxList, event) { |
|
||||||
this.stopPropagation(event) |
|
||||||
event.preventDefault() |
|
||||||
this.props.dispatch(actions.cancelAllTx(unconfTxList)) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.signMessage = function (msgData, event) { |
|
||||||
log.info('conf-tx.js: signing message') |
|
||||||
var params = msgData.msgParams |
|
||||||
params.metamaskId = msgData.id |
|
||||||
this.stopPropagation(event) |
|
||||||
this.props.dispatch(actions.signMsg(params)) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.stopPropagation = function (event) { |
|
||||||
if (event.stopPropagation) { |
|
||||||
event.stopPropagation() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.signPersonalMessage = function (msgData, event) { |
|
||||||
log.info('conf-tx.js: signing personal message') |
|
||||||
var params = msgData.msgParams |
|
||||||
params.metamaskId = msgData.id |
|
||||||
this.stopPropagation(event) |
|
||||||
this.props.dispatch(actions.signPersonalMsg(params)) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.signTypedMessage = function (msgData, event) { |
|
||||||
log.info('conf-tx.js: signing typed message') |
|
||||||
var params = msgData.msgParams |
|
||||||
params.metamaskId = msgData.id |
|
||||||
this.stopPropagation(event) |
|
||||||
this.props.dispatch(actions.signTypedMsg(params)) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.cancelMessage = function (msgData, event) { |
|
||||||
log.info('canceling message') |
|
||||||
this.stopPropagation(event) |
|
||||||
this.props.dispatch(actions.cancelMsg(msgData)) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.cancelPersonalMessage = function (msgData, event) { |
|
||||||
log.info('canceling personal message') |
|
||||||
this.stopPropagation(event) |
|
||||||
this.props.dispatch(actions.cancelPersonalMsg(msgData)) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.cancelTypedMessage = function (msgData, event) { |
|
||||||
log.info('canceling typed message') |
|
||||||
this.stopPropagation(event) |
|
||||||
this.props.dispatch(actions.cancelTypedMsg(msgData)) |
|
||||||
} |
|
||||||
|
|
||||||
ConfirmTxScreen.prototype.goHome = function (event) { |
|
||||||
this.stopPropagation(event) |
|
||||||
this.props.dispatch(actions.goHome()) |
|
||||||
} |
|
||||||
|
|
||||||
function warningIfExists (warning) { |
|
||||||
if (warning && |
|
||||||
// Do not display user rejections on this screen:
|
|
||||||
warning.indexOf('User denied transaction signature') === -1) { |
|
||||||
return h('.error', { |
|
||||||
style: { |
|
||||||
margin: 'auto', |
|
||||||
}, |
|
||||||
}, warning) |
|
||||||
} |
|
||||||
} |
|
@ -1,383 +0,0 @@ |
|||||||
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 infuraCurrencies = require('./infura-conversion.json').objects.sort((a, b) => { |
|
||||||
return a.quote.name.toLocaleLowerCase().localeCompare(b.quote.name.toLocaleLowerCase()) |
|
||||||
}) |
|
||||||
const validUrl = require('valid-url') |
|
||||||
const exportAsFile = require('./util').exportAsFile |
|
||||||
const Modal = require('../../ui/app/components/modals/index').Modal |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(ConfigScreen) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
metamask: state.metamask, |
|
||||||
warning: state.appState.warning, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(ConfigScreen, Component) |
|
||||||
function ConfigScreen () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
ConfigScreen.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
var metamaskState = state.metamask |
|
||||||
var warning = state.warning |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.flex-column.flex-grow', { |
|
||||||
style: { |
|
||||||
maxHeight: '585px', |
|
||||||
overflowY: 'auto', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h(Modal, {}, []), |
|
||||||
|
|
||||||
// subtitle and nav
|
|
||||||
h('.section-title.flex-row.flex-center', [ |
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { |
|
||||||
onClick: () => { |
|
||||||
state.dispatch(actions.goHome()) |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('h2.page-subtitle', 'Settings'), |
|
||||||
]), |
|
||||||
|
|
||||||
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', |
|
||||||
overflow: 'auto', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
currentProviderDisplay(metamaskState), |
|
||||||
|
|
||||||
h('div', { style: {display: 'block'} }, [ |
|
||||||
h('input#new_rpc', { |
|
||||||
placeholder: 'New RPC URL', |
|
||||||
style: { |
|
||||||
width: 'inherit', |
|
||||||
flex: '1 0 auto', |
|
||||||
height: '30px', |
|
||||||
margin: '8px', |
|
||||||
}, |
|
||||||
onKeyPress (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
var element = event.target |
|
||||||
var newRpc = element.value |
|
||||||
var chainid = document.querySelector('input#chainid') |
|
||||||
var ticker = document.querySelector('input#ticker') |
|
||||||
var nickname = document.querySelector('input#nickname') |
|
||||||
rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state) |
|
||||||
} |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('br'), |
|
||||||
h('input#chainid', { |
|
||||||
placeholder: 'ChainId (optional)', |
|
||||||
style: { |
|
||||||
width: 'inherit', |
|
||||||
flex: '1 0 auto', |
|
||||||
height: '30px', |
|
||||||
margin: '8px', |
|
||||||
}, |
|
||||||
onKeyPress (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
var element = document.querySelector('input#new_rpc') |
|
||||||
var newRpc = element.value |
|
||||||
var chainid = document.querySelector('input#chainid') |
|
||||||
var ticker = document.querySelector('input#ticker') |
|
||||||
var nickname = document.querySelector('input#nickname') |
|
||||||
rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state) |
|
||||||
} |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('br'), |
|
||||||
h('input#ticker', { |
|
||||||
placeholder: 'Symbol (optional)', |
|
||||||
style: { |
|
||||||
width: 'inherit', |
|
||||||
flex: '1 0 auto', |
|
||||||
height: '30px', |
|
||||||
margin: '8px', |
|
||||||
}, |
|
||||||
onKeyPress (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
var element = document.querySelector('input#new_rpc') |
|
||||||
var newRpc = element.value |
|
||||||
var chainid = document.querySelector('input#chainid') |
|
||||||
var ticker = document.querySelector('input#ticker') |
|
||||||
var nickname = document.querySelector('input#nickname') |
|
||||||
rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state) |
|
||||||
} |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('br'), |
|
||||||
h('input#nickname', { |
|
||||||
placeholder: 'Nickname (optional)', |
|
||||||
style: { |
|
||||||
width: 'inherit', |
|
||||||
flex: '1 0 auto', |
|
||||||
height: '30px', |
|
||||||
margin: '8px', |
|
||||||
}, |
|
||||||
onKeyPress (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
var element = document.querySelector('input#new_rpc') |
|
||||||
var newRpc = element.value |
|
||||||
var chainid = document.querySelector('input#chainid') |
|
||||||
var ticker = document.querySelector('input#ticker') |
|
||||||
var nickname = document.querySelector('input#nickname') |
|
||||||
rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state) |
|
||||||
} |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('button', { |
|
||||||
style: { |
|
||||||
alignSelf: 'center', |
|
||||||
}, |
|
||||||
onClick (event) { |
|
||||||
event.preventDefault() |
|
||||||
var element = document.querySelector('input#new_rpc') |
|
||||||
var newRpc = element.value |
|
||||||
var chainid = document.querySelector('input#chainid') |
|
||||||
var ticker = document.querySelector('input#ticker') |
|
||||||
var nickname = document.querySelector('input#nickname') |
|
||||||
rpcValidation(newRpc, chainid.value, ticker.value, nickname.value, state) |
|
||||||
}, |
|
||||||
}, 'Save'), |
|
||||||
]), |
|
||||||
|
|
||||||
h('hr.horizontal-line'), |
|
||||||
|
|
||||||
currentConversionInformation(metamaskState, state), |
|
||||||
|
|
||||||
h('hr.horizontal-line'), |
|
||||||
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
marginTop: '20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('p', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
fontSize: '13px', |
|
||||||
}, |
|
||||||
}, `State logs contain your public account addresses and sent transactions.`), |
|
||||||
h('br'), |
|
||||||
h('button', { |
|
||||||
style: { |
|
||||||
alignSelf: 'center', |
|
||||||
}, |
|
||||||
onClick (event) { |
|
||||||
window.logStateString((err, result) => { |
|
||||||
if (err) { |
|
||||||
state.dispatch(actions.displayWarning('Error in retrieving state logs.')) |
|
||||||
} else { |
|
||||||
exportAsFile('MetaMask State Logs.json', result) |
|
||||||
} |
|
||||||
}) |
|
||||||
}, |
|
||||||
}, 'Download State Logs'), |
|
||||||
]), |
|
||||||
|
|
||||||
h('hr.horizontal-line'), |
|
||||||
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
marginTop: '20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('p', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
fontSize: '13px', |
|
||||||
}, |
|
||||||
}, 'Clear privacy data so all websites must request access to view account information again.'), |
|
||||||
h('br'), |
|
||||||
h('button', { |
|
||||||
style: { |
|
||||||
alignSelf: 'center', |
|
||||||
}, |
|
||||||
onClick (event) { |
|
||||||
event.preventDefault() |
|
||||||
state.dispatch(actions.clearApprovedOrigins()) |
|
||||||
}, |
|
||||||
}, 'Clear privacy data'), |
|
||||||
]), |
|
||||||
|
|
||||||
h('hr.horizontal-line'), |
|
||||||
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
marginTop: '20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('p', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
fontSize: '13px', |
|
||||||
}, |
|
||||||
}, metamaskState.featureFlags.privacyMode ? |
|
||||||
'Websites will be able to view your account information.' : |
|
||||||
'Websites must request access to view your account information.' |
|
||||||
), |
|
||||||
h('br'), |
|
||||||
h('button', { |
|
||||||
style: { |
|
||||||
alignSelf: 'center', |
|
||||||
}, |
|
||||||
onClick (event) { |
|
||||||
event.preventDefault() |
|
||||||
state.dispatch(actions.setFeatureFlag('privacyMode', !metamaskState.featureFlags.privacyMode)) |
|
||||||
}, |
|
||||||
}, metamaskState.featureFlags.privacyMode ? |
|
||||||
'Disable privacy mode' : |
|
||||||
'Enable privacy mode' |
|
||||||
), |
|
||||||
]), |
|
||||||
|
|
||||||
h('hr.horizontal-line'), |
|
||||||
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
marginTop: '20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('button', { |
|
||||||
style: { |
|
||||||
alignSelf: 'center', |
|
||||||
}, |
|
||||||
onClick (event) { |
|
||||||
event.preventDefault() |
|
||||||
state.dispatch(actions.revealSeedConfirmation()) |
|
||||||
}, |
|
||||||
}, 'Reveal Seed Words'), |
|
||||||
]), |
|
||||||
|
|
||||||
h('hr.horizontal-line'), |
|
||||||
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
marginTop: '20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('p', { |
|
||||||
style: { |
|
||||||
fontFamily: 'Montserrat Light', |
|
||||||
fontSize: '13px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'Resetting is for developer use only. ', |
|
||||||
h('a', { |
|
||||||
href: 'https://metamask.zendesk.com/hc/en-us/articles/360015489231-Resetting-an-Account-Old-UI-', |
|
||||||
target: '_blank', |
|
||||||
}, 'Read more.'), |
|
||||||
]), |
|
||||||
h('br'), |
|
||||||
|
|
||||||
h('button', { |
|
||||||
style: { |
|
||||||
alignSelf: 'center', |
|
||||||
}, |
|
||||||
onClick (event) { |
|
||||||
event.preventDefault() |
|
||||||
state.dispatch(actions.resetAccount()) |
|
||||||
}, |
|
||||||
}, 'Reset Account'), |
|
||||||
]), |
|
||||||
|
|
||||||
]), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
function rpcValidation (newRpc, chainid, ticker = 'ETH', nickname = '', state) { |
|
||||||
if (validUrl.isWebUri(newRpc)) { |
|
||||||
state.dispatch(actions.setRpcTarget(newRpc, chainid, ticker, nickname)) |
|
||||||
} else { |
|
||||||
var appendedRpc = `http://${newRpc}` |
|
||||||
if (validUrl.isWebUri(appendedRpc)) { |
|
||||||
state.dispatch(actions.displayWarning('URIs require the appropriate HTTP/HTTPS prefix.')) |
|
||||||
} else { |
|
||||||
state.dispatch(actions.displayWarning('Invalid RPC URI')) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
function currentConversionInformation (metamaskState, state) { |
|
||||||
var currentCurrency = metamaskState.currentCurrency |
|
||||||
var conversionDate = metamaskState.conversionDate |
|
||||||
return h('div', [ |
|
||||||
h('span', {style: { fontWeight: 'bold', paddingRight: '10px'}}, 'Current Conversion'), |
|
||||||
h('span', {style: { fontWeight: 'bold', paddingRight: '10px', fontSize: '13px'}}, `Updated ${Date(conversionDate)}`), |
|
||||||
h('select#currentCurrency', { |
|
||||||
onChange (event) { |
|
||||||
event.preventDefault() |
|
||||||
var element = document.getElementById('currentCurrency') |
|
||||||
var newCurrency = element.value |
|
||||||
state.dispatch(actions.setCurrentCurrency(newCurrency)) |
|
||||||
}, |
|
||||||
defaultValue: currentCurrency, |
|
||||||
}, infuraCurrencies.map((currency) => { |
|
||||||
return h('option', {key: currency.quote.code, value: currency.quote.code}, `${currency.quote.code.toUpperCase()} - ${currency.quote.name}`) |
|
||||||
}) |
|
||||||
), |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
function currentProviderDisplay (metamaskState) { |
|
||||||
var provider = metamaskState.provider |
|
||||||
var title, value |
|
||||||
|
|
||||||
switch (provider.type) { |
|
||||||
|
|
||||||
case 'mainnet': |
|
||||||
title = 'Current Network' |
|
||||||
value = 'Main Ethereum Network' |
|
||||||
break |
|
||||||
|
|
||||||
case 'ropsten': |
|
||||||
title = 'Current Network' |
|
||||||
value = 'Ropsten Test Network' |
|
||||||
break |
|
||||||
|
|
||||||
case 'kovan': |
|
||||||
title = 'Current Network' |
|
||||||
value = 'Kovan Test Network' |
|
||||||
break |
|
||||||
|
|
||||||
case 'rinkeby': |
|
||||||
title = 'Current Network' |
|
||||||
value = 'Rinkeby Test Network' |
|
||||||
break |
|
||||||
|
|
||||||
default: |
|
||||||
title = 'Current RPC' |
|
||||||
value = metamaskState.provider.rpcTarget |
|
||||||
} |
|
||||||
|
|
||||||
return h('div', [ |
|
||||||
h('span', {style: { fontWeight: 'bold', paddingRight: '10px'}}, title), |
|
||||||
h('span', value), |
|
||||||
]) |
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
/* |
|
||||||
debug / dev |
|
||||||
*/ |
|
||||||
|
|
||||||
#app-content { |
|
||||||
border: 2px solid green; |
|
||||||
} |
|
||||||
|
|
||||||
#design-container { |
|
||||||
position: absolute; |
|
||||||
left: 360px; |
|
||||||
top: -42px; |
|
||||||
width: calc(100vw - 360px); |
|
||||||
height: 100vh; |
|
||||||
overflow: scroll; |
|
||||||
} |
|
||||||
|
|
||||||
#design-container img { |
|
||||||
width: 2000px; |
|
||||||
margin-right: 600px; |
|
||||||
} |
|
@ -1,372 +0,0 @@ |
|||||||
/* cyrillic-ext */ |
|
||||||
@import url('/fonts/Font_Awesome/font-awesome.min.css'); |
|
||||||
|
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 100; |
|
||||||
src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); |
|
||||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; |
|
||||||
} |
|
||||||
/* cyrillic */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 100; |
|
||||||
src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); |
|
||||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; |
|
||||||
} |
|
||||||
/* greek-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 100; |
|
||||||
src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); |
|
||||||
unicode-range: U+1F00-1FFF; |
|
||||||
} |
|
||||||
/* greek */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 100; |
|
||||||
src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); |
|
||||||
unicode-range: U+0370-03FF; |
|
||||||
} |
|
||||||
/* vietnamese */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 100; |
|
||||||
src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); |
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; |
|
||||||
} |
|
||||||
/* latin-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 100; |
|
||||||
src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); |
|
||||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; |
|
||||||
} |
|
||||||
/* latin */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 100; |
|
||||||
src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype'); |
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; |
|
||||||
} |
|
||||||
/* cyrillic-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 300; |
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); |
|
||||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; |
|
||||||
} |
|
||||||
/* cyrillic */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 300; |
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); |
|
||||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; |
|
||||||
} |
|
||||||
/* greek-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 300; |
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); |
|
||||||
unicode-range: U+1F00-1FFF; |
|
||||||
} |
|
||||||
/* greek */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 300; |
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); |
|
||||||
unicode-range: U+0370-03FF; |
|
||||||
} |
|
||||||
/* vietnamese */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 300; |
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); |
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; |
|
||||||
} |
|
||||||
/* latin-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 300; |
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); |
|
||||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; |
|
||||||
} |
|
||||||
/* latin */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 300; |
|
||||||
src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype'); |
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; |
|
||||||
} |
|
||||||
/* cyrillic-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 400; |
|
||||||
src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); |
|
||||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; |
|
||||||
} |
|
||||||
/* cyrillic */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 400; |
|
||||||
src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); |
|
||||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; |
|
||||||
} |
|
||||||
/* greek-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 400; |
|
||||||
src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); |
|
||||||
unicode-range: U+1F00-1FFF; |
|
||||||
} |
|
||||||
/* greek */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 400; |
|
||||||
src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); |
|
||||||
unicode-range: U+0370-03FF; |
|
||||||
} |
|
||||||
/* vietnamese */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 400; |
|
||||||
src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); |
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; |
|
||||||
} |
|
||||||
/* latin-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 400; |
|
||||||
src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); |
|
||||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; |
|
||||||
} |
|
||||||
/* latin */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 400; |
|
||||||
src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype'); |
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; |
|
||||||
} |
|
||||||
/* cyrillic-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 500; |
|
||||||
src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); |
|
||||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; |
|
||||||
} |
|
||||||
/* cyrillic */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 500; |
|
||||||
src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); |
|
||||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; |
|
||||||
} |
|
||||||
/* greek-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 500; |
|
||||||
src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); |
|
||||||
unicode-range: U+1F00-1FFF; |
|
||||||
} |
|
||||||
/* greek */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 500; |
|
||||||
src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); |
|
||||||
unicode-range: U+0370-03FF; |
|
||||||
} |
|
||||||
/* vietnamese */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 500; |
|
||||||
src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); |
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; |
|
||||||
} |
|
||||||
/* latin-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 500; |
|
||||||
src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); |
|
||||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; |
|
||||||
} |
|
||||||
/* latin */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 500; |
|
||||||
src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype'); |
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; |
|
||||||
} |
|
||||||
/* cyrillic-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 700; |
|
||||||
src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); |
|
||||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; |
|
||||||
} |
|
||||||
/* cyrillic */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 700; |
|
||||||
src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); |
|
||||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; |
|
||||||
} |
|
||||||
/* greek-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 700; |
|
||||||
src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); |
|
||||||
unicode-range: U+1F00-1FFF; |
|
||||||
} |
|
||||||
/* greek */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 700; |
|
||||||
src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); |
|
||||||
unicode-range: U+0370-03FF; |
|
||||||
} |
|
||||||
/* vietnamese */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 700; |
|
||||||
src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); |
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; |
|
||||||
} |
|
||||||
/* latin-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 700; |
|
||||||
src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); |
|
||||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; |
|
||||||
} |
|
||||||
/* latin */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 700; |
|
||||||
src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype'); |
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; |
|
||||||
} |
|
||||||
/* cyrillic-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 900; |
|
||||||
src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); |
|
||||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; |
|
||||||
} |
|
||||||
/* cyrillic */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 900; |
|
||||||
src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); |
|
||||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; |
|
||||||
} |
|
||||||
/* greek-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 900; |
|
||||||
src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); |
|
||||||
unicode-range: U+1F00-1FFF; |
|
||||||
} |
|
||||||
/* greek */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 900; |
|
||||||
src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); |
|
||||||
unicode-range: U+0370-03FF; |
|
||||||
} |
|
||||||
/* vietnamese */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 900; |
|
||||||
src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); |
|
||||||
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; |
|
||||||
} |
|
||||||
/* latin-ext */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 900; |
|
||||||
src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); |
|
||||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; |
|
||||||
} |
|
||||||
/* latin */ |
|
||||||
@font-face { |
|
||||||
font-family: 'Roboto'; |
|
||||||
font-style: normal; |
|
||||||
font-weight: 900; |
|
||||||
src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype'); |
|
||||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; |
|
||||||
} |
|
||||||
|
|
||||||
@font-face { |
|
||||||
font-family: 'Montserrat Regular'; |
|
||||||
src: url('/fonts/Montserrat/Montserrat-Regular.woff') format('woff'); |
|
||||||
src: url('/fonts/Montserrat/Montserrat-Regular.ttf') format('truetype'); |
|
||||||
font-weight: normal; |
|
||||||
font-style: normal; |
|
||||||
font-size: 'small'; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@font-face { |
|
||||||
font-family: 'Montserrat Bold'; |
|
||||||
src: url('/fonts/Montserrat/Montserrat-Bold.woff') format('woff'); |
|
||||||
src: url('/fonts/Montserrat/Montserrat-Bold.ttf') format('truetype'); |
|
||||||
font-weight: normal; |
|
||||||
font-style: normal; |
|
||||||
} |
|
||||||
|
|
||||||
@font-face { |
|
||||||
font-family: 'Montserrat Light'; |
|
||||||
src: url('/fonts/Montserrat/Montserrat-Light.woff') format('woff'); |
|
||||||
src: url('/fonts/Montserrat/Montserrat-Light.ttf') format('truetype'); |
|
||||||
font-weight: normal; |
|
||||||
font-style: normal; |
|
||||||
} |
|
||||||
|
|
||||||
@font-face { |
|
||||||
font-family: 'Montserrat UltraLight'; |
|
||||||
src: url('/fonts/Montserrat/Montserrat-UltraLight.woff') format('woff'); |
|
||||||
src: url('/fonts/Montserrat/Montserrat-UltraLight.ttf') format('truetype'); |
|
||||||
font-weight: normal; |
|
||||||
font-style: normal; |
|
||||||
} |
|
@ -1,939 +0,0 @@ |
|||||||
/* |
|
||||||
faint orange (textfield shades) #FAF6F0 |
|
||||||
light orange (button shades): #F5C26D |
|
||||||
dark orange (text): #F5A623 |
|
||||||
borders/font/any gray: #4A4A4A |
|
||||||
*/ |
|
||||||
|
|
||||||
/* |
|
||||||
application specific styles |
|
||||||
*/ |
|
||||||
|
|
||||||
* { |
|
||||||
box-sizing: border-box; |
|
||||||
} |
|
||||||
|
|
||||||
html, body { |
|
||||||
font-family: 'Montserrat Regular', Arial; |
|
||||||
color: #4D4D4D; |
|
||||||
font-weight: 300; |
|
||||||
line-height: 1.4em; |
|
||||||
background: #F7F7F7; |
|
||||||
margin: 0; |
|
||||||
padding: 0; |
|
||||||
height: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
html { |
|
||||||
min-height: 500px; |
|
||||||
} |
|
||||||
|
|
||||||
.app-root { |
|
||||||
overflow: hidden; |
|
||||||
position: relative |
|
||||||
} |
|
||||||
|
|
||||||
.app-primary { |
|
||||||
display: flex; |
|
||||||
} |
|
||||||
|
|
||||||
input:focus, textarea:focus { |
|
||||||
outline: none; |
|
||||||
} |
|
||||||
|
|
||||||
.full-size { |
|
||||||
height: 100%; |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.full-width { |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.full-height { |
|
||||||
height: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.full-flex-height { |
|
||||||
display: flex; |
|
||||||
flex: 1 1 auto; |
|
||||||
flex-direction: column; |
|
||||||
} |
|
||||||
|
|
||||||
#app-content { |
|
||||||
overflow-x: hidden; |
|
||||||
height: 100%; |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
} |
|
||||||
|
|
||||||
button, input[type="submit"] { |
|
||||||
font-family: 'Montserrat Bold'; |
|
||||||
outline: none; |
|
||||||
cursor: pointer; |
|
||||||
padding: 8px 12px; |
|
||||||
border: none; |
|
||||||
color: white; |
|
||||||
transform-origin: center center; |
|
||||||
transition: transform 50ms ease-in; |
|
||||||
/* default orange */ |
|
||||||
background: rgba(247, 134, 28, 1); |
|
||||||
box-shadow: 0px 3px 6px rgba(247, 134, 28, 0.36); |
|
||||||
} |
|
||||||
|
|
||||||
.btn-green, input[type="submit"].btn-green { |
|
||||||
background: rgba(106, 195, 96, 1); |
|
||||||
box-shadow: 0px 3px 6px rgba(106, 195, 96, 0.36); |
|
||||||
} |
|
||||||
|
|
||||||
.btn-red { |
|
||||||
background: rgba(254, 35, 17, 1); |
|
||||||
box-shadow: 0px 3px 6px rgba(254, 35, 17, 0.36); |
|
||||||
} |
|
||||||
|
|
||||||
button[disabled], input[type="submit"][disabled] { |
|
||||||
cursor: not-allowed; |
|
||||||
background: rgba(197, 197, 197, 1); |
|
||||||
box-shadow: 0px 3px 6px rgba(197, 197, 197, 0.36); |
|
||||||
} |
|
||||||
|
|
||||||
button.spaced { |
|
||||||
margin: 2px; |
|
||||||
} |
|
||||||
|
|
||||||
button:not([disabled]):hover, input[type="submit"]:not([disabled]):hover { |
|
||||||
transform: scale(1.1); |
|
||||||
} |
|
||||||
button:not([disabled]):active, input[type="submit"]:not([disabled]):active { |
|
||||||
transform: scale(0.95); |
|
||||||
} |
|
||||||
|
|
||||||
.grow-on-hover:hover { |
|
||||||
transform: scale(1.05); |
|
||||||
} |
|
||||||
|
|
||||||
a { |
|
||||||
text-decoration: none; |
|
||||||
color: inherit; |
|
||||||
} |
|
||||||
|
|
||||||
a:hover{ |
|
||||||
color: #df6b0e; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
app |
|
||||||
*/ |
|
||||||
|
|
||||||
.active { |
|
||||||
color: #909090; |
|
||||||
} |
|
||||||
|
|
||||||
button.primary { |
|
||||||
padding: 8px 12px; |
|
||||||
background: #F7861C; |
|
||||||
box-shadow: 0px 3px 6px rgba(247, 134, 28, 0.36); |
|
||||||
color: white; |
|
||||||
font-size: 1.1em; |
|
||||||
font-family: 'Montserrat Regular'; |
|
||||||
text-transform: uppercase; |
|
||||||
} |
|
||||||
|
|
||||||
button.btn-thin { |
|
||||||
border: 1px solid; |
|
||||||
border-color: #4D4D4D; |
|
||||||
color: #4D4D4D; |
|
||||||
background: rgb(255, 174, 41); |
|
||||||
border-radius: 4px; |
|
||||||
min-width: 200px; |
|
||||||
margin: 12px 0; |
|
||||||
padding: 6px; |
|
||||||
font-size: 13px; |
|
||||||
} |
|
||||||
|
|
||||||
.app-header { |
|
||||||
padding: 6px 8px; |
|
||||||
} |
|
||||||
|
|
||||||
.app-header h1 { |
|
||||||
font-family: 'Montserrat Regular'; |
|
||||||
text-transform: uppercase; |
|
||||||
color: #AEAEAE; |
|
||||||
} |
|
||||||
|
|
||||||
h2.page-subtitle { |
|
||||||
font-family: 'Montserrat Regular'; |
|
||||||
text-transform: uppercase; |
|
||||||
color: #AEAEAE; |
|
||||||
font-size: 1em; |
|
||||||
margin: 12px; |
|
||||||
} |
|
||||||
|
|
||||||
.app-footer { |
|
||||||
padding-bottom: 10px; |
|
||||||
align-items: center; |
|
||||||
} |
|
||||||
|
|
||||||
.identicon { |
|
||||||
height: 46px; |
|
||||||
width: 46px; |
|
||||||
background-size: cover; |
|
||||||
border-radius: 100%; |
|
||||||
border: 3px solid gray; |
|
||||||
} |
|
||||||
|
|
||||||
textarea.twelve-word-phrase { |
|
||||||
padding: 12px; |
|
||||||
width: 300px; |
|
||||||
height: 140px; |
|
||||||
font-size: 16px; |
|
||||||
background: white; |
|
||||||
resize: none; |
|
||||||
} |
|
||||||
|
|
||||||
.network-indicator { |
|
||||||
display: flex; |
|
||||||
align-items: center; |
|
||||||
font-size: 0.6em; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.network-name { |
|
||||||
width: 5.2em; |
|
||||||
line-height: 9px; |
|
||||||
text-rendering: geometricPrecision; |
|
||||||
} |
|
||||||
|
|
||||||
.check { |
|
||||||
margin-left: 12px; |
|
||||||
color: #F7861C; |
|
||||||
flex: 1 0 auto; |
|
||||||
display: flex; |
|
||||||
justify-content: flex-end; |
|
||||||
} |
|
||||||
/* |
|
||||||
app sections |
|
||||||
*/ |
|
||||||
|
|
||||||
/* initialize */ |
|
||||||
|
|
||||||
.initialize-screen hr { |
|
||||||
width: 60px; |
|
||||||
margin: 12px; |
|
||||||
border-color: #F7861C; |
|
||||||
border-style: solid; |
|
||||||
} |
|
||||||
|
|
||||||
.initialize-screen label { |
|
||||||
margin-top: 20px; |
|
||||||
} |
|
||||||
|
|
||||||
.initialize-screen button.create-vault { |
|
||||||
margin-top: 40px; |
|
||||||
} |
|
||||||
|
|
||||||
.initialize-screen .warning { |
|
||||||
font-size: 14px; |
|
||||||
margin: 0 16px; |
|
||||||
} |
|
||||||
|
|
||||||
/* unlock */ |
|
||||||
.error { |
|
||||||
color: #f7861c; |
|
||||||
margin-bottom: 9px; |
|
||||||
} |
|
||||||
|
|
||||||
.warning { |
|
||||||
color: #FFAE00; |
|
||||||
} |
|
||||||
|
|
||||||
.dropped { |
|
||||||
color: #6195ED; |
|
||||||
} |
|
||||||
|
|
||||||
.lock { |
|
||||||
width: 50px; |
|
||||||
height: 50px; |
|
||||||
} |
|
||||||
|
|
||||||
.lock.locked { |
|
||||||
transform: scale(1.5); |
|
||||||
opacity: 0.0; |
|
||||||
transition: opacity 400ms ease-in, transform 400ms ease-in; |
|
||||||
} |
|
||||||
.lock.unlocked { |
|
||||||
transform: scale(1); |
|
||||||
opacity: 1; |
|
||||||
transition: opacity 500ms ease-out, transform 500ms ease-out, background 200ms ease-in; |
|
||||||
} |
|
||||||
|
|
||||||
.lock.locked .lock-top { |
|
||||||
transform: scaleX(1) translateX(0); |
|
||||||
transition: transform 250ms ease-in; |
|
||||||
} |
|
||||||
.lock.unlocked .lock-top { |
|
||||||
transform: scaleX(-1) translateX(-12px); |
|
||||||
transition: transform 250ms ease-in; |
|
||||||
} |
|
||||||
.lock.unlocked:hover { |
|
||||||
border-radius: 4px; |
|
||||||
background: #e5e5e5; |
|
||||||
border: 1px solid #b1b1b1; |
|
||||||
} |
|
||||||
.lock.unlocked:active { |
|
||||||
background: #c3c3c3; |
|
||||||
} |
|
||||||
|
|
||||||
.section-title .fa-arrow-left { |
|
||||||
margin: -2px 8px 0px -8px; |
|
||||||
} |
|
||||||
|
|
||||||
.unlock-screen #metamask-mascot-container { |
|
||||||
margin-top: 80px; |
|
||||||
} |
|
||||||
|
|
||||||
.unlock-screen h1 { |
|
||||||
margin-top: -28px; |
|
||||||
margin-bottom: 42px; |
|
||||||
} |
|
||||||
|
|
||||||
.unlock-screen input[type=password] { |
|
||||||
width: 260px; |
|
||||||
/*height: 36px; |
|
||||||
margin-bottom: 24px; |
|
||||||
padding: 8px;*/ |
|
||||||
} |
|
||||||
|
|
||||||
.sizing-input{ |
|
||||||
font-size: 14px; |
|
||||||
height: 30px; |
|
||||||
padding-left: 5px; |
|
||||||
} |
|
||||||
.editable-label{ |
|
||||||
display: flex; |
|
||||||
} |
|
||||||
/* Webkit */ |
|
||||||
.unlock-screen input::-webkit-input-placeholder { |
|
||||||
text-align: center; |
|
||||||
font-size: 1.2em; |
|
||||||
} |
|
||||||
/* Firefox 18- */ |
|
||||||
.unlock-screen input:-moz-placeholder { |
|
||||||
text-align: center; |
|
||||||
font-size: 1.2em; |
|
||||||
} |
|
||||||
/* Firefox 19+ */ |
|
||||||
.unlock-screen input::-moz-placeholder { |
|
||||||
text-align: center; |
|
||||||
font-size: 1.2em; |
|
||||||
} |
|
||||||
/* IE */ |
|
||||||
.unlock-screen input:-ms-input-placeholder { |
|
||||||
text-align: center; |
|
||||||
font-size: 1.2em; |
|
||||||
} |
|
||||||
|
|
||||||
input.large-input, textarea.large-input { |
|
||||||
/*margin-bottom: 24px;*/ |
|
||||||
padding: 8px; |
|
||||||
} |
|
||||||
|
|
||||||
input.large-input { |
|
||||||
height: 36px; |
|
||||||
} |
|
||||||
|
|
||||||
.letter-spacey { |
|
||||||
letter-spacing: 0.1em; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* accounts */ |
|
||||||
|
|
||||||
.accounts-section { |
|
||||||
margin: 0 0px; |
|
||||||
} |
|
||||||
|
|
||||||
.accounts-section .horizontal-line { |
|
||||||
margin: 0px 18px; |
|
||||||
} |
|
||||||
|
|
||||||
.accounts-list-option { |
|
||||||
height: 120px; |
|
||||||
} |
|
||||||
|
|
||||||
.accounts-list-option .identicon-wrapper { |
|
||||||
width: 100px; |
|
||||||
} |
|
||||||
|
|
||||||
.unconftx-link { |
|
||||||
margin-top: 24px; |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
|
|
||||||
.unconftx-link .fa-arrow-right { |
|
||||||
margin: 0px -8px 0px 8px; |
|
||||||
} |
|
||||||
|
|
||||||
/* identity panel */ |
|
||||||
|
|
||||||
.identity-panel { |
|
||||||
font-weight: 500; |
|
||||||
} |
|
||||||
|
|
||||||
.identity-panel .identicon-wrapper { |
|
||||||
margin: 4px; |
|
||||||
margin-top: 8px; |
|
||||||
display: flex; |
|
||||||
align-items: center; |
|
||||||
} |
|
||||||
|
|
||||||
.identity-panel .identicon-wrapper span { |
|
||||||
margin: 0 auto; |
|
||||||
} |
|
||||||
|
|
||||||
.identity-panel .identity-data { |
|
||||||
margin: 8px 8px 8px 18px; |
|
||||||
} |
|
||||||
|
|
||||||
.identity-panel i { |
|
||||||
margin-top: 32px; |
|
||||||
margin-right: 6px; |
|
||||||
color: #B9B9B9; |
|
||||||
} |
|
||||||
|
|
||||||
.identity-panel .arrow-right { |
|
||||||
padding-left: 18px; |
|
||||||
width: 42px; |
|
||||||
min-width: 18px; |
|
||||||
height: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.identity-copy.flex-column { |
|
||||||
flex: 0.25 0 auto; |
|
||||||
justify-content: center; |
|
||||||
} |
|
||||||
|
|
||||||
/* accounts screen */ |
|
||||||
|
|
||||||
.identity-section { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.identity-section .identity-panel { |
|
||||||
background: #E9E9E9; |
|
||||||
border-bottom: 1px solid #B1B1B1; |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
|
|
||||||
.identity-section .identity-panel.selected { |
|
||||||
background: white; |
|
||||||
color: #F3C83E; |
|
||||||
} |
|
||||||
|
|
||||||
.identity-section .identity-panel.selected .identicon { |
|
||||||
border-color: orange; |
|
||||||
} |
|
||||||
|
|
||||||
.identity-section .accounts-list-option:hover, |
|
||||||
.identity-section .accounts-list-option.selected { |
|
||||||
background:white; |
|
||||||
} |
|
||||||
|
|
||||||
/* account detail screen */ |
|
||||||
|
|
||||||
.account-detail-section { |
|
||||||
display: flex; |
|
||||||
flex-wrap: wrap; |
|
||||||
overflow-x: hidden; |
|
||||||
overflow-y: auto; |
|
||||||
max-height: 585px; |
|
||||||
flex-direction: inherit; |
|
||||||
} |
|
||||||
|
|
||||||
.account-detail-section .name-label { |
|
||||||
margin-left: 15px; |
|
||||||
} |
|
||||||
|
|
||||||
.grow-tenx { |
|
||||||
flex-grow: 10; |
|
||||||
} |
|
||||||
|
|
||||||
.name-label{ |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.unapproved-tx-icon { |
|
||||||
height: 16px; |
|
||||||
width: 16px; |
|
||||||
background: rgb(47, 174, 244); |
|
||||||
border-color: #AEAEAE; |
|
||||||
border-radius: 13px; |
|
||||||
} |
|
||||||
|
|
||||||
.edit-text { |
|
||||||
height: 100%; |
|
||||||
visibility: hidden; |
|
||||||
} |
|
||||||
.editing-label { |
|
||||||
display: flex; |
|
||||||
justify-content: flex-start; |
|
||||||
margin-left: 50px; |
|
||||||
margin-bottom: 2px; |
|
||||||
font-size: 11px; |
|
||||||
text-rendering: geometricPrecision; |
|
||||||
color: #F7861C; |
|
||||||
} |
|
||||||
.name-label:hover .edit-text { |
|
||||||
visibility: visible; |
|
||||||
} |
|
||||||
/* tx confirm */ |
|
||||||
|
|
||||||
.unconftx-section input[type=password] { |
|
||||||
height: 22px; |
|
||||||
padding: 2px; |
|
||||||
margin: 12px; |
|
||||||
margin-bottom: 24px; |
|
||||||
border-radius: 4px; |
|
||||||
border: 2px solid #F3C83E; |
|
||||||
background: #FAF6F0; |
|
||||||
} |
|
||||||
|
|
||||||
/* Send Screen */ |
|
||||||
|
|
||||||
.send-screen { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.send-screen section { |
|
||||||
margin: 8px 16px; |
|
||||||
} |
|
||||||
|
|
||||||
.send-screen input { |
|
||||||
width: 100%; |
|
||||||
font-size: 12px; |
|
||||||
} |
|
||||||
|
|
||||||
/* Ether Balance Widget */ |
|
||||||
|
|
||||||
.ether-balance-amount { |
|
||||||
color: #F7861C; |
|
||||||
} |
|
||||||
|
|
||||||
.ether-balance-label { |
|
||||||
color: #ABA9AA; |
|
||||||
} |
|
||||||
|
|
||||||
/* Info screen */ |
|
||||||
.info-gray{ |
|
||||||
font-family: 'Montserrat Regular'; |
|
||||||
text-transform: uppercase; |
|
||||||
color: #AEAEAE; |
|
||||||
} |
|
||||||
|
|
||||||
.icon-size{ |
|
||||||
width: 20px; |
|
||||||
} |
|
||||||
|
|
||||||
.info{ |
|
||||||
font-family: 'Montserrat Regular', Arial; |
|
||||||
padding-bottom: 10px; |
|
||||||
display: inline-block; |
|
||||||
padding-left: 5px; |
|
||||||
} |
|
||||||
|
|
||||||
/* buy eth warning screen */ |
|
||||||
.custom-radios { |
|
||||||
justify-content: space-around; |
|
||||||
align-items: center; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
.custom-radio-selected { |
|
||||||
width: 17px; |
|
||||||
height: 17px; |
|
||||||
border: solid; |
|
||||||
border-style: double; |
|
||||||
border-radius: 15px; |
|
||||||
border-width: 5px; |
|
||||||
background: rgba(247, 134, 28, 1); |
|
||||||
border-color: #F7F7F7; |
|
||||||
} |
|
||||||
|
|
||||||
.custom-radio-inactive { |
|
||||||
width: 14px; |
|
||||||
height: 14px; |
|
||||||
border: solid; |
|
||||||
border-width: 1px; |
|
||||||
border-radius: 24px; |
|
||||||
border-color: #AEAEAE; |
|
||||||
} |
|
||||||
|
|
||||||
.radio-titles { |
|
||||||
color: rgba(247, 134, 28, 1); |
|
||||||
} |
|
||||||
|
|
||||||
.radio-titles-subtext { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.selected-exchange { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.buy-radio { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.eth-warning{ |
|
||||||
transition: opacity 400ms ease-in, transform 400ms ease-in; |
|
||||||
} |
|
||||||
|
|
||||||
.buy-subview{ |
|
||||||
transition: opacity 400ms ease-in, transform 400ms ease-in; |
|
||||||
} |
|
||||||
|
|
||||||
.input-container:hover .edit-text{ |
|
||||||
visibility: visible; |
|
||||||
} |
|
||||||
|
|
||||||
.buy-inputs{ |
|
||||||
font-family: 'Montserrat Light'; |
|
||||||
font-size: 13px; |
|
||||||
height: 20px; |
|
||||||
background: transparent; |
|
||||||
box-sizing: border-box; |
|
||||||
border: solid; |
|
||||||
border-color: transparent; |
|
||||||
border-width: 0.5px; |
|
||||||
border-radius: 2px; |
|
||||||
|
|
||||||
} |
|
||||||
.input-container:hover .buy-inputs{ |
|
||||||
box-sizing: inherit; |
|
||||||
border: solid; |
|
||||||
border-color: #F7861C; |
|
||||||
border-width: 0.5px; |
|
||||||
border-radius: 2px; |
|
||||||
} |
|
||||||
|
|
||||||
.buy-inputs:focus{ |
|
||||||
border: solid; |
|
||||||
border-color: #F7861C; |
|
||||||
border-width: 0.5px; |
|
||||||
border-radius: 2px; |
|
||||||
} |
|
||||||
|
|
||||||
.activeForm { |
|
||||||
background: #F7F7F7; |
|
||||||
border: none; |
|
||||||
border-radius: 8px 8px 0px 0px; |
|
||||||
width: 50%; |
|
||||||
text-align: center; |
|
||||||
padding-bottom: 4px; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
.inactiveForm { |
|
||||||
border: none; |
|
||||||
border-radius: 8px 8px 0px 0px; |
|
||||||
width: 50%; |
|
||||||
text-align: center; |
|
||||||
padding-bottom: 4px; |
|
||||||
} |
|
||||||
|
|
||||||
.ex-coins { |
|
||||||
font-family: 'Montserrat Regular'; |
|
||||||
text-transform: uppercase; |
|
||||||
text-align: center; |
|
||||||
font-size: 33px; |
|
||||||
width: 118px; |
|
||||||
height: 42px; |
|
||||||
padding: 1px; |
|
||||||
color: #4D4D4D; |
|
||||||
} |
|
||||||
|
|
||||||
.marketinfo{ |
|
||||||
font-family: 'Montserrat light'; |
|
||||||
color: #AEAEAE; |
|
||||||
font-size: 15px; |
|
||||||
line-height: 17px; |
|
||||||
} |
|
||||||
|
|
||||||
#fromCoin::-webkit-calendar-picker-indicator { |
|
||||||
display: none; |
|
||||||
} |
|
||||||
|
|
||||||
#coinList { |
|
||||||
width: 400px; |
|
||||||
height: 500px; |
|
||||||
overflow: scroll; |
|
||||||
} |
|
||||||
|
|
||||||
.icon-control .fa-refresh{ |
|
||||||
visibility: hidden; |
|
||||||
} |
|
||||||
|
|
||||||
.icon-control:hover .fa-refresh{ |
|
||||||
visibility: visible; |
|
||||||
} |
|
||||||
|
|
||||||
.icon-control:hover .fa-chevron-right{ |
|
||||||
visibility: hidden; |
|
||||||
} |
|
||||||
|
|
||||||
.inactive { |
|
||||||
color: #AEAEAE; |
|
||||||
} |
|
||||||
|
|
||||||
.inactive button{ |
|
||||||
background: #AEAEAE; |
|
||||||
color: white; |
|
||||||
} |
|
||||||
|
|
||||||
.ellip-address { |
|
||||||
overflow: hidden; |
|
||||||
text-overflow: ellipsis; |
|
||||||
width: 5em; |
|
||||||
font-size: 14px; |
|
||||||
font-family: "Montserrat Light"; |
|
||||||
margin-left: 5px; |
|
||||||
} |
|
||||||
|
|
||||||
.qr-header { |
|
||||||
font-size: 25px; |
|
||||||
margin-top: 40px; |
|
||||||
} |
|
||||||
|
|
||||||
.qr-message { |
|
||||||
font-size: 12px; |
|
||||||
color: #F7861C; |
|
||||||
} |
|
||||||
|
|
||||||
div.message-container > div:first-child { |
|
||||||
margin-top: 18px; |
|
||||||
font-size: 15px; |
|
||||||
color: #4D4D4D; |
|
||||||
} |
|
||||||
|
|
||||||
.pop-hover:hover { |
|
||||||
transform: scale(1.1); |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement { |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
height: 100%; |
|
||||||
background: white; |
|
||||||
color: #4D4D4D; |
|
||||||
font-family: Roboto, Arial, sans-serif; |
|
||||||
padding: 1.5rem; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__announcement-header { |
|
||||||
display: flex; |
|
||||||
flex-direction: row; |
|
||||||
justify-content: space-between; |
|
||||||
padding-bottom: 1rem; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__announcement-header a.close { |
|
||||||
cursor: pointer; |
|
||||||
font-size: 32px; |
|
||||||
line-height: 17px; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__announcement-header a.close:hover { |
|
||||||
color: inherit; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__announcement-header h1 { |
|
||||||
color: #33A4E7; |
|
||||||
text-transform: uppercase; |
|
||||||
font-size: 18px; |
|
||||||
font-weight: 400; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__body { |
|
||||||
display: flex; |
|
||||||
flex: 1; |
|
||||||
flex-direction: column; |
|
||||||
font-size: 10.5pt; |
|
||||||
font-weight: 300; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__body h1 { |
|
||||||
font-size: 22px; |
|
||||||
font-weight: 600; |
|
||||||
padding-bottom: 1rem; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__body a { |
|
||||||
color: #33A4E7; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__body .updates-list { |
|
||||||
padding: .5rem 1rem; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__body .updates-list h2 { |
|
||||||
font-weight: 600; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__body .updates-list ul { |
|
||||||
list-style: disc inside; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__footer { |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
align-items: center; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__footer h1 { |
|
||||||
font-family: inherit; |
|
||||||
font-weight: 600; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__footer button:hover { |
|
||||||
transform: none; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__footer button.positive { |
|
||||||
padding: 1rem; |
|
||||||
margin: 1rem; |
|
||||||
background: #33A4E7; |
|
||||||
color: white; |
|
||||||
text-transform: uppercase; |
|
||||||
box-shadow: none; |
|
||||||
border-radius: 5px; |
|
||||||
font-family: inherit; |
|
||||||
font-size: 13px; |
|
||||||
font-weight: 400; |
|
||||||
width: 90%; |
|
||||||
} |
|
||||||
|
|
||||||
.new-ui-announcement__footer button.negative { |
|
||||||
margin: 0; |
|
||||||
padding: 0; |
|
||||||
background: white; |
|
||||||
color: #33A4E7; |
|
||||||
font-family: inherit; |
|
||||||
font-size: 13px; |
|
||||||
font-weight: 400; |
|
||||||
box-shadow: none; |
|
||||||
} |
|
||||||
|
|
||||||
.app-bar { |
|
||||||
width: 100%; |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
} |
|
||||||
|
|
||||||
.app-bar__new-ui-banner { |
|
||||||
background: #33A4E7; |
|
||||||
color: white; |
|
||||||
font-size: 12px; |
|
||||||
line-height: 12px; |
|
||||||
padding: 8px; |
|
||||||
font-family: Roboto, Arial, sans-serif; |
|
||||||
font-weight: 400; |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.banner__link { |
|
||||||
cursor: pointer; |
|
||||||
text-decoration: underline; |
|
||||||
} |
|
||||||
|
|
||||||
.notification-modal-wrapper { |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
justify-content: flex-start; |
|
||||||
align-items: center; |
|
||||||
position: relative; |
|
||||||
border: 1px solid #dedede; |
|
||||||
box-shadow: 0 0 2px 2px #dedede; |
|
||||||
font-family: Roboto; |
|
||||||
} |
|
||||||
|
|
||||||
.notification-modal-header { |
|
||||||
background: #f6f6f6; |
|
||||||
width: 100%; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
padding: 30px; |
|
||||||
font-size: 22px; |
|
||||||
color: #1b344d; |
|
||||||
height: 79px; |
|
||||||
} |
|
||||||
|
|
||||||
.notification-modal-message { |
|
||||||
padding: 20px; |
|
||||||
} |
|
||||||
|
|
||||||
.notification-modal-message { |
|
||||||
width: 100%; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
font-size: 17px; |
|
||||||
color: #1b344d; |
|
||||||
} |
|
||||||
|
|
||||||
.modal-close-x::after { |
|
||||||
content: '\00D7'; |
|
||||||
font-size: 2em; |
|
||||||
color: #9b9b9b; |
|
||||||
position: absolute; |
|
||||||
top: 25px; |
|
||||||
right: 17.5px; |
|
||||||
font-family: sans-serif; |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
|
|
||||||
.notification-modal__wrapper { |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
justify-content: flex-start; |
|
||||||
align-items: center; |
|
||||||
position: relative; |
|
||||||
border: 1px solid #dedede; |
|
||||||
box-shadow: 0 0 2px 2px #dedede; |
|
||||||
font-family: Roboto; |
|
||||||
} |
|
||||||
|
|
||||||
.notification-modal__header { |
|
||||||
background: #f6f6f6; |
|
||||||
width: 100%; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
padding: 30px; |
|
||||||
font-size: 22px; |
|
||||||
color: #1b344d; |
|
||||||
height: 79px; |
|
||||||
} |
|
||||||
|
|
||||||
.notification-modal__message { |
|
||||||
padding: 20px; |
|
||||||
width: 100%; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
font-size: 17px; |
|
||||||
color: #1b344d; |
|
||||||
} |
|
||||||
|
|
||||||
.notification-modal__buttons { |
|
||||||
display: flex; |
|
||||||
justify-content: space-evenly; |
|
||||||
width: 100%; |
|
||||||
margin-bottom: 24px; |
|
||||||
padding: 0px 42px; |
|
||||||
} |
|
||||||
|
|
||||||
.notification-modal__buttons__btn { |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
|
|
||||||
.notification-modal__link { |
|
||||||
color: #2f9ae0; |
|
||||||
} |
|
@ -1,306 +0,0 @@ |
|||||||
/* color */ |
|
||||||
|
|
||||||
.color-orange { |
|
||||||
color: #F7861C; |
|
||||||
} |
|
||||||
|
|
||||||
.color-forest { |
|
||||||
color: #0A5448; |
|
||||||
} |
|
||||||
|
|
||||||
/* lib */ |
|
||||||
|
|
||||||
.full-width { |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.full-height { |
|
||||||
height: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-column { |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
} |
|
||||||
|
|
||||||
.space-between { |
|
||||||
justify-content: space-between; |
|
||||||
} |
|
||||||
|
|
||||||
.space-around { |
|
||||||
justify-content: space-around; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-column-bottom { |
|
||||||
display: flex; |
|
||||||
flex-direction: column-reverse; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-row { |
|
||||||
display: flex; |
|
||||||
flex-direction: row; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-space-between { |
|
||||||
justify-content: space-between; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-space-around { |
|
||||||
justify-content: space-around; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-right { |
|
||||||
display: flex; |
|
||||||
flex-direction: row; |
|
||||||
justify-content: flex-end; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-left { |
|
||||||
display: flex; |
|
||||||
flex-direction: row; |
|
||||||
justify-content: flex-start; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-fixed { |
|
||||||
flex: none; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-basis-auto { |
|
||||||
flex-basis: auto; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-grow { |
|
||||||
flex: 1 1 auto; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-wrap { |
|
||||||
flex-wrap: wrap; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-center { |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
align-items: center; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-justify-center { |
|
||||||
justify-content: center; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-align-center { |
|
||||||
align-items: center; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-self-end { |
|
||||||
align-self: flex-end; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-self-stretch { |
|
||||||
align-self: stretch; |
|
||||||
} |
|
||||||
|
|
||||||
.flex-vertical { |
|
||||||
flex-direction: column; |
|
||||||
} |
|
||||||
|
|
||||||
.z-bump { |
|
||||||
z-index: 1; |
|
||||||
} |
|
||||||
|
|
||||||
.select-none { |
|
||||||
cursor: inherit; |
|
||||||
-moz-user-select: none; |
|
||||||
-webkit-user-select: none; |
|
||||||
-ms-user-select: none; |
|
||||||
user-select: none; |
|
||||||
} |
|
||||||
|
|
||||||
.pointer { |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
.cursor-pointer { |
|
||||||
cursor: pointer; |
|
||||||
transform-origin: center center; |
|
||||||
transition: transform 50ms ease-in-out; |
|
||||||
} |
|
||||||
.cursor-pointer:hover { |
|
||||||
transform: scale(1.1); |
|
||||||
} |
|
||||||
.cursor-pointer:active { |
|
||||||
transform: scale(0.95); |
|
||||||
} |
|
||||||
|
|
||||||
.cursor-disabled { |
|
||||||
cursor: not-allowed; |
|
||||||
} |
|
||||||
|
|
||||||
.margin-bottom-sml { |
|
||||||
margin-bottom: 20px; |
|
||||||
} |
|
||||||
|
|
||||||
.margin-bottom-med { |
|
||||||
margin-bottom: 40px; |
|
||||||
} |
|
||||||
|
|
||||||
.margin-right-left { |
|
||||||
margin: 0 20px; |
|
||||||
} |
|
||||||
|
|
||||||
.bold { |
|
||||||
font-weight: bold; |
|
||||||
} |
|
||||||
|
|
||||||
.text-transform-uppercase { |
|
||||||
text-transform: uppercase; |
|
||||||
} |
|
||||||
|
|
||||||
.font-small { |
|
||||||
font-size: 12px; |
|
||||||
} |
|
||||||
|
|
||||||
.font-medium { |
|
||||||
font-size: 1.2em; |
|
||||||
} |
|
||||||
|
|
||||||
hr.horizontal-line { |
|
||||||
display: block; |
|
||||||
height: 1px; |
|
||||||
border: 0; |
|
||||||
border-top: 1px solid #ccc; |
|
||||||
margin: 1em 0; |
|
||||||
padding: 0; |
|
||||||
} |
|
||||||
|
|
||||||
.hover-white:hover { |
|
||||||
background: white; |
|
||||||
} |
|
||||||
|
|
||||||
.red-dot { |
|
||||||
background: #E91550; |
|
||||||
color: white; |
|
||||||
border-radius: 10px; |
|
||||||
} |
|
||||||
|
|
||||||
.diamond { |
|
||||||
transform: rotate(45deg); |
|
||||||
background: #038789; |
|
||||||
} |
|
||||||
|
|
||||||
.hollow-diamond { |
|
||||||
transform: rotate(45deg); |
|
||||||
border: 3px solid #690496; |
|
||||||
} |
|
||||||
|
|
||||||
.golden-square { |
|
||||||
background: #EBB33F; |
|
||||||
} |
|
||||||
|
|
||||||
.pending-dot { |
|
||||||
background: red; |
|
||||||
left: 14px; |
|
||||||
top: 14px; |
|
||||||
color: white; |
|
||||||
border-radius: 10px; |
|
||||||
height: 20px; |
|
||||||
min-width: 20px; |
|
||||||
position: relative; |
|
||||||
display: flex; |
|
||||||
align-items: center; |
|
||||||
justify-content: center; |
|
||||||
padding: 4px; |
|
||||||
z-index: 1; |
|
||||||
} |
|
||||||
|
|
||||||
.keyring-label { |
|
||||||
z-index: 1; |
|
||||||
font-size: 11px; |
|
||||||
background: rgba(255,0,0,0.8); |
|
||||||
color: white; |
|
||||||
bottom: 0px; |
|
||||||
left: -18px; |
|
||||||
border-radius: 10px; |
|
||||||
height: 20px; |
|
||||||
min-width: 20px; |
|
||||||
position: absolute; |
|
||||||
display: flex; |
|
||||||
align-items: center; |
|
||||||
justify-content: center; |
|
||||||
padding: 4px; |
|
||||||
} |
|
||||||
|
|
||||||
.ether-balance { |
|
||||||
display: flex; |
|
||||||
align-items: center; |
|
||||||
} |
|
||||||
|
|
||||||
.tabSection { |
|
||||||
min-width: 350px; |
|
||||||
} |
|
||||||
|
|
||||||
.menu-icon { |
|
||||||
display: inline-block; |
|
||||||
height: 12px; |
|
||||||
min-width: 12px; |
|
||||||
margin: 13px; |
|
||||||
} |
|
||||||
|
|
||||||
i.fa.fa-question-circle.fa-lg.menu-icon { |
|
||||||
font-size: 18px; |
|
||||||
} |
|
||||||
|
|
||||||
.ether-icon { |
|
||||||
background: rgb(0, 163, 68); |
|
||||||
border-radius: 20px; |
|
||||||
} |
|
||||||
.testnet-icon { |
|
||||||
background: #2465E1; |
|
||||||
} |
|
||||||
|
|
||||||
.drop-menu-item { |
|
||||||
display: flex; |
|
||||||
align-items: center; |
|
||||||
} |
|
||||||
|
|
||||||
.invisible { |
|
||||||
visibility: hidden; |
|
||||||
} |
|
||||||
|
|
||||||
.one-line-concat { |
|
||||||
overflow: hidden; |
|
||||||
text-overflow: ellipsis; |
|
||||||
white-space: nowrap; |
|
||||||
} |
|
||||||
|
|
||||||
.critical-error { |
|
||||||
text-align: center; |
|
||||||
margin-top: 20px; |
|
||||||
color: red; |
|
||||||
} |
|
||||||
|
|
||||||
/* |
|
||||||
Hacky breakpoint fix for account + tab sections |
|
||||||
Resolves issue from @frankiebee in |
|
||||||
https://github.com/MetaMask/metamask-extension/pull/1835 |
|
||||||
Please remove this when integrating new designs |
|
||||||
*/ |
|
||||||
|
|
||||||
@media screen and (min-width: 575px) and (max-width: 800px) { |
|
||||||
.account-data-subsection { |
|
||||||
flex: 0 0 auto !important; // reset flex |
|
||||||
margin-left: 10px !important; // create additional horizontal space |
|
||||||
margin-right: 10px !important; |
|
||||||
width: 40%; |
|
||||||
} |
|
||||||
|
|
||||||
.tabSection { |
|
||||||
flex: 0 0 auto !important; |
|
||||||
margin-left: 10px !important; |
|
||||||
margin-right: 10px !important; |
|
||||||
min-width: 285px; |
|
||||||
width: 49%; |
|
||||||
} |
|
||||||
|
|
||||||
.name-label { |
|
||||||
width: 80%; |
|
||||||
} |
|
||||||
} |
|
@ -1,48 +0,0 @@ |
|||||||
/* http://meyerweb.com/eric/tools/css/reset/ |
|
||||||
v2.0 | 20110126 |
|
||||||
License: none (public domain) |
|
||||||
*/ |
|
||||||
|
|
||||||
html, body, div, span, applet, object, iframe, |
|
||||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre, |
|
||||||
a, abbr, acronym, address, big, cite, code, |
|
||||||
del, dfn, em, img, ins, kbd, q, s, samp, |
|
||||||
small, strike, strong, sub, sup, tt, var, |
|
||||||
b, u, i, center, |
|
||||||
dl, dt, dd, ol, ul, li, |
|
||||||
fieldset, form, label, legend, |
|
||||||
table, caption, tbody, tfoot, thead, tr, th, td, |
|
||||||
article, aside, canvas, details, embed, |
|
||||||
figure, figcaption, footer, header, hgroup, |
|
||||||
menu, nav, output, ruby, section, summary, |
|
||||||
time, mark, audio, video { |
|
||||||
margin: 0; |
|
||||||
padding: 0; |
|
||||||
border: 0; |
|
||||||
font-size: 100%; |
|
||||||
font: inherit; |
|
||||||
vertical-align: baseline; |
|
||||||
} |
|
||||||
/* HTML5 display-role reset for older browsers */ |
|
||||||
article, aside, details, figcaption, figure, |
|
||||||
footer, header, hgroup, menu, nav, section { |
|
||||||
display: block; |
|
||||||
} |
|
||||||
body { |
|
||||||
line-height: 1; |
|
||||||
} |
|
||||||
ol, ul { |
|
||||||
list-style: none; |
|
||||||
} |
|
||||||
blockquote, q { |
|
||||||
quotes: none; |
|
||||||
} |
|
||||||
blockquote:before, blockquote:after, |
|
||||||
q:before, q:after { |
|
||||||
content: ''; |
|
||||||
content: none; |
|
||||||
} |
|
||||||
table { |
|
||||||
border-collapse: collapse; |
|
||||||
border-spacing: 0; |
|
||||||
} |
|
@ -1,42 +0,0 @@ |
|||||||
/* universal */ |
|
||||||
.app-primary .main-enter { |
|
||||||
position: absolute; |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
/* center position */ |
|
||||||
.app-primary.from-right .main-enter-active, |
|
||||||
.app-primary.from-left .main-enter-active { |
|
||||||
overflow-x: hidden; |
|
||||||
transform: translateX(0px); |
|
||||||
transition: transform 300ms ease-in; |
|
||||||
} |
|
||||||
|
|
||||||
/* exited positions */ |
|
||||||
.app-primary.from-left .main-leave-active { |
|
||||||
transform: translateX(360px); |
|
||||||
transition: transform 300ms ease-in; |
|
||||||
} |
|
||||||
.app-primary.from-right .main-leave-active { |
|
||||||
transform: translateX(-360px); |
|
||||||
transition: transform 300ms ease-in; |
|
||||||
} |
|
||||||
|
|
||||||
/* loader transitions */ |
|
||||||
.loader-enter, .loader-leave-active { |
|
||||||
opacity: 0.0; |
|
||||||
transition: opacity 150 ease-in; |
|
||||||
} |
|
||||||
.loader-enter-active, .loader-leave { |
|
||||||
opacity: 1.0; |
|
||||||
transition: opacity 150 ease-in; |
|
||||||
} |
|
||||||
|
|
||||||
/* entering positions */ |
|
||||||
.app-primary.from-right .main-enter:not(.main-enter-active) { |
|
||||||
transform: translateX(360px); |
|
||||||
} |
|
||||||
.app-primary.from-left .main-enter:not(.main-enter-active) { |
|
||||||
transform: translateX(-360px); |
|
||||||
} |
|
||||||
|
|
@ -1,179 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const EventEmitter = require('events').EventEmitter |
|
||||||
const Component = require('react').Component |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const Mascot = require('../components/mascot') |
|
||||||
const actions = require('../../../ui/app/actions') |
|
||||||
const Tooltip = require('../components/tooltip') |
|
||||||
const getCaretCoordinates = require('textarea-caret') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(InitializeMenuScreen) |
|
||||||
|
|
||||||
inherits(InitializeMenuScreen, Component) |
|
||||||
function InitializeMenuScreen () { |
|
||||||
Component.call(this) |
|
||||||
this.animationEventEmitter = new EventEmitter() |
|
||||||
} |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
// state from plugin
|
|
||||||
currentView: state.appState.currentView, |
|
||||||
warning: state.appState.warning, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
|
|
||||||
switch (state.currentView.name) { |
|
||||||
|
|
||||||
default: |
|
||||||
return this.renderMenu(state) |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// InitializeMenuScreen.prototype.componentDidMount = function(){
|
|
||||||
// document.getElementById('password-box').focus()
|
|
||||||
// }
|
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.renderMenu = function (state) { |
|
||||||
return ( |
|
||||||
|
|
||||||
h('.initialize-screen.flex-column.flex-center.flex-grow', [ |
|
||||||
|
|
||||||
h(Mascot, { |
|
||||||
animationEventEmitter: this.animationEventEmitter, |
|
||||||
}), |
|
||||||
|
|
||||||
h('h1', { |
|
||||||
style: { |
|
||||||
fontSize: '1.3em', |
|
||||||
textTransform: 'uppercase', |
|
||||||
color: '#7F8082', |
|
||||||
marginBottom: 10, |
|
||||||
}, |
|
||||||
}, 'MetaMask'), |
|
||||||
|
|
||||||
|
|
||||||
h('div', [ |
|
||||||
h('h3', { |
|
||||||
style: { |
|
||||||
fontSize: '0.8em', |
|
||||||
color: '#7F8082', |
|
||||||
display: 'inline', |
|
||||||
}, |
|
||||||
}, 'Encrypt your new DEN'), |
|
||||||
|
|
||||||
h(Tooltip, { |
|
||||||
title: 'Your DEN is your password-encrypted storage within MetaMask.', |
|
||||||
}, [ |
|
||||||
h('i.fa.fa-question-circle.pointer', { |
|
||||||
style: { |
|
||||||
fontSize: '18px', |
|
||||||
position: 'relative', |
|
||||||
color: 'rgb(247, 134, 28)', |
|
||||||
top: '2px', |
|
||||||
marginLeft: '4px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
]), |
|
||||||
|
|
||||||
h('span.in-progress-notification', state.warning), |
|
||||||
|
|
||||||
// password
|
|
||||||
h('input.large-input.letter-spacey', { |
|
||||||
type: 'password', |
|
||||||
id: 'password-box', |
|
||||||
placeholder: 'New Password (min 8 chars)', |
|
||||||
onInput: this.inputChanged.bind(this), |
|
||||||
style: { |
|
||||||
width: 260, |
|
||||||
marginTop: 12, |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
// confirm password
|
|
||||||
h('input.large-input.letter-spacey', { |
|
||||||
type: 'password', |
|
||||||
id: 'password-box-confirm', |
|
||||||
placeholder: 'Confirm Password', |
|
||||||
onKeyPress: this.createVaultOnEnter.bind(this), |
|
||||||
onInput: this.inputChanged.bind(this), |
|
||||||
style: { |
|
||||||
width: 260, |
|
||||||
marginTop: 16, |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
|
|
||||||
h('button.primary', { |
|
||||||
onClick: this.createNewVaultAndKeychain.bind(this), |
|
||||||
style: { |
|
||||||
margin: 12, |
|
||||||
}, |
|
||||||
}, 'Create'), |
|
||||||
|
|
||||||
h('.flex-row.flex-center.flex-grow', [ |
|
||||||
h('p.pointer', { |
|
||||||
onClick: this.showRestoreVault.bind(this), |
|
||||||
style: { |
|
||||||
fontSize: '0.8em', |
|
||||||
color: 'rgb(247, 134, 28)', |
|
||||||
textDecoration: 'underline', |
|
||||||
}, |
|
||||||
}, 'Import Existing DEN'), |
|
||||||
]), |
|
||||||
|
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.createVaultOnEnter = function (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
event.preventDefault() |
|
||||||
this.createNewVaultAndKeychain() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.componentDidMount = function () { |
|
||||||
document.getElementById('password-box').focus() |
|
||||||
} |
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.showRestoreVault = function () { |
|
||||||
this.props.dispatch(actions.showRestoreVault()) |
|
||||||
} |
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () { |
|
||||||
var passwordBox = document.getElementById('password-box') |
|
||||||
var password = passwordBox.value |
|
||||||
var passwordConfirmBox = document.getElementById('password-box-confirm') |
|
||||||
var passwordConfirm = passwordConfirmBox.value |
|
||||||
|
|
||||||
if (password.length < 8) { |
|
||||||
this.warning = 'password not long enough' |
|
||||||
this.props.dispatch(actions.displayWarning(this.warning)) |
|
||||||
return |
|
||||||
} |
|
||||||
if (password !== passwordConfirm) { |
|
||||||
this.warning = 'passwords don\'t match' |
|
||||||
this.props.dispatch(actions.displayWarning(this.warning)) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
this.props.dispatch(actions.createNewVaultAndKeychain(password)) |
|
||||||
} |
|
||||||
|
|
||||||
InitializeMenuScreen.prototype.inputChanged = function (event) { |
|
||||||
// tell mascot to look at page action
|
|
||||||
var element = event.target |
|
||||||
var boundingRect = element.getBoundingClientRect() |
|
||||||
var coordinates = getCaretCoordinates(element, element.selectionEnd) |
|
||||||
this.animationEventEmitter.emit('point', { |
|
||||||
x: boundingRect.left + coordinates.left - element.scrollLeft, |
|
||||||
y: boundingRect.top + coordinates.top - element.scrollTop, |
|
||||||
}) |
|
||||||
} |
|
Before Width: | Height: | Size: 138 KiB |
Before Width: | Height: | Size: 380 KiB |
@ -1,154 +0,0 @@ |
|||||||
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') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(InfoScreen) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return {} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(InfoScreen, Component) |
|
||||||
function InfoScreen () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
InfoScreen.prototype.render = function () { |
|
||||||
const state = this.props |
|
||||||
const version = global.platform.getVersion() |
|
||||||
|
|
||||||
return ( |
|
||||||
h('.flex-column.flex-grow', { |
|
||||||
style: { |
|
||||||
maxWidth: '400px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// subtitle and nav
|
|
||||||
h('.section-title.flex-row.flex-center', [ |
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { |
|
||||||
onClick: (event) => { |
|
||||||
state.dispatch(actions.goHome()) |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('h2.page-subtitle', 'Info'), |
|
||||||
]), |
|
||||||
|
|
||||||
// main view
|
|
||||||
h('.flex-column.flex-justify-center.flex-grow.select-none', [ |
|
||||||
h('.flex-space-around', { |
|
||||||
style: { |
|
||||||
padding: '20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
// current version number
|
|
||||||
|
|
||||||
h('.info.info-gray', [ |
|
||||||
h('div', 'Metamask'), |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
marginBottom: '10px', |
|
||||||
}, |
|
||||||
}, `Version: ${version}`), |
|
||||||
]), |
|
||||||
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
marginBottom: '5px', |
|
||||||
}}, |
|
||||||
[ |
|
||||||
h('div', [ |
|
||||||
h('a', { |
|
||||||
href: 'https://metamask.io/privacy.html', |
|
||||||
target: '_blank', |
|
||||||
onClick: (event) => { this.navigateTo(event.target.href) }, |
|
||||||
}, [ |
|
||||||
h('div.info', 'Privacy Policy'), |
|
||||||
]), |
|
||||||
]), |
|
||||||
h('div', [ |
|
||||||
h('a', { |
|
||||||
href: 'https://metamask.io/terms.html', |
|
||||||
target: '_blank', |
|
||||||
onClick: (event) => { this.navigateTo(event.target.href) }, |
|
||||||
}, [ |
|
||||||
h('div.info', 'Terms of Use'), |
|
||||||
]), |
|
||||||
]), |
|
||||||
h('div', [ |
|
||||||
h('a', { |
|
||||||
href: 'https://metamask.io/attributions.html', |
|
||||||
target: '_blank', |
|
||||||
onClick: (event) => { this.navigateTo(event.target.href) }, |
|
||||||
}, [ |
|
||||||
h('div.info', 'Attributions'), |
|
||||||
]), |
|
||||||
]), |
|
||||||
] |
|
||||||
), |
|
||||||
|
|
||||||
h('hr', { |
|
||||||
style: { |
|
||||||
margin: '10px 0 ', |
|
||||||
width: '7em', |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
paddingLeft: '30px', |
|
||||||
}}, |
|
||||||
[ |
|
||||||
h('div.fa.fa-support', [ |
|
||||||
h('a.info', { |
|
||||||
href: 'https://support.metamask.io', |
|
||||||
target: '_blank', |
|
||||||
}, 'Visit our Support Center'), |
|
||||||
]), |
|
||||||
|
|
||||||
h('div', [ |
|
||||||
h('a', { |
|
||||||
href: 'https://metamask.io/', |
|
||||||
target: '_blank', |
|
||||||
}, [ |
|
||||||
h('img.icon-size', { |
|
||||||
src: 'images/icon-128.png', |
|
||||||
style: { |
|
||||||
// IE6-9
|
|
||||||
filter: 'grayscale(100%)', |
|
||||||
// Microsoft Edge and Firefox 35+
|
|
||||||
WebkitFilter: 'grayscale(100%)', |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('div.info', 'Visit our web site'), |
|
||||||
]), |
|
||||||
]), |
|
||||||
|
|
||||||
h('div', [ |
|
||||||
h('.fa.fa-twitter', [ |
|
||||||
h('a.info', { |
|
||||||
href: 'https://twitter.com/metamask_io', |
|
||||||
target: '_blank', |
|
||||||
}, 'Follow us on Twitter'), |
|
||||||
]), |
|
||||||
]), |
|
||||||
|
|
||||||
h('div.fa.fa-envelope', [ |
|
||||||
h('a.info', { |
|
||||||
target: '_blank', |
|
||||||
href: 'mailto:help@metamask.io?subject=Feedback', |
|
||||||
}, 'Email us!'), |
|
||||||
]), |
|
||||||
]), |
|
||||||
]), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
InfoScreen.prototype.navigateTo = function (url) { |
|
||||||
global.platform.openWindow({ url }) |
|
||||||
} |
|
||||||
|
|
@ -1,653 +0,0 @@ |
|||||||
{ |
|
||||||
"objects": [ |
|
||||||
{ |
|
||||||
"symbol": "ethaud", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "aud", |
|
||||||
"name": "Australian Dollar" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethhkd", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "hkd", |
|
||||||
"name": "Hong Kong Dollar" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethsgd", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "sgd", |
|
||||||
"name": "Singapore Dollar" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethidr", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "idr", |
|
||||||
"name": "Indonesian Rupiah" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethphp", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "php", |
|
||||||
"name": "Philippine Peso" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "eth1st", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "1st", |
|
||||||
"name": "FirstBlood" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethadt", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "adt", |
|
||||||
"name": "adToken" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethadx", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "adx", |
|
||||||
"name": "AdEx" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethant", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "ant", |
|
||||||
"name": "Aragon" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethbat", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "bat", |
|
||||||
"name": "Basic Attention Token" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethbnt", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "bnt", |
|
||||||
"name": "Bancor" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethbtc", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "btc", |
|
||||||
"name": "Bitcoin" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethcad", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "cad", |
|
||||||
"name": "Canadian Dollar" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethcfi", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "cfi", |
|
||||||
"name": "Cofound.it" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethcrb", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "crb", |
|
||||||
"name": "CreditBit" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethcvc", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "cvc", |
|
||||||
"name": "Civic" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethdash", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "dash", |
|
||||||
"name": "Dash" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethdgd", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "dgd", |
|
||||||
"name": "DigixDAO" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethetc", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "etc", |
|
||||||
"name": "Ethereum Classic" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "etheur", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "eur", |
|
||||||
"name": "Euro" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethfun", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "fun", |
|
||||||
"name": "FunFair" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethgbp", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "gbp", |
|
||||||
"name": "Pound Sterling" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethgno", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "gno", |
|
||||||
"name": "Gnosis" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethgnt", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "gnt", |
|
||||||
"name": "Golem" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethgup", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "gup", |
|
||||||
"name": "Matchpool" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethhmq", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "hmq", |
|
||||||
"name": "Humaniq" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethjpy", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "jpy", |
|
||||||
"name": "Japanese Yen" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethlgd", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "lgd", |
|
||||||
"name": "Legends Room" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethlsk", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "lsk", |
|
||||||
"name": "Lisk" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethltc", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "ltc", |
|
||||||
"name": "Litecoin" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethlun", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "lun", |
|
||||||
"name": "Lunyr" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethmco", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "mco", |
|
||||||
"name": "Monaco" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethmtl", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "mtl", |
|
||||||
"name": "Metal" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethmyst", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "myst", |
|
||||||
"name": "Mysterium" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethnmr", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "nmr", |
|
||||||
"name": "Numeraire" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethomg", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "omg", |
|
||||||
"name": "OmiseGO" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethpay", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "pay", |
|
||||||
"name": "TenX" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethptoy", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "ptoy", |
|
||||||
"name": "Patientory" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethqrl", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "qrl", |
|
||||||
"name": "Quantum-Resistant Ledger" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethqtum", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "qtum", |
|
||||||
"name": "Qtum" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethrep", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "rep", |
|
||||||
"name": "Augur" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethrlc", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "rlc", |
|
||||||
"name": "iEx.ec" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethrub", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "rub", |
|
||||||
"name": "Russian Ruble" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethsc", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "sc", |
|
||||||
"name": "Siacoin" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethsngls", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "sngls", |
|
||||||
"name": "SingularDTV" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethsnt", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "snt", |
|
||||||
"name": "Status" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethsteem", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "steem", |
|
||||||
"name": "Steem" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethstorj", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "storj", |
|
||||||
"name": "Storj" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethtime", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "time", |
|
||||||
"name": "ChronoBank" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethtkn", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "tkn", |
|
||||||
"name": "TokenCard" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethtrst", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "trst", |
|
||||||
"name": "WeTrust" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethuah", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "uah", |
|
||||||
"name": "Ukrainian Hryvnia" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethusd", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "usd", |
|
||||||
"name": "United States Dollar" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethwings", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "wings", |
|
||||||
"name": "Wings" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethxem", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "xem", |
|
||||||
"name": "NEM" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethxlm", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "xlm", |
|
||||||
"name": "Stellar Lumen" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethxmr", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "xmr", |
|
||||||
"name": "Monero" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethxrp", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "xrp", |
|
||||||
"name": "Ripple" |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"symbol": "ethzec", |
|
||||||
"base": { |
|
||||||
"code": "eth", |
|
||||||
"name": "Ethereum" |
|
||||||
}, |
|
||||||
"quote": { |
|
||||||
"code": "zec", |
|
||||||
"name": "Zcash" |
|
||||||
} |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
@ -1,91 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const actions = require('../../../../ui/app/actions') |
|
||||||
const exportAsFile = require('../../util').exportAsFile |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(CreateVaultCompleteScreen) |
|
||||||
|
|
||||||
inherits(CreateVaultCompleteScreen, Component) |
|
||||||
function CreateVaultCompleteScreen () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
seed: state.appState.currentView.seedWords, |
|
||||||
cachedSeed: state.metamask.seedWords, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
CreateVaultCompleteScreen.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
var seed = state.seed || state.cachedSeed || '' |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.initialize-screen.flex-column.flex-center.flex-grow', [ |
|
||||||
|
|
||||||
// // subtitle and nav
|
|
||||||
// h('.section-title.flex-row.flex-center', [
|
|
||||||
// h('h2.page-subtitle', 'Vault Created'),
|
|
||||||
// ]),
|
|
||||||
|
|
||||||
h('h3.flex-center.text-transform-uppercase', { |
|
||||||
style: { |
|
||||||
background: '#EBEBEB', |
|
||||||
color: '#AEAEAE', |
|
||||||
marginTop: 36, |
|
||||||
marginBottom: 8, |
|
||||||
width: '100%', |
|
||||||
fontSize: '20px', |
|
||||||
padding: 6, |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'Vault Created', |
|
||||||
]), |
|
||||||
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
fontSize: '1em', |
|
||||||
marginTop: '10px', |
|
||||||
textAlign: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('span.error', 'These 12 words are the only way to restore your MetaMask accounts.\nSave them somewhere safe and secret.'), |
|
||||||
]), |
|
||||||
|
|
||||||
h('textarea.twelve-word-phrase', { |
|
||||||
readOnly: true, |
|
||||||
value: seed, |
|
||||||
}), |
|
||||||
|
|
||||||
h('button.primary', { |
|
||||||
onClick: () => this.confirmSeedWords() |
|
||||||
.then(account => this.showAccountDetail(account)), |
|
||||||
style: { |
|
||||||
margin: '24px', |
|
||||||
fontSize: '0.9em', |
|
||||||
marginBottom: '10px', |
|
||||||
}, |
|
||||||
}, 'I\'ve copied it somewhere safe'), |
|
||||||
|
|
||||||
h('button.primary', { |
|
||||||
onClick: () => exportAsFile(`MetaMask Seed Words`, seed), |
|
||||||
style: { |
|
||||||
margin: '10px', |
|
||||||
fontSize: '0.9em', |
|
||||||
}, |
|
||||||
}, 'Save Seed Words As File'), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
CreateVaultCompleteScreen.prototype.confirmSeedWords = function () { |
|
||||||
return this.props.dispatch(actions.confirmSeedWords()) |
|
||||||
} |
|
||||||
|
|
||||||
CreateVaultCompleteScreen.prototype.showAccountDetail = function (account) { |
|
||||||
return this.props.dispatch(actions.showAccountDetail(account)) |
|
||||||
} |
|
@ -1,121 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
|
|
||||||
const Component = require('react').Component |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const actions = require('../../../../../ui/app/actions') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(RevealSeedConfirmation) |
|
||||||
|
|
||||||
inherits(RevealSeedConfirmation, Component) |
|
||||||
function RevealSeedConfirmation () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
warning: state.appState.warning, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
RevealSeedConfirmation.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.initialize-screen.flex-column.flex-center.flex-grow', { |
|
||||||
style: { maxWidth: '420px' }, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('h3.flex-center.text-transform-uppercase', { |
|
||||||
style: { |
|
||||||
background: '#EBEBEB', |
|
||||||
color: '#AEAEAE', |
|
||||||
marginBottom: 24, |
|
||||||
width: '100%', |
|
||||||
fontSize: '20px', |
|
||||||
padding: 6, |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'Reveal Seed Words', |
|
||||||
]), |
|
||||||
|
|
||||||
h('.div', { |
|
||||||
style: { |
|
||||||
display: 'flex', |
|
||||||
flexDirection: 'column', |
|
||||||
padding: '20px', |
|
||||||
justifyContent: 'center', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('h4', 'Do not recover your seed words in a public place! These words can be used to steal all your accounts.'), |
|
||||||
|
|
||||||
// confirmation
|
|
||||||
h('input.large-input.letter-spacey', { |
|
||||||
type: 'password', |
|
||||||
id: 'password-box', |
|
||||||
placeholder: 'Enter your password to confirm', |
|
||||||
onKeyPress: this.checkConfirmation.bind(this), |
|
||||||
style: { |
|
||||||
width: 260, |
|
||||||
marginTop: '12px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
h('.flex-row.flex-start', { |
|
||||||
style: { |
|
||||||
marginTop: 30, |
|
||||||
width: '50%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
// cancel
|
|
||||||
h('button.primary', { |
|
||||||
onClick: this.goHome.bind(this), |
|
||||||
}, 'CANCEL'), |
|
||||||
|
|
||||||
// submit
|
|
||||||
h('button.primary', { |
|
||||||
style: { marginLeft: '10px' }, |
|
||||||
onClick: this.revealSeedWords.bind(this), |
|
||||||
}, 'OK'), |
|
||||||
|
|
||||||
]), |
|
||||||
|
|
||||||
(props.warning) && ( |
|
||||||
h('span.error', { |
|
||||||
style: { |
|
||||||
margin: '20px', |
|
||||||
}, |
|
||||||
}, props.warning.split('-')) |
|
||||||
), |
|
||||||
|
|
||||||
props.inProgress && ( |
|
||||||
h('span.in-progress-notification', 'Generating Seed...') |
|
||||||
), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
RevealSeedConfirmation.prototype.componentDidMount = function () { |
|
||||||
document.getElementById('password-box').focus() |
|
||||||
} |
|
||||||
|
|
||||||
RevealSeedConfirmation.prototype.goHome = function () { |
|
||||||
this.props.dispatch(actions.showConfigPage(false)) |
|
||||||
} |
|
||||||
|
|
||||||
// create vault
|
|
||||||
|
|
||||||
RevealSeedConfirmation.prototype.checkConfirmation = function (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
event.preventDefault() |
|
||||||
this.revealSeedWords() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
RevealSeedConfirmation.prototype.revealSeedWords = function () { |
|
||||||
var password = document.getElementById('password-box').value |
|
||||||
this.props.dispatch(actions.requestRevealSeed(password)) |
|
||||||
} |
|
@ -1,162 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const PersistentForm = require('../../../lib/persistent-form') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const actions = require('../../../../ui/app/actions') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(RestoreVaultScreen) |
|
||||||
|
|
||||||
inherits(RestoreVaultScreen, PersistentForm) |
|
||||||
function RestoreVaultScreen () { |
|
||||||
PersistentForm.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
warning: state.appState.warning, |
|
||||||
forgottenPassword: state.appState.forgottenPassword, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
RestoreVaultScreen.prototype.render = function () { |
|
||||||
var state = this.props |
|
||||||
this.persistentFormParentId = 'restore-vault-form' |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.initialize-screen.flex-column.flex-center.flex-grow', [ |
|
||||||
|
|
||||||
h('h3.flex-center.text-transform-uppercase', { |
|
||||||
style: { |
|
||||||
background: '#EBEBEB', |
|
||||||
color: '#AEAEAE', |
|
||||||
marginBottom: 24, |
|
||||||
width: '100%', |
|
||||||
fontSize: '20px', |
|
||||||
padding: 6, |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'Restore Vault', |
|
||||||
]), |
|
||||||
|
|
||||||
// wallet seed entry
|
|
||||||
h('h3', 'Wallet Seed'), |
|
||||||
h('textarea.twelve-word-phrase.letter-spacey', { |
|
||||||
placeholder: 'Enter your secret twelve word phrase here to restore your vault.', |
|
||||||
}), |
|
||||||
|
|
||||||
// password
|
|
||||||
h('input.large-input.letter-spacey', { |
|
||||||
type: 'password', |
|
||||||
id: 'password-box', |
|
||||||
placeholder: 'New Password (min 8 chars)', |
|
||||||
dataset: { |
|
||||||
persistentFormId: 'password', |
|
||||||
}, |
|
||||||
style: { |
|
||||||
width: 260, |
|
||||||
marginTop: 12, |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
// confirm password
|
|
||||||
h('input.large-input.letter-spacey', { |
|
||||||
type: 'password', |
|
||||||
id: 'password-box-confirm', |
|
||||||
placeholder: 'Confirm Password', |
|
||||||
onKeyPress: this.createOnEnter.bind(this), |
|
||||||
dataset: { |
|
||||||
persistentFormId: 'password-confirmation', |
|
||||||
}, |
|
||||||
style: { |
|
||||||
width: 260, |
|
||||||
marginTop: 16, |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
(state.warning) && ( |
|
||||||
h('span.error.in-progress-notification', state.warning) |
|
||||||
), |
|
||||||
|
|
||||||
// submit
|
|
||||||
|
|
||||||
h('.flex-row.flex-space-between', { |
|
||||||
style: { |
|
||||||
marginTop: 30, |
|
||||||
width: '50%', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// cancel
|
|
||||||
h('button.primary', { |
|
||||||
onClick: this.showInitializeMenu.bind(this), |
|
||||||
}, 'CANCEL'), |
|
||||||
|
|
||||||
// submit
|
|
||||||
h('button.primary', { |
|
||||||
onClick: this.createNewVaultAndRestore.bind(this), |
|
||||||
}, 'OK'), |
|
||||||
|
|
||||||
]), |
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
RestoreVaultScreen.prototype.showInitializeMenu = function () { |
|
||||||
if (this.props.forgottenPassword) { |
|
||||||
this.props.dispatch(actions.backToUnlockView()) |
|
||||||
} else { |
|
||||||
this.props.dispatch(actions.showInitializeMenu()) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
RestoreVaultScreen.prototype.createOnEnter = function (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
this.createNewVaultAndRestore() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { |
|
||||||
// check password
|
|
||||||
var passwordBox = document.getElementById('password-box') |
|
||||||
var password = passwordBox.value |
|
||||||
var passwordConfirmBox = document.getElementById('password-box-confirm') |
|
||||||
var passwordConfirm = passwordConfirmBox.value |
|
||||||
if (password.length < 8) { |
|
||||||
this.warning = 'Password not long enough' |
|
||||||
|
|
||||||
this.props.dispatch(actions.displayWarning(this.warning)) |
|
||||||
return |
|
||||||
} |
|
||||||
if (password !== passwordConfirm) { |
|
||||||
this.warning = 'Passwords don\'t match' |
|
||||||
this.props.dispatch(actions.displayWarning(this.warning)) |
|
||||||
return |
|
||||||
} |
|
||||||
// check seed
|
|
||||||
var seedBox = document.querySelector('textarea.twelve-word-phrase') |
|
||||||
var seed = seedBox.value.trim() |
|
||||||
|
|
||||||
// true if the string has more than a space between words.
|
|
||||||
if (seed.split(' ').length > 1) { |
|
||||||
this.warning = 'there can only be a space between words' |
|
||||||
this.props.dispatch(actions.displayWarning(this.warning)) |
|
||||||
return |
|
||||||
} |
|
||||||
// true if seed contains a character that is not between a-z or a space
|
|
||||||
if (!seed.match(/^[a-z ]+$/)) { |
|
||||||
this.warning = 'seed words only have lowercase characters' |
|
||||||
this.props.dispatch(actions.displayWarning(this.warning)) |
|
||||||
return |
|
||||||
} |
|
||||||
if (seed.split(' ').length !== 12) { |
|
||||||
this.warning = 'seed phrases are 12 words long' |
|
||||||
this.props.dispatch(actions.displayWarning(this.warning)) |
|
||||||
return |
|
||||||
} |
|
||||||
// submit
|
|
||||||
this.warning = null |
|
||||||
this.props.dispatch(actions.displayWarning(this.warning)) |
|
||||||
this.props.dispatch(actions.createNewVaultAndRestore(password, seed)) |
|
||||||
} |
|
@ -1,29 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(NewKeychain) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return {} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(NewKeychain, Component) |
|
||||||
function NewKeychain () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
NewKeychain.prototype.render = function () { |
|
||||||
// const props = this.props
|
|
||||||
|
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
background: 'blue', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('h1', `Here's a list!!!!`), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
@ -1,85 +0,0 @@ |
|||||||
const PropTypes = require('prop-types') |
|
||||||
const {PureComponent} = require('react') |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const actions = require('../../ui/app/actions') |
|
||||||
|
|
||||||
module.exports = class NewUiAnnouncement extends PureComponent { |
|
||||||
static propTypes = { |
|
||||||
dispatch: PropTypes.func.isRequired, |
|
||||||
}; |
|
||||||
|
|
||||||
close = async () => { |
|
||||||
await this.props.dispatch(actions.setFeatureFlag('skipAnnounceBetaUI', true)) |
|
||||||
} |
|
||||||
|
|
||||||
switchToNewUi = async () => { |
|
||||||
const flag = 'betaUI' |
|
||||||
const enabled = true |
|
||||||
await this.props.dispatch(actions.setFeatureFlag( |
|
||||||
flag, |
|
||||||
enabled, |
|
||||||
)) |
|
||||||
await this.close() |
|
||||||
global.platform.openExtensionInBrowser() |
|
||||||
} |
|
||||||
|
|
||||||
render () { |
|
||||||
return ( |
|
||||||
h('div.new-ui-announcement', [ |
|
||||||
h('section.new-ui-announcement__announcement-header', [ |
|
||||||
h('h1', 'Announcement'), |
|
||||||
h('a.close', { |
|
||||||
onClick: this.close, |
|
||||||
}, '×'), |
|
||||||
]), |
|
||||||
h('section.new-ui-announcement__body', [ |
|
||||||
h('h1', 'A New Version of MetaMask'), |
|
||||||
h('p', [ |
|
||||||
"We're excited to announce a brand-new version of MetaMask with enhanced features and functionality.", |
|
||||||
]), |
|
||||||
h('div.updates-list', [ |
|
||||||
h('h2', 'Updates include'), |
|
||||||
h('ul', [ |
|
||||||
h('li', 'New user interface'), |
|
||||||
h('li', 'Full-screen mode'), |
|
||||||
h('li', 'Better token support'), |
|
||||||
h('li', 'Better gas controls'), |
|
||||||
h('li', 'Advanced features for developers'), |
|
||||||
h('li', 'New confirmation screens'), |
|
||||||
h('li', 'And more!'), |
|
||||||
]), |
|
||||||
]), |
|
||||||
h('p', [ |
|
||||||
'You can still use the current version of MetaMask. The new version is still in beta, ' + |
|
||||||
'however we encourage you to try it out as we transition into this exciting new update.', |
|
||||||
h('span', { |
|
||||||
dangerouslySetInnerHTML: { |
|
||||||
__html: ' ', |
|
||||||
}, |
|
||||||
}), |
|
||||||
h('a', { |
|
||||||
href: 'https://medium.com/metamask/74dba32cc7f7', |
|
||||||
onClick ({target}) { |
|
||||||
const url = target.href |
|
||||||
global.platform.openWindow({ |
|
||||||
url, |
|
||||||
}) |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'Learn more.', |
|
||||||
]), |
|
||||||
]), |
|
||||||
]), |
|
||||||
h('section.new-ui-announcement__footer', [ |
|
||||||
h('h1', 'Ready to try the new MetaMask?'), |
|
||||||
h('button.positive', { |
|
||||||
onClick: this.switchToNewUi, |
|
||||||
}, 'Try it now'), |
|
||||||
h('button.negative', { |
|
||||||
onClick: this.close, |
|
||||||
}, 'No thanks, maybe later'), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
} |
|
@ -1,65 +0,0 @@ |
|||||||
import PropTypes from 'prop-types' |
|
||||||
import React, { Component } from 'react' |
|
||||||
import { approveProviderRequest, rejectProviderRequest } from '../../ui/app/actions' |
|
||||||
import { connect } from 'react-redux' |
|
||||||
class ProviderApproval extends Component { |
|
||||||
render () { |
|
||||||
const { approveProviderRequest, origin, tabID, rejectProviderRequest } = this.props |
|
||||||
return ( |
|
||||||
<div className="flex-column flex-grow"> |
|
||||||
<style dangerouslySetInnerHTML={{__html: ` |
|
||||||
.provider_approval_actions { |
|
||||||
display: flex; |
|
||||||
justify-content: flex-end; |
|
||||||
margin: 14px 25px; |
|
||||||
} |
|
||||||
.provider_approval_actions button { |
|
||||||
margin-left: 10px; |
|
||||||
text-transform: uppercase; |
|
||||||
} |
|
||||||
.provider_approval_content { |
|
||||||
padding: 0 25px; |
|
||||||
} |
|
||||||
.provider_approval_origin { |
|
||||||
font-weight: bold; |
|
||||||
margin: 14px 0; |
|
||||||
} |
|
||||||
`}} />
|
|
||||||
<div className="section-title flex-row flex-center"> |
|
||||||
<i |
|
||||||
className="fa fa-arrow-left fa-lg cursor-pointer" |
|
||||||
onClick={() => { rejectProviderRequest(tabID) }} /> |
|
||||||
<h2 className="page-subtitle">Web3 API Request</h2> |
|
||||||
</div> |
|
||||||
<div className="provider_approval_content"> |
|
||||||
{"The domain listed below is requesting access to the Ethereum blockchain and to view your current account. Always double check that you're on the correct site before approving access."} |
|
||||||
<div className="provider_approval_origin">{origin}</div> |
|
||||||
</div> |
|
||||||
<div className="provider_approval_actions"> |
|
||||||
<button |
|
||||||
className="btn-green" |
|
||||||
onClick={() => { approveProviderRequest(tabID) }}>APPROVE</button> |
|
||||||
<button |
|
||||||
className="cancel btn-red" |
|
||||||
onClick={() => { rejectProviderRequest(tabID) }}>REJECT</button> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ProviderApproval.propTypes = { |
|
||||||
approveProviderRequest: PropTypes.func, |
|
||||||
origin: PropTypes.string, |
|
||||||
tabID: PropTypes.string, |
|
||||||
rejectProviderRequest: PropTypes.func, |
|
||||||
} |
|
||||||
|
|
||||||
function mapDispatchToProps (dispatch) { |
|
||||||
return { |
|
||||||
approveProviderRequest: tabID => dispatch(approveProviderRequest(tabID)), |
|
||||||
rejectProviderRequest: tabID => dispatch(rejectProviderRequest(tabID)), |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = connect(null, mapDispatchToProps)(ProviderApproval) |
|
@ -1,309 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const PersistentForm = require('../lib/persistent-form') |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
const Identicon = require('./components/identicon') |
|
||||||
const actions = require('../../ui/app/actions') |
|
||||||
const util = require('./util') |
|
||||||
const numericBalance = require('./util').numericBalance |
|
||||||
const addressSummary = require('./util').addressSummary |
|
||||||
const isHex = require('./util').isHex |
|
||||||
const EthBalance = require('./components/eth-balance') |
|
||||||
const EnsInput = require('./components/ens-input') |
|
||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
module.exports = connect(mapStateToProps)(SendTransactionScreen) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
var result = { |
|
||||||
address: state.metamask.selectedAddress, |
|
||||||
accounts: state.metamask.accounts, |
|
||||||
identities: state.metamask.identities, |
|
||||||
warning: state.appState.warning, |
|
||||||
network: state.metamask.network, |
|
||||||
addressBook: state.metamask.addressBook, |
|
||||||
conversionRate: state.metamask.conversionRate, |
|
||||||
currentCurrency: state.metamask.currentCurrency, |
|
||||||
} |
|
||||||
|
|
||||||
result.error = result.warning && result.warning.split('.')[0] |
|
||||||
|
|
||||||
result.account = result.accounts[result.address] |
|
||||||
result.identity = result.identities[result.address] |
|
||||||
result.balance = result.account ? numericBalance(result.account.balance) : null |
|
||||||
|
|
||||||
return result |
|
||||||
} |
|
||||||
|
|
||||||
inherits(SendTransactionScreen, PersistentForm) |
|
||||||
function SendTransactionScreen () { |
|
||||||
PersistentForm.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
SendTransactionScreen.prototype.render = function () { |
|
||||||
this.persistentFormParentId = 'send-tx-form' |
|
||||||
|
|
||||||
const props = this.props |
|
||||||
const { |
|
||||||
address, |
|
||||||
account, |
|
||||||
identity, |
|
||||||
network, |
|
||||||
identities, |
|
||||||
addressBook, |
|
||||||
conversionRate, |
|
||||||
currentCurrency, |
|
||||||
} = props |
|
||||||
|
|
||||||
return ( |
|
||||||
|
|
||||||
h('.send-screen.flex-column.flex-grow', [ |
|
||||||
|
|
||||||
//
|
|
||||||
// Sender Profile
|
|
||||||
//
|
|
||||||
|
|
||||||
h('.account-data-subsection.flex-row.flex-grow', { |
|
||||||
style: { |
|
||||||
margin: '0 20px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
// header - identicon + nav
|
|
||||||
h('.flex-row.flex-space-between', { |
|
||||||
style: { |
|
||||||
marginTop: '15px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
// back button
|
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', { |
|
||||||
onClick: this.back.bind(this), |
|
||||||
}), |
|
||||||
|
|
||||||
// large identicon
|
|
||||||
h('.identicon-wrapper.flex-column.flex-center.select-none', [ |
|
||||||
h(Identicon, { |
|
||||||
diameter: 62, |
|
||||||
address: address, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
// invisible place holder
|
|
||||||
h('i.fa.fa-users.fa-lg.invisible', { |
|
||||||
style: { |
|
||||||
marginTop: '28px', |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
]), |
|
||||||
|
|
||||||
// account label
|
|
||||||
|
|
||||||
h('.flex-column', { |
|
||||||
style: { |
|
||||||
marginTop: '10px', |
|
||||||
alignItems: 'flex-start', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('h2.font-medium.color-forest.flex-center', { |
|
||||||
style: { |
|
||||||
paddingTop: '8px', |
|
||||||
marginBottom: '8px', |
|
||||||
}, |
|
||||||
}, identity && identity.name), |
|
||||||
|
|
||||||
// address and getter actions
|
|
||||||
h('.flex-row.flex-center', { |
|
||||||
style: { |
|
||||||
marginBottom: '8px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
|
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
lineHeight: '16px', |
|
||||||
}, |
|
||||||
}, addressSummary(address)), |
|
||||||
|
|
||||||
]), |
|
||||||
|
|
||||||
// balance
|
|
||||||
h('.flex-row.flex-center', [ |
|
||||||
|
|
||||||
h(EthBalance, { |
|
||||||
value: account && account.balance, |
|
||||||
conversionRate, |
|
||||||
currentCurrency, |
|
||||||
}), |
|
||||||
|
|
||||||
]), |
|
||||||
]), |
|
||||||
]), |
|
||||||
|
|
||||||
//
|
|
||||||
// Required Fields
|
|
||||||
//
|
|
||||||
|
|
||||||
h('h3.flex-center.text-transform-uppercase', { |
|
||||||
style: { |
|
||||||
background: '#EBEBEB', |
|
||||||
color: '#AEAEAE', |
|
||||||
marginTop: '15px', |
|
||||||
marginBottom: '16px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'Send Transaction', |
|
||||||
]), |
|
||||||
|
|
||||||
// error message
|
|
||||||
props.error && h('span.error.flex-center', props.error), |
|
||||||
|
|
||||||
// 'to' field
|
|
||||||
h('section.flex-row.flex-center', [ |
|
||||||
h(EnsInput, { |
|
||||||
name: 'address', |
|
||||||
placeholder: 'Recipient Address', |
|
||||||
onChange: this.recipientDidChange.bind(this), |
|
||||||
network, |
|
||||||
identities, |
|
||||||
addressBook, |
|
||||||
}), |
|
||||||
]), |
|
||||||
|
|
||||||
// 'amount' and send button
|
|
||||||
h('section.flex-row.flex-center', [ |
|
||||||
|
|
||||||
h('input.large-input', { |
|
||||||
name: 'amount', |
|
||||||
placeholder: 'Amount', |
|
||||||
type: 'number', |
|
||||||
style: { |
|
||||||
marginRight: '6px', |
|
||||||
}, |
|
||||||
dataset: { |
|
||||||
persistentFormId: 'tx-amount', |
|
||||||
}, |
|
||||||
}), |
|
||||||
|
|
||||||
h('button.primary', { |
|
||||||
onClick: this.onSubmit.bind(this), |
|
||||||
style: { |
|
||||||
textTransform: 'uppercase', |
|
||||||
}, |
|
||||||
}, 'Next'), |
|
||||||
|
|
||||||
]), |
|
||||||
|
|
||||||
//
|
|
||||||
// Optional Fields
|
|
||||||
//
|
|
||||||
h('h3.flex-center.text-transform-uppercase', { |
|
||||||
style: { |
|
||||||
background: '#EBEBEB', |
|
||||||
color: '#AEAEAE', |
|
||||||
marginTop: '16px', |
|
||||||
marginBottom: '16px', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
'Transaction Data (optional)', |
|
||||||
]), |
|
||||||
|
|
||||||
// 'data' field
|
|
||||||
h('section.flex-column.flex-center', [ |
|
||||||
h('input.large-input', { |
|
||||||
name: 'txData', |
|
||||||
placeholder: '0x01234', |
|
||||||
style: { |
|
||||||
width: '100%', |
|
||||||
resize: 'none', |
|
||||||
}, |
|
||||||
dataset: { |
|
||||||
persistentFormId: 'tx-data', |
|
||||||
}, |
|
||||||
}), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
SendTransactionScreen.prototype.navigateToAccounts = function (event) { |
|
||||||
event.stopPropagation() |
|
||||||
this.props.dispatch(actions.showAccountsPage()) |
|
||||||
} |
|
||||||
|
|
||||||
SendTransactionScreen.prototype.back = function () { |
|
||||||
var address = this.props.address |
|
||||||
this.props.dispatch(actions.backToAccountDetail(address)) |
|
||||||
} |
|
||||||
|
|
||||||
SendTransactionScreen.prototype.recipientDidChange = function (recipient, nickname) { |
|
||||||
this.setState({ |
|
||||||
recipient: recipient, |
|
||||||
nickname: nickname, |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
SendTransactionScreen.prototype.onSubmit = function () { |
|
||||||
const state = this.state || {} |
|
||||||
const recipient = state.recipient || document.querySelector('input[name="address"]').value.replace(/^[.\s]+|[.\s]+$/g, '') |
|
||||||
const nickname = state.nickname || ' ' |
|
||||||
const input = document.querySelector('input[name="amount"]').value |
|
||||||
const parts = input.split('') |
|
||||||
|
|
||||||
let message |
|
||||||
|
|
||||||
if (isNaN(input) || input === '') { |
|
||||||
message = 'Invalid ether value.' |
|
||||||
return this.props.dispatch(actions.displayWarning(message)) |
|
||||||
} |
|
||||||
|
|
||||||
if (parts[1]) { |
|
||||||
var decimal = parts[1] |
|
||||||
if (decimal.length > 18) { |
|
||||||
message = 'Ether amount is too precise.' |
|
||||||
return this.props.dispatch(actions.displayWarning(message)) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
const value = util.normalizeEthStringToWei(input) |
|
||||||
const txData = document.querySelector('input[name="txData"]').value |
|
||||||
const balance = this.props.balance |
|
||||||
|
|
||||||
if (value.gt(balance)) { |
|
||||||
message = 'Insufficient funds.' |
|
||||||
return this.props.dispatch(actions.displayWarning(message)) |
|
||||||
} |
|
||||||
|
|
||||||
if (input < 0) { |
|
||||||
message = 'Can not send negative amounts of ETH.' |
|
||||||
return this.props.dispatch(actions.displayWarning(message)) |
|
||||||
} |
|
||||||
|
|
||||||
if ((util.isInvalidChecksumAddress(recipient))) { |
|
||||||
message = 'Recipient address checksum is invalid.' |
|
||||||
return this.props.dispatch(actions.displayWarning(message)) |
|
||||||
} |
|
||||||
|
|
||||||
if ((!util.isValidAddress(recipient) && !txData) || (!recipient && !txData)) { |
|
||||||
message = 'Recipient address is invalid.' |
|
||||||
return this.props.dispatch(actions.displayWarning(message)) |
|
||||||
} |
|
||||||
|
|
||||||
if (!isHex(ethUtil.stripHexPrefix(txData)) && txData) { |
|
||||||
message = 'Transaction data must be hex string.' |
|
||||||
return this.props.dispatch(actions.displayWarning(message)) |
|
||||||
} |
|
||||||
|
|
||||||
this.props.dispatch(actions.hideWarning()) |
|
||||||
|
|
||||||
this.props.dispatch(actions.addToAddressBook(recipient, nickname)) |
|
||||||
|
|
||||||
var txParams = { |
|
||||||
from: this.props.address, |
|
||||||
value: '0x' + value.toString(16), |
|
||||||
} |
|
||||||
|
|
||||||
if (recipient) txParams.to = ethUtil.addHexPrefix(recipient) |
|
||||||
if (txData) txParams.data = txData |
|
||||||
|
|
||||||
this.props.dispatch(actions.signTx(txParams)) |
|
||||||
} |
|
@ -1,59 +0,0 @@ |
|||||||
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') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(AppSettingsPage) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return {} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(AppSettingsPage, Component) |
|
||||||
function AppSettingsPage () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
AppSettingsPage.prototype.render = function () { |
|
||||||
return ( |
|
||||||
|
|
||||||
h('.account-detail-section.flex-column.flex-grow', [ |
|
||||||
|
|
||||||
// subtitle and nav
|
|
||||||
h('.flex-row.flex-center', [ |
|
||||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { |
|
||||||
onClick: this.navigateToAccounts.bind(this), |
|
||||||
}), |
|
||||||
h('h2.page-subtitle', 'Settings'), |
|
||||||
]), |
|
||||||
|
|
||||||
h('label', { |
|
||||||
htmlFor: 'settings-rpc-endpoint', |
|
||||||
}, 'RPC Endpoint:'), |
|
||||||
h('input', { |
|
||||||
type: 'url', |
|
||||||
id: 'settings-rpc-endpoint', |
|
||||||
onKeyPress: this.onKeyPress.bind(this), |
|
||||||
}), |
|
||||||
|
|
||||||
]) |
|
||||||
|
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
AppSettingsPage.prototype.componentDidMount = function () { |
|
||||||
document.querySelector('input').focus() |
|
||||||
} |
|
||||||
|
|
||||||
AppSettingsPage.prototype.onKeyPress = function (event) { |
|
||||||
// get submit event
|
|
||||||
if (event.key === 'Enter') { |
|
||||||
// this.submitPassword(event)
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
AppSettingsPage.prototype.navigateToAccounts = function (event) { |
|
||||||
event.stopPropagation() |
|
||||||
this.props.dispatch(actions.showAccountsPage()) |
|
||||||
} |
|
@ -1,30 +0,0 @@ |
|||||||
const inherits = require('util').inherits |
|
||||||
const Component = require('react').Component |
|
||||||
const h = require('react-hyperscript') |
|
||||||
const connect = require('react-redux').connect |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(COMPONENTNAME) |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return {} |
|
||||||
} |
|
||||||
|
|
||||||
inherits(COMPONENTNAME, Component) |
|
||||||
function COMPONENTNAME () { |
|
||||||
Component.call(this) |
|
||||||
} |
|
||||||
|
|
||||||
COMPONENTNAME.prototype.render = function () { |
|
||||||
const props = this.props |
|
||||||
|
|
||||||
return ( |
|
||||||
h('div', { |
|
||||||
style: { |
|
||||||
background: 'blue', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
`Hello, ${props.sender}`, |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
@ -1,122 +0,0 @@ |
|||||||
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 getCaretCoordinates = require('textarea-caret') |
|
||||||
const EventEmitter = require('events').EventEmitter |
|
||||||
|
|
||||||
const Mascot = require('./components/mascot') |
|
||||||
|
|
||||||
module.exports = connect(mapStateToProps)(UnlockScreen) |
|
||||||
|
|
||||||
inherits(UnlockScreen, Component) |
|
||||||
function UnlockScreen () { |
|
||||||
Component.call(this) |
|
||||||
this.animationEventEmitter = new EventEmitter() |
|
||||||
} |
|
||||||
|
|
||||||
function mapStateToProps (state) { |
|
||||||
return { |
|
||||||
warning: state.appState.warning, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
UnlockScreen.prototype.render = function () { |
|
||||||
const state = this.props |
|
||||||
const warning = state.warning |
|
||||||
return ( |
|
||||||
h('.flex-column', { |
|
||||||
style: { |
|
||||||
width: 'inherit', |
|
||||||
}, |
|
||||||
}, [ |
|
||||||
h('.unlock-screen.flex-column.flex-center.flex-grow', [ |
|
||||||
|
|
||||||
h(Mascot, { |
|
||||||
animationEventEmitter: this.animationEventEmitter, |
|
||||||
}), |
|
||||||
|
|
||||||
h('h1', { |
|
||||||
style: { |
|
||||||
fontSize: '1.4em', |
|
||||||
textTransform: 'uppercase', |
|
||||||
color: '#7F8082', |
|
||||||
}, |
|
||||||
}, 'MetaMask'), |
|
||||||
|
|
||||||
h('input.large-input', { |
|
||||||
type: 'password', |
|
||||||
id: 'password-box', |
|
||||||
placeholder: 'enter password', |
|
||||||
style: { |
|
||||||
|
|
||||||
}, |
|
||||||
onKeyPress: this.onKeyPress.bind(this), |
|
||||||
onInput: this.inputChanged.bind(this), |
|
||||||
}), |
|
||||||
|
|
||||||
h('.error', { |
|
||||||
style: { |
|
||||||
display: warning ? 'block' : 'none', |
|
||||||
padding: '0 20px', |
|
||||||
textAlign: 'center', |
|
||||||
}, |
|
||||||
}, warning), |
|
||||||
|
|
||||||
h('button.primary.cursor-pointer', { |
|
||||||
onClick: this.onSubmit.bind(this), |
|
||||||
style: { |
|
||||||
margin: 10, |
|
||||||
}, |
|
||||||
}, 'Log In'), |
|
||||||
]), |
|
||||||
|
|
||||||
h('.flex-row.flex-center.flex-grow', [ |
|
||||||
h('p.pointer', { |
|
||||||
onClick: () => this.props.dispatch(actions.forgotPassword()), |
|
||||||
style: { |
|
||||||
fontSize: '0.8em', |
|
||||||
color: 'rgb(247, 134, 28)', |
|
||||||
textDecoration: 'underline', |
|
||||||
}, |
|
||||||
}, 'Restore from seed phrase'), |
|
||||||
]), |
|
||||||
]) |
|
||||||
) |
|
||||||
} |
|
||||||
|
|
||||||
UnlockScreen.prototype.componentDidMount = function () { |
|
||||||
document.getElementById('password-box').focus() |
|
||||||
} |
|
||||||
|
|
||||||
UnlockScreen.prototype.onSubmit = function (event) { |
|
||||||
const input = document.getElementById('password-box') |
|
||||||
const password = input.value |
|
||||||
this.props.dispatch(actions.tryUnlockMetamask(password)) |
|
||||||
} |
|
||||||
|
|
||||||
UnlockScreen.prototype.onKeyPress = function (event) { |
|
||||||
if (event.key === 'Enter') { |
|
||||||
this.submitPassword(event) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
UnlockScreen.prototype.submitPassword = function (event) { |
|
||||||
var element = event.target |
|
||||||
var password = element.value |
|
||||||
// reset input
|
|
||||||
element.value = '' |
|
||||||
this.props.dispatch(actions.tryUnlockMetamask(password)) |
|
||||||
} |
|
||||||
|
|
||||||
UnlockScreen.prototype.inputChanged = function (event) { |
|
||||||
// tell mascot to look at page action
|
|
||||||
var element = event.target |
|
||||||
var boundingRect = element.getBoundingClientRect() |
|
||||||
var coordinates = getCaretCoordinates(element, element.selectionEnd) |
|
||||||
this.animationEventEmitter.emit('point', { |
|
||||||
x: boundingRect.left + coordinates.left - element.scrollLeft, |
|
||||||
y: boundingRect.top + coordinates.top - element.scrollTop, |
|
||||||
}) |
|
||||||
} |
|
@ -1,241 +0,0 @@ |
|||||||
const ethUtil = require('ethereumjs-util') |
|
||||||
|
|
||||||
var valueTable = { |
|
||||||
wei: '1000000000000000000', |
|
||||||
kwei: '1000000000000000', |
|
||||||
mwei: '1000000000000', |
|
||||||
gwei: '1000000000', |
|
||||||
szabo: '1000000', |
|
||||||
finney: '1000', |
|
||||||
ether: '1', |
|
||||||
kether: '0.001', |
|
||||||
mether: '0.000001', |
|
||||||
gether: '0.000000001', |
|
||||||
tether: '0.000000000001', |
|
||||||
} |
|
||||||
var bnTable = {} |
|
||||||
for (var currency in valueTable) { |
|
||||||
bnTable[currency] = new ethUtil.BN(valueTable[currency], 10) |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = { |
|
||||||
valuesFor: valuesFor, |
|
||||||
addressSummary: addressSummary, |
|
||||||
miniAddressSummary: miniAddressSummary, |
|
||||||
isAllOneCase: isAllOneCase, |
|
||||||
isValidAddress: isValidAddress, |
|
||||||
numericBalance: numericBalance, |
|
||||||
parseBalance: parseBalance, |
|
||||||
formatBalance: formatBalance, |
|
||||||
generateBalanceObject: generateBalanceObject, |
|
||||||
dataSize: dataSize, |
|
||||||
readableDate: readableDate, |
|
||||||
normalizeToWei: normalizeToWei, |
|
||||||
normalizeEthStringToWei: normalizeEthStringToWei, |
|
||||||
normalizeNumberToWei: normalizeNumberToWei, |
|
||||||
valueTable: valueTable, |
|
||||||
bnTable: bnTable, |
|
||||||
isHex: isHex, |
|
||||||
exportAsFile: exportAsFile, |
|
||||||
isInvalidChecksumAddress, |
|
||||||
} |
|
||||||
|
|
||||||
function valuesFor (obj) { |
|
||||||
if (!obj) return [] |
|
||||||
return Object.keys(obj) |
|
||||||
.map(function (key) { return obj[key] }) |
|
||||||
} |
|
||||||
|
|
||||||
function addressSummary (address, firstSegLength = 10, lastSegLength = 4, includeHex = true) { |
|
||||||
if (!address) return '' |
|
||||||
let checked = ethUtil.toChecksumAddress(address) |
|
||||||
if (!includeHex) { |
|
||||||
checked = ethUtil.stripHexPrefix(checked) |
|
||||||
} |
|
||||||
return checked ? checked.slice(0, firstSegLength) + '...' + checked.slice(checked.length - lastSegLength) : '...' |
|
||||||
} |
|
||||||
|
|
||||||
function miniAddressSummary (address) { |
|
||||||
if (!address) return '' |
|
||||||
var checked = ethUtil.toChecksumAddress(address) |
|
||||||
return checked ? checked.slice(0, 4) + '...' + checked.slice(-4) : '...' |
|
||||||
} |
|
||||||
|
|
||||||
function isValidAddress (address) { |
|
||||||
var prefixed = ethUtil.addHexPrefix(address) |
|
||||||
if (address === '0x0000000000000000000000000000000000000000') return false |
|
||||||
return (isAllOneCase(prefixed) && ethUtil.isValidAddress(prefixed)) || ethUtil.isValidChecksumAddress(prefixed) |
|
||||||
} |
|
||||||
|
|
||||||
function isInvalidChecksumAddress (address) { |
|
||||||
var prefixed = ethUtil.addHexPrefix(address) |
|
||||||
if (address === '0x0000000000000000000000000000000000000000') return false |
|
||||||
return !isAllOneCase(prefixed) && !ethUtil.isValidChecksumAddress(prefixed) && ethUtil.isValidAddress(prefixed) |
|
||||||
} |
|
||||||
|
|
||||||
function isAllOneCase (address) { |
|
||||||
if (!address) return true |
|
||||||
var lower = address.toLowerCase() |
|
||||||
var upper = address.toUpperCase() |
|
||||||
return address === lower || address === upper |
|
||||||
} |
|
||||||
|
|
||||||
// Takes wei Hex, returns wei BN, even if input is null
|
|
||||||
function numericBalance (balance) { |
|
||||||
if (!balance) return new ethUtil.BN(0, 16) |
|
||||||
var stripped = ethUtil.stripHexPrefix(balance) |
|
||||||
return new ethUtil.BN(stripped, 16) |
|
||||||
} |
|
||||||
|
|
||||||
// Takes hex, returns [beforeDecimal, afterDecimal]
|
|
||||||
function parseBalance (balance) { |
|
||||||
var beforeDecimal, afterDecimal |
|
||||||
const wei = numericBalance(balance) |
|
||||||
var weiString = wei.toString() |
|
||||||
const trailingZeros = /0+$/ |
|
||||||
|
|
||||||
beforeDecimal = weiString.length > 18 ? weiString.slice(0, weiString.length - 18) : '0' |
|
||||||
afterDecimal = ('000000000000000000' + wei).slice(-18).replace(trailingZeros, '') |
|
||||||
if (afterDecimal === '') { afterDecimal = '0' } |
|
||||||
return [beforeDecimal, afterDecimal] |
|
||||||
} |
|
||||||
|
|
||||||
// Takes wei hex, returns an object with three properties.
|
|
||||||
// Its "formatted" property is what we generally use to render values.
|
|
||||||
function formatBalance (balance, decimalsToKeep, needsParse = true, ticker = 'ETH') { |
|
||||||
var parsed = needsParse ? parseBalance(balance) : balance.split('.') |
|
||||||
var beforeDecimal = parsed[0] |
|
||||||
var afterDecimal = parsed[1] |
|
||||||
var formatted = 'None' |
|
||||||
if (decimalsToKeep === undefined) { |
|
||||||
if (beforeDecimal === '0') { |
|
||||||
if (afterDecimal !== '0') { |
|
||||||
var sigFigs = afterDecimal.match(/^0*(.{2})/) // default: grabs 2 most significant digits
|
|
||||||
if (sigFigs) { afterDecimal = sigFigs[0] } |
|
||||||
formatted = '0.' + afterDecimal + ` ${ticker}` |
|
||||||
} |
|
||||||
} else { |
|
||||||
formatted = beforeDecimal + '.' + afterDecimal.slice(0, 3) + ` ${ticker}` |
|
||||||
} |
|
||||||
} else { |
|
||||||
afterDecimal += Array(decimalsToKeep).join('0') |
|
||||||
formatted = beforeDecimal + '.' + afterDecimal.slice(0, decimalsToKeep) + ` ${ticker}` |
|
||||||
} |
|
||||||
return formatted |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
function generateBalanceObject (formattedBalance, decimalsToKeep = 1) { |
|
||||||
var balance = formattedBalance.split(' ')[0] |
|
||||||
var label = formattedBalance.split(' ')[1] |
|
||||||
var beforeDecimal = balance.split('.')[0] |
|
||||||
var afterDecimal = balance.split('.')[1] |
|
||||||
var shortBalance = shortenBalance(balance, decimalsToKeep) |
|
||||||
|
|
||||||
if (beforeDecimal === '0' && afterDecimal.substr(0, 5) === '00000') { |
|
||||||
// eslint-disable-next-line eqeqeq
|
|
||||||
if (afterDecimal == 0) { |
|
||||||
balance = '0' |
|
||||||
} else { |
|
||||||
balance = '<1.0e-5' |
|
||||||
} |
|
||||||
} else if (beforeDecimal !== '0') { |
|
||||||
balance = `${beforeDecimal}.${afterDecimal.slice(0, decimalsToKeep)}` |
|
||||||
} |
|
||||||
|
|
||||||
return { balance, label, shortBalance } |
|
||||||
} |
|
||||||
|
|
||||||
function shortenBalance (balance, decimalsToKeep = 1) { |
|
||||||
var truncatedValue |
|
||||||
var convertedBalance = parseFloat(balance) |
|
||||||
if (convertedBalance > 1000000) { |
|
||||||
truncatedValue = (balance / 1000000).toFixed(decimalsToKeep) |
|
||||||
return `${truncatedValue}m` |
|
||||||
} else if (convertedBalance > 1000) { |
|
||||||
truncatedValue = (balance / 1000).toFixed(decimalsToKeep) |
|
||||||
return `${truncatedValue}k` |
|
||||||
} else if (convertedBalance === 0) { |
|
||||||
return '0' |
|
||||||
} else if (convertedBalance < 0.001) { |
|
||||||
return '<0.001' |
|
||||||
} else if (convertedBalance < 1) { |
|
||||||
var stringBalance = convertedBalance.toString() |
|
||||||
if (stringBalance.split('.')[1].length > 3) { |
|
||||||
return convertedBalance.toFixed(3) |
|
||||||
} else { |
|
||||||
return stringBalance |
|
||||||
} |
|
||||||
} else { |
|
||||||
return convertedBalance.toFixed(decimalsToKeep) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
function dataSize (data) { |
|
||||||
var size = data ? ethUtil.stripHexPrefix(data).length : 0 |
|
||||||
return size + ' bytes' |
|
||||||
} |
|
||||||
|
|
||||||
// Takes a BN and an ethereum currency name,
|
|
||||||
// returns a BN in wei
|
|
||||||
function normalizeToWei (amount, currency) { |
|
||||||
try { |
|
||||||
return amount.mul(bnTable.wei).div(bnTable[currency]) |
|
||||||
} catch (e) {} |
|
||||||
return amount |
|
||||||
} |
|
||||||
|
|
||||||
function normalizeEthStringToWei (str) { |
|
||||||
const parts = str.split('.') |
|
||||||
let eth = new ethUtil.BN(parts[0], 10).mul(bnTable.wei) |
|
||||||
if (parts[1]) { |
|
||||||
var decimal = parts[1] |
|
||||||
while (decimal.length < 18) { |
|
||||||
decimal += '0' |
|
||||||
} |
|
||||||
const decimalBN = new ethUtil.BN(decimal, 10) |
|
||||||
eth = eth.add(decimalBN) |
|
||||||
} |
|
||||||
return eth |
|
||||||
} |
|
||||||
|
|
||||||
var multiple = new ethUtil.BN('10000', 10) |
|
||||||
function normalizeNumberToWei (n, currency) { |
|
||||||
var enlarged = n * 10000 |
|
||||||
var amount = new ethUtil.BN(String(enlarged), 10) |
|
||||||
return normalizeToWei(amount, currency).div(multiple) |
|
||||||
} |
|
||||||
|
|
||||||
function readableDate (ms) { |
|
||||||
var date = new Date(ms) |
|
||||||
var month = date.getMonth() |
|
||||||
var day = date.getDate() |
|
||||||
var year = date.getFullYear() |
|
||||||
var hours = date.getHours() |
|
||||||
var minutes = '0' + date.getMinutes() |
|
||||||
var seconds = '0' + date.getSeconds() |
|
||||||
|
|
||||||
var dateStr = `${month}/${day}/${year}` |
|
||||||
var time = `${hours}:${minutes.substr(-2)}:${seconds.substr(-2)}` |
|
||||||
return `${dateStr} ${time}` |
|
||||||
} |
|
||||||
|
|
||||||
function isHex (str) { |
|
||||||
return Boolean(str.match(/^(0x)?[0-9a-fA-F]+$/)) |
|
||||||
} |
|
||||||
|
|
||||||
function exportAsFile (filename, data) { |
|
||||||
// source: https://stackoverflow.com/a/33542499 by Ludovic Feltz
|
|
||||||
const blob = new Blob([data], {type: 'text/csv'}) |
|
||||||
if (window.navigator.msSaveOrOpenBlob) { |
|
||||||
window.navigator.msSaveBlob(blob, filename) |
|
||||||
} else { |
|
||||||
const elem = window.document.createElement('a') |
|
||||||
elem.target = '_blank' |
|
||||||
elem.href = window.URL.createObjectURL(blob) |
|
||||||
elem.download = filename |
|
||||||
document.body.appendChild(elem) |
|
||||||
elem.click() |
|
||||||
document.body.removeChild(elem) |
|
||||||
} |
|
||||||
} |
|
@ -1,29 +0,0 @@ |
|||||||
const fs = require('fs') |
|
||||||
const path = require('path') |
|
||||||
|
|
||||||
module.exports = bundleCss |
|
||||||
|
|
||||||
var cssFiles = { |
|
||||||
'fonts.css': fs.readFileSync(path.join(__dirname, '/app/css/fonts.css'), 'utf8'), |
|
||||||
'reset.css': fs.readFileSync(path.join(__dirname, '/app/css/reset.css'), 'utf8'), |
|
||||||
'lib.css': fs.readFileSync(path.join(__dirname, '/app/css/lib.css'), 'utf8'), |
|
||||||
'index.css': fs.readFileSync(path.join(__dirname, '/app/css/index.css'), 'utf8'), |
|
||||||
'transitions.css': fs.readFileSync(path.join(__dirname, '/app/css/transitions.css'), 'utf8'), |
|
||||||
'react-tooltip-component.css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-tooltip-component', 'dist', 'react-tooltip-component.css'), 'utf8'), |
|
||||||
'react-css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-select', 'dist', 'react-select.css'), 'utf8'), |
|
||||||
} |
|
||||||
|
|
||||||
function bundleCss () { |
|
||||||
var cssBundle = Object.keys(cssFiles).reduce(function (bundle, fileName) { |
|
||||||
var fileContent = cssFiles[fileName] |
|
||||||
var output = String() |
|
||||||
|
|
||||||
output += '/*========== ' + fileName + ' ==========*/\n\n' |
|
||||||
output += fileContent |
|
||||||
output += '\n\n' |
|
||||||
|
|
||||||
return bundle + output |
|
||||||
}, String()) |
|
||||||
|
|
||||||
return cssBundle |
|
||||||
} |
|
Before Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 108 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 215 KiB |
Before Width: | Height: | Size: 209 KiB |
Before Width: | Height: | Size: 247 KiB |
Before Width: | Height: | Size: 189 KiB |
Before Width: | Height: | Size: 5.6 KiB |