Merge pull request #406 from MetaMask/ConfirmationStyle
Update transaction confirmation style
This commit is contained in:
commit
2bd31c3e50
|
@ -6,6 +6,7 @@
|
|||
- Fix formatting of account details.
|
||||
- Use web3 minified dist for faster inject times
|
||||
- Fix issue where dropdowns were not in front of icons.
|
||||
- Update transaction approval styles.
|
||||
- Align failed and successful transaction history text.
|
||||
|
||||
## 2.5.0 2016-06-29
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="4.2333331mm"
|
||||
height="12.800793mm"
|
||||
viewBox="0 0 14.999999 45.357139"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="forward-carrat.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.6"
|
||||
inkscape:cx="17.87049"
|
||||
inkscape:cy="17.678567"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
showguides="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1276"
|
||||
inkscape:window-height="755"
|
||||
inkscape:window-x="4"
|
||||
inkscape:window-y="1"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4136"
|
||||
originx="-180"
|
||||
originy="-602.14286" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-180,-404.8622)">
|
||||
<path
|
||||
style="fill:#f7861c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 180,404.8622 0,7.5 10,15 -10,15 0,7.85714 15,-22.85714 z"
|
||||
id="path4138"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
|
@ -18,7 +18,7 @@ html, body, #app-content, .super-dev-container {
|
|||
height: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
background: #cccccc;
|
||||
background: white;
|
||||
}
|
||||
.mock-app-root {
|
||||
background: #F7F7F7;
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,84 @@
|
|||
{
|
||||
"metamask": {
|
||||
"isInitialized": true,
|
||||
"isUnlocked": true,
|
||||
"currentDomain": "example.com",
|
||||
"rpcTarget": "https://rawtestrpc.metamask.io/",
|
||||
"identities": {
|
||||
"0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": {
|
||||
"name": "Wallet 1",
|
||||
"address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
|
||||
"mayBeFauceting": false
|
||||
},
|
||||
"0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": {
|
||||
"name": "Wallet 2",
|
||||
"address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b",
|
||||
"mayBeFauceting": false
|
||||
},
|
||||
"0xeb9e64b93097bc15f01f13eae97015c57ab64823": {
|
||||
"name": "Wallet 3",
|
||||
"address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823",
|
||||
"mayBeFauceting": false
|
||||
},
|
||||
"0x704107d04affddd9b66ab9de3dd7b095852e9b69": {
|
||||
"name": "Wallet 4",
|
||||
"address": "0x704107d04affddd9b66ab9de3dd7b095852e9b69",
|
||||
"mayBeFauceting": false
|
||||
}
|
||||
},
|
||||
"unconfTxs": {},
|
||||
"accounts": {
|
||||
"0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": {
|
||||
"code": "0x",
|
||||
"balance": "0x01",
|
||||
"nonce": "0x0",
|
||||
"address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
|
||||
},
|
||||
"0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": {
|
||||
"code": "0x",
|
||||
"nonce": "0x0",
|
||||
"balance": "0x01",
|
||||
"address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b"
|
||||
},
|
||||
"0xeb9e64b93097bc15f01f13eae97015c57ab64823": {
|
||||
"code": "0x",
|
||||
"nonce": "0x0",
|
||||
"balance": "0x01",
|
||||
"address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823"
|
||||
},
|
||||
"0x704107d04affddd9b66ab9de3dd7b095852e9b69": {
|
||||
"code": "0x",
|
||||
"balance": "0x0",
|
||||
"nonce": "0x0",
|
||||
"address": "0x704107d04affddd9b66ab9de3dd7b095852e9b69"
|
||||
}
|
||||
},
|
||||
"transactions": [],
|
||||
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
|
||||
"network": "2",
|
||||
"seedWords": null,
|
||||
"isConfirmed": true,
|
||||
"unconfMsgs": {},
|
||||
"messages": [],
|
||||
"provider": {
|
||||
"type": "testnet"
|
||||
},
|
||||
"selectedAccount": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
|
||||
},
|
||||
"appState": {
|
||||
"menuOpen": false,
|
||||
"currentView": {
|
||||
"name": "accountDetail",
|
||||
"detailView": null,
|
||||
"context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
|
||||
},
|
||||
"accountDetail": {
|
||||
"subview": "transactions"
|
||||
},
|
||||
"currentDomain": "127.0.0.1:9966",
|
||||
"transForward": true,
|
||||
"isLoading": false,
|
||||
"warning": null
|
||||
},
|
||||
"identities": {}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,44 @@
|
|||
var assert = require('assert')
|
||||
var sinon = require('sinon')
|
||||
|
||||
var path = require('path')
|
||||
var contractNamer = require(path.join(__dirname, '..', '..', 'ui', 'lib', 'contract-namer.js'))
|
||||
|
||||
describe('contractNamer', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
this.sinon = sinon.sandbox.create()
|
||||
})
|
||||
|
||||
afterEach(function() {
|
||||
this.sinon.restore()
|
||||
})
|
||||
|
||||
describe('naming a contract', function() {
|
||||
|
||||
it('should return nothing for an unknown random account', function() {
|
||||
const input = '0x2386F26FC10000'
|
||||
const output = contractNamer(input)
|
||||
assert.deepEqual(output, null)
|
||||
})
|
||||
|
||||
it('should accept identities as an optional second parameter', function() {
|
||||
const input = '0x2386F26FC10000'.toLowerCase()
|
||||
const expected = 'bar'
|
||||
const identities = {}
|
||||
identities[input] = { name: expected }
|
||||
const output = contractNamer(input, identities)
|
||||
assert.deepEqual(output, expected)
|
||||
})
|
||||
|
||||
it('should check for identities case insensitively', function() {
|
||||
const input = '0x2386F26FC10000'.toLowerCase()
|
||||
const expected = 'bar'
|
||||
const identities = {}
|
||||
identities[input] = { name: expected }
|
||||
const output = contractNamer(input.toUpperCase(), identities)
|
||||
assert.deepEqual(output, expected)
|
||||
})
|
||||
|
||||
})
|
||||
})
|
|
@ -52,6 +52,12 @@ describe('util', function() {
|
|||
var result = util.addressSummary(address)
|
||||
assert.equal(result, '0xFDEa65C8...b825')
|
||||
})
|
||||
|
||||
it('should accept arguments for firstseg, lastseg, and keepPrefix', function() {
|
||||
var address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825'
|
||||
var result = util.addressSummary(address, 4, 4, false)
|
||||
assert.equal(result, 'FDEa...b825')
|
||||
})
|
||||
})
|
||||
|
||||
describe('isValidAddress', function() {
|
||||
|
|
19
ui-dev.js
19
ui-dev.js
|
@ -1,3 +1,20 @@
|
|||
/* UI DEV
|
||||
*
|
||||
* This is a utility module.
|
||||
* It initializes a minimalist browserifiable project
|
||||
* that contains the Metamask UI, with a mocked state.
|
||||
*
|
||||
* Includes a state menu for switching between different
|
||||
* mocked states, along with query param support,
|
||||
* so those states are preserved when live-reloading.
|
||||
*
|
||||
* This is a convenient way to develop on the UI
|
||||
* without having to re-enter your password
|
||||
* every time the plugin rebuilds.
|
||||
*
|
||||
* To use, run `npm run ui`.
|
||||
*/
|
||||
|
||||
const render = require('react-dom').render
|
||||
const h = require('react-hyperscript')
|
||||
const Root = require('./ui/app/root')
|
||||
|
@ -54,7 +71,7 @@ render(
|
|||
style: {
|
||||
height: '500px',
|
||||
width: '360px',
|
||||
boxShadow: '2px 2px 5px grey',
|
||||
boxShadow: 'grey 0px 2px 9px',
|
||||
margin: '20px',
|
||||
},
|
||||
}, [
|
||||
|
|
|
@ -22,7 +22,7 @@ AccountPanel.prototype.render = function () {
|
|||
var panelState = {
|
||||
key: `accountPanel${identity.address}`,
|
||||
identiconKey: identity.address,
|
||||
identiconLabel: identity.name,
|
||||
identiconLabel: identity.name || '',
|
||||
attributes: [
|
||||
{
|
||||
key: 'ADDRESS',
|
||||
|
|
|
@ -12,9 +12,11 @@ function EthBalanceComponent () {
|
|||
}
|
||||
|
||||
EthBalanceComponent.prototype.render = function () {
|
||||
var state = this.props
|
||||
var style = state.style
|
||||
var value = formatBalance(state.value)
|
||||
var props = this.props
|
||||
var style = props.style
|
||||
|
||||
const value = formatBalance(props.value)
|
||||
|
||||
return (
|
||||
|
||||
h('.ether-balance', {
|
||||
|
@ -30,33 +32,49 @@ EthBalanceComponent.prototype.render = function () {
|
|||
)
|
||||
}
|
||||
EthBalanceComponent.prototype.renderBalance = function (value) {
|
||||
const props = this.props
|
||||
if (value === 'None') return value
|
||||
var balanceObj = generateBalanceObject(value)
|
||||
|
||||
var balance = balanceObj.balance
|
||||
var label = balanceObj.label
|
||||
var tagName = props.inline ? 'span' : 'div'
|
||||
var topTag = props.inline ? 'div' : '.flex-column'
|
||||
|
||||
return (
|
||||
|
||||
h(Tooltip, {
|
||||
position: 'bottom',
|
||||
title: value.split(' ')[0],
|
||||
}, [
|
||||
h('.flex-column', {
|
||||
h(topTag, {
|
||||
style: {
|
||||
alignItems: 'flex-end',
|
||||
lineHeight: '13px',
|
||||
fontFamily: 'Montserrat Light',
|
||||
lineHeight: props.fontSize || '13px',
|
||||
fontFamily: 'Montserrat Regular',
|
||||
textRendering: 'geometricPrecision',
|
||||
},
|
||||
}, [
|
||||
h('div', balance),
|
||||
h('div', {
|
||||
h(tagName, {
|
||||
style: {
|
||||
color: ' #AEAEAE',
|
||||
fontSize: '12px',
|
||||
fontSize: props.fontSize || '12px',
|
||||
},
|
||||
}, label),
|
||||
}, balance + ' '),
|
||||
h(tagName, {
|
||||
style: {
|
||||
color: props.labelColor || '#AEAEAE',
|
||||
fontSize: props.fontSize || '12px',
|
||||
},
|
||||
}, [
|
||||
h('div', balance),
|
||||
h('div', {
|
||||
style: {
|
||||
color: '#AEAEAE',
|
||||
fontSize: '12px',
|
||||
},
|
||||
}, label),
|
||||
]),
|
||||
]),
|
||||
])
|
||||
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
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,
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
|
@ -2,10 +2,17 @@ const Component = require('react').Component
|
|||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
|
||||
const AccountPanel = require('./account-panel')
|
||||
const MiniAccountPanel = require('./mini-account-panel')
|
||||
const EtherBalance = require('./eth-balance')
|
||||
const addressSummary = require('../util').addressSummary
|
||||
const readableDate = require('../util').readableDate
|
||||
const formatBalance = require('../util').formatBalance
|
||||
const nameForAddress = require('../../lib/contract-namer')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const BN = ethUtil.BN
|
||||
|
||||
const baseGasFee = new BN('21000', 10)
|
||||
const gasCost = new BN('4a817c800', 16)
|
||||
const baseFeeHex = baseGasFee.mul(gasCost).toString(16)
|
||||
|
||||
module.exports = PendingTxDetails
|
||||
|
||||
|
@ -14,52 +21,204 @@ function PendingTxDetails () {
|
|||
Component.call(this)
|
||||
}
|
||||
|
||||
PendingTxDetails.prototype.render = function () {
|
||||
var state = this.props
|
||||
return this.renderGeneric(h, state)
|
||||
}
|
||||
const PTXP = PendingTxDetails.prototype
|
||||
|
||||
PendingTxDetails.prototype.renderGeneric = function (h, state) {
|
||||
var txData = state.txData
|
||||
PTXP.render = function () {
|
||||
var props = this.props
|
||||
var txData = props.txData
|
||||
|
||||
var txParams = txData.txParams || {}
|
||||
var address = txParams.from || state.selectedAddress
|
||||
var identity = state.identities[address] || { address: address }
|
||||
var account = state.accounts[address] || { address: address }
|
||||
var address = txParams.from || props.selectedAddress
|
||||
var identity = props.identities[address] || { address: address }
|
||||
var balance = props.accounts[address].balance
|
||||
|
||||
var gasCost = ethUtil.stripHexPrefix(txParams.gas || baseFeeHex)
|
||||
var txValue = ethUtil.stripHexPrefix(txParams.value || '0x0')
|
||||
var maxCost = ((new BN(txValue, 16)).add(new BN(gasCost, 16))).toString(16)
|
||||
var dataLength = txParams.data ? (txParams.data.length - 2) / 2 : 0
|
||||
|
||||
return (
|
||||
|
||||
h('div', [
|
||||
|
||||
// account that will sign
|
||||
h(AccountPanel, {
|
||||
showFullAddress: true,
|
||||
identity: identity,
|
||||
account: account,
|
||||
imageifyIdenticons: state.imageifyIdenticons,
|
||||
}),
|
||||
h('.flex-row.flex-center', {
|
||||
style: {
|
||||
maxWidth: '100%',
|
||||
},
|
||||
}, [
|
||||
|
||||
// tx data
|
||||
h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [
|
||||
h(MiniAccountPanel, {
|
||||
imageSeed: address,
|
||||
imageifyIdenticons: props.imageifyIdenticons,
|
||||
picOrder: 'right',
|
||||
}, [
|
||||
h('span.font-small', {
|
||||
style: {
|
||||
fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
|
||||
},
|
||||
}, identity.name),
|
||||
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(EtherBalance, {
|
||||
value: balance,
|
||||
inline: true,
|
||||
})),
|
||||
|
||||
h('.flex-row.flex-space-between', [
|
||||
h('label.font-small', 'TO ADDRESS'),
|
||||
h('span.font-small', addressSummary(txParams.to)),
|
||||
]),
|
||||
|
||||
h('.flex-row.flex-space-between', [
|
||||
h('label.font-small', 'DATE'),
|
||||
h('span.font-small', readableDate(txData.time)),
|
||||
]),
|
||||
h('img', {
|
||||
src: 'images/forward-carrat.svg',
|
||||
style: {
|
||||
padding: '5px 6px 0px 10px',
|
||||
height: '37px',
|
||||
},
|
||||
}),
|
||||
|
||||
h('.flex-row.flex-space-between', [
|
||||
h('label.font-small', 'AMOUNT'),
|
||||
h('span.font-small', formatBalance(txParams.value)),
|
||||
]),
|
||||
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', [
|
||||
|
||||
h('.row', [
|
||||
h('.cell.label', 'Amount'),
|
||||
h('.cell.value', formatBalance(txParams.value)),
|
||||
]),
|
||||
|
||||
h('.cell.row', [
|
||||
h('.cell.label', 'Max Transaction Fee'),
|
||||
h('.cell.value', formatBalance(gasCost)),
|
||||
]),
|
||||
|
||||
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(EtherBalance, {
|
||||
value: maxCost,
|
||||
inline: true,
|
||||
labelColor: 'black',
|
||||
fontSize: '16px',
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
|
||||
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
|
||||
|
||||
this.warnIfNeeded(),
|
||||
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
PTXP.miniAccountPanelForRecipient = function () {
|
||||
var props = this.props
|
||||
var txData = props.txData
|
||||
var txParams = txData.txParams || {}
|
||||
var isContractDeploy = !('to' in txParams)
|
||||
|
||||
// If it's not a contract deploy, send to the account
|
||||
if (!isContractDeploy) {
|
||||
return h(MiniAccountPanel, {
|
||||
imageSeed: txParams.to,
|
||||
imageifyIdenticons: props.imageifyIdenticons,
|
||||
picOrder: 'left',
|
||||
}, [
|
||||
h('span.font-small', {
|
||||
style: {
|
||||
fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
|
||||
},
|
||||
}, nameForAddress(txParams.to, props.identities)),
|
||||
h('span.font-small', {
|
||||
style: {
|
||||
fontFamily: 'Montserrat Light, Montserrat, sans-serif',
|
||||
},
|
||||
}, addressSummary(txParams.to, 6, 4, false)),
|
||||
])
|
||||
|
||||
} else {
|
||||
return h(MiniAccountPanel, {
|
||||
imageifyIdenticons: props.imageifyIdenticons,
|
||||
picOrder: 'left',
|
||||
}, [
|
||||
|
||||
h('span.font-small', {
|
||||
style: {
|
||||
fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
|
||||
},
|
||||
}, 'New Contract'),
|
||||
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
// Should analyze if there is a DELEGATECALL opcode
|
||||
// in the recipient contract, and show a warning if so.
|
||||
PTXP.warnIfNeeded = function () {
|
||||
const containsDelegateCall = !!this.props.txData.containsDelegateCall
|
||||
|
||||
if (!containsDelegateCall) {
|
||||
return null
|
||||
}
|
||||
|
||||
return h('span.error', {
|
||||
style: {
|
||||
fontFamily: 'Montserrat Light',
|
||||
fontSize: '13px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
}, [
|
||||
h('i.fa.fa-lg.fa-info-circle', { style: { margin: '5px' } }),
|
||||
h('span', ' Your identity may be used in other contracts!'),
|
||||
])
|
||||
}
|
||||
|
|
|
@ -21,29 +21,35 @@ PendingTx.prototype.render = function () {
|
|||
key: txData.id,
|
||||
}, [
|
||||
|
||||
// header
|
||||
h('h3', {
|
||||
style: {
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center',
|
||||
},
|
||||
}, 'Submit Transaction'),
|
||||
|
||||
// tx info
|
||||
h(PendingTxDetails, state),
|
||||
|
||||
h('style', `
|
||||
.conf-buttons button {
|
||||
margin-left: 10px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
`),
|
||||
|
||||
// send + cancel
|
||||
h('.flex-row.flex-space-around', [
|
||||
h('button', {
|
||||
onClick: state.cancelTransaction,
|
||||
}, 'Reject'),
|
||||
h('button', {
|
||||
h('.flex-row.flex-space-around.conf-buttons', {
|
||||
style: {
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
margin: '14px 25px',
|
||||
},
|
||||
}, [
|
||||
h('button.confirm', {
|
||||
onClick: state.sendTransaction,
|
||||
}, 'Approve'),
|
||||
style: { background: 'rgb(251,117,1)' },
|
||||
}, 'Accept'),
|
||||
|
||||
h('button.cancel', {
|
||||
onClick: state.cancelTransaction,
|
||||
style: { background: 'rgb(254,35,17)' },
|
||||
}, 'Reject'),
|
||||
]),
|
||||
|
||||
])
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -39,14 +39,14 @@ ConfirmTxScreen.prototype.render = function () {
|
|||
|
||||
return (
|
||||
|
||||
h('.unconftx-section.flex-column.flex-grow', [
|
||||
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: this.goHome.bind(this),
|
||||
}),
|
||||
h('h2.page-subtitle', 'Confirmation'),
|
||||
h('h2.page-subtitle', 'Confirm Transaction'),
|
||||
]),
|
||||
|
||||
h('h3', {
|
||||
|
|
|
@ -411,10 +411,6 @@ input.large-input {
|
|||
}
|
||||
/* tx confirm */
|
||||
|
||||
.unconftx-section {
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.unconftx-section input[type=password] {
|
||||
height: 22px;
|
||||
padding: 2px;
|
||||
|
|
|
@ -220,3 +220,9 @@ hr.horizontal-line {
|
|||
.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.one-line-concat {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ for (var currency in valueTable) {
|
|||
module.exports = {
|
||||
valuesFor: valuesFor,
|
||||
addressSummary: addressSummary,
|
||||
miniAddressSummary: miniAddressSummary,
|
||||
isAllOneCase: isAllOneCase,
|
||||
isValidAddress: isValidAddress,
|
||||
numericBalance: numericBalance,
|
||||
|
@ -44,10 +45,19 @@ function valuesFor (obj) {
|
|||
.map(function (key) { return obj[key] })
|
||||
}
|
||||
|
||||
function addressSummary (address) {
|
||||
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, 2 + 8) + '...' + checked.slice(-4) : '...'
|
||||
return checked ? checked.slice(0, 4) + '...' + checked.slice(-4) : '...'
|
||||
}
|
||||
|
||||
function isValidAddress (address) {
|
||||
|
@ -95,7 +105,8 @@ function parseBalance (balance) {
|
|||
return [beforeDecimal, afterDecimal]
|
||||
}
|
||||
|
||||
// Takes wei hex, returns "None" or "${formattedAmount} ETH"
|
||||
// Takes wei hex, returns an object with three properties.
|
||||
// Its "formatted" property is what we generally use to render values.
|
||||
function formatBalance (balance, decimalsToKeep) {
|
||||
var parsed = parseBalance(balance)
|
||||
var beforeDecimal = parsed[0]
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* CONTRACT NAMER
|
||||
*
|
||||
* Takes an address,
|
||||
* Returns a nicname if we have one stored,
|
||||
* otherwise returns null.
|
||||
*/
|
||||
|
||||
// Nickname keys must be stored in lower case.
|
||||
const nicknames = {}
|
||||
|
||||
module.exports = function(addr, identities = {}) {
|
||||
|
||||
const address = addr.toLowerCase()
|
||||
const ids = hashFromIdentities(identities)
|
||||
|
||||
console.dir({ addr, ids })
|
||||
return addrFromHash(address, ids) || addrFromHash(address, nicknames)
|
||||
}
|
||||
|
||||
function hashFromIdentities(identities) {
|
||||
const result = {}
|
||||
for (let key in identities) {
|
||||
result[key] = identities[key].name
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function addrFromHash(addr, hash) {
|
||||
const address = addr.toLowerCase()
|
||||
return hash[address] || null
|
||||
}
|
Loading…
Reference in New Issue