RSK address checksum

This commit is contained in:
Victor Baranov 2019-06-12 23:58:58 +03:00
parent 2e36d0b44a
commit 45834b0d2a
15 changed files with 77 additions and 51 deletions

View File

@ -4,12 +4,11 @@ const Component = require('react').Component
const h = require('react-hyperscript') const h = require('react-hyperscript')
const connect = require('react-redux').connect const connect = require('react-redux').connect
const actions = require('../../ui/app/actions') const actions = require('../../ui/app/actions')
const { getCurrentKeyring, ifContractAcc, valuesFor } = require('./util') const { getCurrentKeyring, ifContractAcc, valuesFor, toChecksumAddress } = require('./util')
const Identicon = require('./components/identicon') const Identicon = require('./components/identicon')
const EthBalance = require('./components/eth-balance') const EthBalance = require('./components/eth-balance')
const TransactionList = require('./components/transaction-list') const TransactionList = require('./components/transaction-list')
const ExportAccountView = require('./components/account-export') const ExportAccountView = require('./components/account-export')
const ethUtil = require('ethereumjs-util')
const EditableLabel = require('./components/editable-label') const EditableLabel = require('./components/editable-label')
const TabBar = require('./components/tab-bar') const TabBar = require('./components/tab-bar')
const TokenList = require('./components/token-list') const TokenList = require('./components/token-list')
@ -50,11 +49,11 @@ function AccountDetailScreen () {
AccountDetailScreen.prototype.render = function () { AccountDetailScreen.prototype.render = function () {
var props = this.props var props = this.props
const { network, conversionRate, currentCurrency } = props
var selected = props.address || Object.keys(props.accounts)[0] var selected = props.address || Object.keys(props.accounts)[0]
var checksumAddress = selected && ethUtil.toChecksumAddress(selected) var checksumAddress = selected && toChecksumAddress(network, selected)
var identity = props.identities[selected] var identity = props.identities[selected]
var account = props.accounts[selected] var account = props.accounts[selected]
const { network, conversionRate, currentCurrency } = props
if (Object.keys(props.suggestedTokens).length > 0) { if (Object.keys(props.suggestedTokens).length > 0) {
this.props.dispatch(actions.showAddSuggestedTokenPage()) this.props.dispatch(actions.showAddSuggestedTokenPage())

View File

@ -6,7 +6,7 @@ const actions = require('../../ui/app/actions')
const Tooltip = require('./components/tooltip.js') const Tooltip = require('./components/tooltip.js')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const Copyable = require('./components/copy/copyable') const Copyable = require('./components/copy/copyable')
const addressSummary = require('./util').addressSummary const { addressSummary, toChecksumAddress } = require('./util')
module.exports = connect(mapStateToProps)(AddSuggestedTokenScreen) module.exports = connect(mapStateToProps)(AddSuggestedTokenScreen)
@ -30,6 +30,7 @@ AddSuggestedTokenScreen.prototype.render = function () {
const state = this.state const state = this.state
const props = this.props const props = this.props
const { warning } = state const { warning } = state
const { network } = props
const key = Object.keys(props.suggestedTokens)[0] const key = Object.keys(props.suggestedTokens)[0]
const { address, symbol, decimals } = props.suggestedTokens[key] const { address, symbol, decimals } = props.suggestedTokens[key]
@ -77,7 +78,7 @@ AddSuggestedTokenScreen.prototype.render = function () {
style: { display: 'flex' }, style: { display: 'flex' },
}, [ }, [
h(Copyable, { h(Copyable, {
value: ethUtil.toChecksumAddress(address), value: toChecksumAddress(network, address),
}, [ }, [
h('span#token-address', { h('span#token-address', {
style: { style: {
@ -87,7 +88,7 @@ AddSuggestedTokenScreen.prototype.render = function () {
margin: '8px', margin: '8px',
display: 'flex', display: 'flex',
}, },
}, addressSummary(address, 24, 4, false)), }, addressSummary(network, address, 24, 4, false)),
]), ]),
]), ]),

View File

@ -3,10 +3,9 @@ import PropTypes from 'prop-types'
import actions from '../../../../ui/app/actions' import actions from '../../../../ui/app/actions'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { Dropdown, DropdownMenuItem } from '../dropdown' import { Dropdown, DropdownMenuItem } from '../dropdown'
import ethUtil from 'ethereumjs-util'
import copyToClipboard from 'copy-to-clipboard' import copyToClipboard from 'copy-to-clipboard'
import ethNetProps from 'eth-net-props' import ethNetProps from 'eth-net-props'
import { getCurrentKeyring, ifContractAcc, ifHardwareAcc, getAllKeyRingsAccounts } from '../../util' import { getCurrentKeyring, ifContractAcc, ifHardwareAcc, getAllKeyRingsAccounts, toChecksumAddress } from '../../util'
import { importTypes } from '../../accounts/import/enums' import { importTypes } from '../../accounts/import/enums'
import { getFullABI } from '../../accounts/import/helpers' import { getFullABI } from '../../accounts/import/helpers'
import log from 'loglevel' import log from 'loglevel'
@ -217,8 +216,8 @@ class AccountDropdowns extends Component {
} }
copyAddress = () => { copyAddress = () => {
const { selected } = this.props const { selected, network } = this.props
const checkSumAddress = selected && ethUtil.toChecksumAddress(selected) const checkSumAddress = selected && toChecksumAddress(network, selected)
copyToClipboard(checkSumAddress) copyToClipboard(checkSumAddress)
} }

View File

@ -26,7 +26,7 @@ AccountPanel.prototype.render = function () {
attributes: [ attributes: [
{ {
key: 'Address', key: 'Address',
value: addressSummary(identity.address), value: addressSummary(state.network, identity.address),
}, },
balanceOrFaucetingIndication(account, isFauceting, state.network), balanceOrFaucetingIndication(account, isFauceting, state.network),
], ],

View File

@ -13,8 +13,7 @@ const MiniAccountPanel = require('./mini-account-panel')
const Copyable = require('./copy/copyable') const Copyable = require('./copy/copyable')
const EthBalance = require('./eth-balance') const EthBalance = require('./eth-balance')
const TokenBalance = require('./token-balance') const TokenBalance = require('./token-balance')
const addressSummary = util.addressSummary const { addressSummary, accountSummary, toChecksumAddress } = util
const accountSummary = util.accountSummary
const nameForAddress = require('../../lib/contract-namer') const nameForAddress = require('../../lib/contract-namer')
const BNInput = require('./bn-as-decimal-input') const BNInput = require('./bn-as-decimal-input')
const { getEnvironmentType } = require('../../../app/scripts/lib/util') const { getEnvironmentType } = require('../../../app/scripts/lib/util')
@ -240,14 +239,14 @@ PendingTx.prototype.render = function () {
}, accountSummary(identity.name, 6, 4)), }, accountSummary(identity.name, 6, 4)),
h(Copyable, { h(Copyable, {
value: ethUtil.toChecksumAddress(address), value: toChecksumAddress(network, address),
}, [ }, [
h('span.font-small', { h('span.font-small', {
style: { style: {
fontFamily: 'Nunito Regular', fontFamily: 'Nunito Regular',
color: 'rgba(255, 255, 255, 0.7)', color: 'rgba(255, 255, 255, 0.7)',
}, },
}, addressSummary(address, 6, 4, false)), }, addressSummary(network, address, 6, 4, false)),
]), ]),
h('span.font-small', { h('span.font-small', {
@ -565,17 +564,17 @@ PendingTx.prototype.miniAccountPanelForRecipient = function (isToken, tokensTran
display: 'inline-block', display: 'inline-block',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
}, },
}, accountSummary(nameForAddress(to, props.identities)), 6, 4), }, accountSummary(nameForAddress(to, props.identities, props.network)), 6, 4),
h(Copyable, { h(Copyable, {
value: ethUtil.toChecksumAddress(to), value: toChecksumAddress(props.network, to),
}, [ }, [
h('span.font-small', { h('span.font-small', {
style: { style: {
fontFamily: 'Nunito Regular', fontFamily: 'Nunito Regular',
color: 'rgba(255, 255, 255, 0.7)', color: 'rgba(255, 255, 255, 0.7)',
}, },
}, addressSummary(to, 6, 4, false)), }, addressSummary(props.network, to, 6, 4, false)),
]), ]),
]), ]),
]) ])

View File

@ -16,12 +16,14 @@ class ExecutorCell extends Component {
address: PropTypes.string, address: PropTypes.string,
identity: PropTypes.object, identity: PropTypes.object,
onClick: PropTypes.func, onClick: PropTypes.func,
network: PropTypes.string,
} }
render () { render () {
const { const {
address, address,
identity, identity,
network,
} = this.props } = this.props
const { isSelected } = this.state const { isSelected } = this.state
@ -70,7 +72,7 @@ class ExecutorCell extends Component {
style={{ color: 'rgba(255, 255, 255, 0.7)' }} style={{ color: 'rgba(255, 255, 255, 0.7)' }}
> >
<div style={{ lineHeight: '16px', fontSize: '14px' }}> <div style={{ lineHeight: '16px', fontSize: '14px' }}>
{addressSummary(address)} {addressSummary(network, address)}
</div> </div>
</div> </div>
</div> </div>

View File

@ -59,7 +59,7 @@ class SendProfile extends Component {
}} }}
> >
<div className="send-profile-address" style={{ lineHeight: '16px', fontSize: '14px' }}> <div className="send-profile-address" style={{ lineHeight: '16px', fontSize: '14px' }}>
{addressSummary(address)} {addressSummary(network, address)}
</div> </div>
</div> </div>
{/* balance */} {/* balance */}

View File

@ -152,7 +152,7 @@ ShiftListItem.prototype.renderInfo = function () {
}, [ }, [
`${props.depositType} to ETH via ShapeShift`, `${props.depositType} to ETH via ShapeShift`,
h(CopyButton, { h(CopyButton, {
value: this.props.depositAddress, value: props.depositAddress,
})]), })]),
h('div', { h('div', {
style: { style: {
@ -219,7 +219,7 @@ ShiftListItem.prototype.renderInfo = function () {
display: 'inline-flex', display: 'inline-flex',
}, },
}, [ }, [
addressSummary(props.response.transaction), addressSummary(props.network, props.response.transaction),
h(CopyButton, { h(CopyButton, {
value: this.props.response.transaction, value: this.props.response.transaction,
}), }),

View File

@ -5,12 +5,11 @@ const Identicon = require('./identicon')
const ethNetProps = require('eth-net-props') const ethNetProps = require('eth-net-props')
const Dropdown = require('./dropdown').Dropdown const Dropdown = require('./dropdown').Dropdown
const DropdownMenuItem = require('./dropdown').DropdownMenuItem const DropdownMenuItem = require('./dropdown').DropdownMenuItem
const ethUtil = require('ethereumjs-util')
const copyToClipboard = require('copy-to-clipboard') const copyToClipboard = require('copy-to-clipboard')
const actions = require('../../../ui/app/actions') const actions = require('../../../ui/app/actions')
const connect = require('react-redux').connect const connect = require('react-redux').connect
const { MAINNET_CODE } = require('../../../app/scripts/controllers/network/enums') const { MAINNET_CODE } = require('../../../app/scripts/controllers/network/enums')
import { countSignificantDecimals } from '../util' import { countSignificantDecimals, toChecksumAddress } from '../util'
const tokenCellDropDownPrefix = 'token-cell_dropdown_' const tokenCellDropDownPrefix = 'token-cell_dropdown_'
@ -132,7 +131,7 @@ TokenCell.prototype.renderTokenOptions = function (menuToTop, ind) {
{ {
closeMenu: () => {}, closeMenu: () => {},
onClick: () => { onClick: () => {
const checkSumAddress = address && ethUtil.toChecksumAddress(address) const checkSumAddress = address && toChecksumAddress(network, address)
copyToClipboard(checkSumAddress) copyToClipboard(checkSumAddress)
}, },
}, },

View File

@ -14,6 +14,7 @@ const ethNetProps = require('eth-net-props')
const TransactionIcon = require('./transaction-list-item-icon') const TransactionIcon = require('./transaction-list-item-icon')
const ShiftListItem = require('./shift-list-item') const ShiftListItem = require('./shift-list-item')
const { ifRSK } = require('../util')
const { POA_CODE, const { POA_CODE,
DAI_CODE, DAI_CODE,
@ -25,7 +26,6 @@ const { POA_CODE,
GOERLI_TESTNET_CODE, GOERLI_TESTNET_CODE,
CLASSIC_CODE, CLASSIC_CODE,
RSK_CODE, RSK_CODE,
RSK_TESTNET_CODE,
} = require('../../../app/scripts/controllers/network/enums') } = require('../../../app/scripts/controllers/network/enums')
const mapDispatchToProps = dispatch => { const mapDispatchToProps = dispatch => {
@ -165,7 +165,7 @@ TransactionListItem.prototype.render = function () {
}, [ }, [
domainField(txParams), domainField(txParams),
h('div.flex-row', [ h('div.flex-row', [
recipientField(txParams, transaction, isTx, isMsg, numericNet), recipientField(txParams, transaction, isTx, isMsg, network),
]), ]),
h('div', { h('div', {
style: { style: {
@ -240,13 +240,13 @@ function domainField (txParams) {
]) ])
} }
function recipientField (txParams, transaction, isTx, isMsg, numericNet) { function recipientField (txParams, transaction, isTx, isMsg, network) {
let message let message
if (isMsg) { if (isMsg) {
message = 'Signature Requested' message = 'Signature Requested'
} else if (txParams.to) { } else if (txParams.to) {
message = addressSummary(txParams.to) message = addressSummary(network, txParams.to)
} else { } else {
message = 'Contract Deployment' message = 'Contract Deployment'
} }
@ -260,7 +260,7 @@ function recipientField (txParams, transaction, isTx, isMsg, numericNet) {
h('span', (!txParams.to ? {style: {whiteSpace: 'nowrap'}} : null), message), h('span', (!txParams.to ? {style: {whiteSpace: 'nowrap'}} : null), message),
// Places a copy button if tx is successful, else places a placeholder empty div. // Places a copy button if tx is successful, else places a placeholder empty div.
transaction.hash ? h(CopyButton, { value: transaction.hash, display: 'inline' }) : h('div', {style: { display: 'flex', alignItems: 'center', width: '26px' }}), transaction.hash ? h(CopyButton, { value: transaction.hash, display: 'inline' }) : h('div', {style: { display: 'flex', alignItems: 'center', width: '26px' }}),
renderErrorOrWarning(transaction, numericNet), renderErrorOrWarning(transaction, network),
]) ])
} }
@ -268,7 +268,7 @@ function formatDate (date) {
return vreme.format(new Date(date), 'March 16 2014 14:30') return vreme.format(new Date(date), 'March 16 2014 14:30')
} }
function renderErrorOrWarning (transaction, numericNet) { function renderErrorOrWarning (transaction, network) {
const { status, err, warning } = transaction const { status, err, warning } = transaction
// show dropped // show dropped
@ -295,7 +295,7 @@ function renderErrorOrWarning (transaction, numericNet) {
} }
// show warning // show warning
const isRSK = numericNet === RSK_CODE || numericNet === RSK_TESTNET_CODE const isRSK = ifRSK(network)
if (warning && !isRSK || (isRSK && !warning.error.includes('[ethjs-rpc] rpc error with payload'))) { if (warning && !isRSK || (isRSK && !warning.error.includes('[ethjs-rpc] rpc error with payload'))) {
const message = warning.message const message = warning.message
return h(Tooltip, { return h(Tooltip, {

View File

@ -1,5 +1,9 @@
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const ethNetProps = require('eth-net-props') const ethNetProps = require('eth-net-props')
const {
RSK_CODE,
RSK_TESTNET_CODE,
} = require('../../app/scripts/controllers/network/enums')
var valueTable = { var valueTable = {
wei: '1000000000000000000', wei: '1000000000000000000',
@ -23,7 +27,6 @@ module.exports = {
valuesFor: valuesFor, valuesFor: valuesFor,
addressSummary: addressSummary, addressSummary: addressSummary,
accountSummary: accountSummary, accountSummary: accountSummary,
miniAddressSummary: miniAddressSummary,
isAllOneCase: isAllOneCase, isAllOneCase: isAllOneCase,
isValidAddress: isValidAddress, isValidAddress: isValidAddress,
isValidENSAddress, isValidENSAddress,
@ -47,6 +50,8 @@ module.exports = {
ifContractAcc, ifContractAcc,
ifHardwareAcc, ifHardwareAcc,
getAllKeyRingsAccounts, getAllKeyRingsAccounts,
ifRSK,
toChecksumAddress,
} }
function valuesFor (obj) { function valuesFor (obj) {
@ -55,9 +60,9 @@ function valuesFor (obj) {
.map(function (key) { return obj[key] }) .map(function (key) { return obj[key] })
} }
function addressSummary (address, firstSegLength = 10, lastSegLength = 4, includeHex = true) { function addressSummary (network, address, firstSegLength = 10, lastSegLength = 4, includeHex = true) {
if (!address) return '' if (!address) return ''
let checked = ethUtil.toChecksumAddress(address) let checked = toChecksumAddress(network, address)
if (!includeHex) { if (!includeHex) {
checked = ethUtil.stripHexPrefix(checked) checked = ethUtil.stripHexPrefix(checked)
} }
@ -72,12 +77,6 @@ function accountSummary (acc, firstSegLength = 6, lastSegLength = 4) {
return acc.slice(0, firstSegLength) + '...' + acc.slice(posOfLastPart) return acc.slice(0, firstSegLength) + '...' + acc.slice(posOfLastPart)
} }
function miniAddressSummary (address) {
if (!address) return ''
var checked = ethUtil.toChecksumAddress(address)
return checked ? checked.slice(0, 4) + '...' + checked.slice(-4) : '...'
}
function isValidAddress (address) { function isValidAddress (address) {
var prefixed = ethUtil.addHexPrefix(address) var prefixed = ethUtil.addHexPrefix(address)
if (address === '0x0000000000000000000000000000000000000000') return false if (address === '0x0000000000000000000000000000000000000000') return false
@ -375,3 +374,31 @@ function getAllKeyRingsAccounts (keyrings, network) {
}, []) }, [])
return accountOrder return accountOrder
} }
function toChecksumAddressRSK (address, chainId = null) {
const stripAddress = ethUtil.stripHexPrefix(address).toLowerCase()
const prefix = chainId != null ? (chainId.toString() + '0x') : ''
const keccakHash = ethUtil.sha3(prefix + stripAddress).toString('hex')
let output = '0x'
for (let i = 0; i < stripAddress.length; i++) {
output += parseInt(keccakHash[i], 16) >= 8 ?
stripAddress[i].toUpperCase() :
stripAddress[i]
}
return output
}
function toChecksumAddress (network, address, chainId = null) {
if (ifRSK(network)) {
return toChecksumAddressRSK(address, parseInt(network))
} else {
return ethUtil.toChecksumAddress(address, chainId)
}
}
function ifRSK (network) {
const numericNet = isNaN(network) ? network : parseInt(network)
return numericNet === RSK_CODE || numericNet === RSK_TESTNET_CODE
}

View File

@ -6,10 +6,10 @@
*/ */
const contractMap = require('eth-contract-metadata') const contractMap = require('eth-contract-metadata')
const ethUtil = require('ethereumjs-util') const { toChecksumAddress } = require('../app/util')
module.exports = function (addr, identities = {}) { module.exports = function (addr, identities = {}, network) {
const checksummed = ethUtil.toChecksumAddress(addr) const checksummed = toChecksumAddress(network, addr)
if (contractMap[checksummed] && contractMap[checksummed].name) { if (contractMap[checksummed] && contractMap[checksummed].name) {
return contractMap[checksummed].name return contractMap[checksummed].name
} }

View File

@ -1,9 +1,9 @@
var iconFactory var iconFactory
const isValidAddress = require('ethereumjs-util').isValidAddress const isValidAddress = require('ethereumjs-util').isValidAddress
const toChecksumAddress = require('ethereumjs-util').toChecksumAddress
const contractMapETH = require('eth-contract-metadata') const contractMapETH = require('eth-contract-metadata')
const contractMapPOA = require('poa-contract-metadata') const contractMapPOA = require('poa-contract-metadata')
const colors = require('../../colors') const colors = require('../../colors')
const { toChecksumAddress } = require('../app/util')
module.exports = function (rockicon) { module.exports = function (rockicon) {
if (!iconFactory) { if (!iconFactory) {
@ -20,7 +20,7 @@ function IconFactory (rockicon) {
IconFactory.prototype.iconForAddress = function (address, diameter, network) { IconFactory.prototype.iconForAddress = function (address, diameter, network) {
const networkID = parseInt(network) const networkID = parseInt(network)
const addr = toChecksumAddress(address) const addr = toChecksumAddress(network, address)
if (iconExistsFor(addr, networkID)) { if (iconExistsFor(addr, networkID)) {
return imageElFor(addr, networkID) return imageElFor(addr, networkID)
} }

View File

@ -4,14 +4,14 @@ module.exports = function (lostAccounts) {
return { return {
date: new Date().toDateString(), date: new Date().toDateString(),
title: 'Account Problem Caught', title: 'Account Problem Caught',
body: `MetaMask has fixed a bug where some accounts were previously mis-generated. This was a rare issue, but you were affected! body: `NiftyWallet has fixed a bug where some accounts were previously mis-generated. This was a rare issue, but you were affected!
We have successfully imported the accounts that were mis-generated, but they will no longer be recovered with your normal seed phrase. We have successfully imported the accounts that were mis-generated, but they will no longer be recovered with your normal seed phrase.
We have marked the affected accounts as "Loose", and recommend you transfer ether and tokens away from those accounts, or export & back them up elsewhere. We have marked the affected accounts as "Loose", and recommend you transfer ether and tokens away from those accounts, or export & back them up elsewhere.
Your affected accounts are: Your affected accounts are:
${lostAccounts.map(acct => ` - ${summary(acct)}`).join('\n')} ${lostAccounts.map(acct => ` - ${summary(null, acct)}`).join('\n')}
These accounts have been marked as "Loose" so they will be easy to recognize in the account list. These accounts have been marked as "Loose" so they will be easy to recognize in the account list.

View File

@ -90,13 +90,13 @@ describe('ifContractAcc(keyring) function', () => {
describe('#addressSummary', function () { describe('#addressSummary', function () {
it('should add case-sensitive checksum', function () { it('should add case-sensitive checksum', function () {
const address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825' const address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825'
const result = addressSummary(address) const result = addressSummary(1, address)
assert.equal(result, '0xFDEa65C8...b825') assert.equal(result, '0xFDEa65C8...b825')
}) })
it('should accept arguments for firstseg, lastseg, and keepPrefix', function () { it('should accept arguments for firstseg, lastseg, and keepPrefix', function () {
const address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825' const address = '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825'
const result = addressSummary(address, 4, 4, false) const result = addressSummary(1, address, 4, 4, false)
assert.equal(result, 'FDEa...b825') assert.equal(result, 'FDEa...b825')
}) })
}) })