aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkumavis <kumavis@users.noreply.github.com>2016-04-21 13:07:00 +0800
committerkumavis <kumavis@users.noreply.github.com>2016-04-21 13:07:00 +0800
commitdb85827b2be19d7bfc7dfaeec4786c4d051b6629 (patch)
tree39075d39ddcfbcb80016d61a22942451dbc745b9
parentf82a4de725e384ab4bb39c57f83a3dbb406c8db6 (diff)
parent532edf670e8c30db958765141974f3fb0f5ec44c (diff)
downloadtangerine-wallet-browser-db85827b2be19d7bfc7dfaeec4786c4d051b6629.tar.gz
tangerine-wallet-browser-db85827b2be19d7bfc7dfaeec4786c4d051b6629.tar.zst
tangerine-wallet-browser-db85827b2be19d7bfc7dfaeec4786c4d051b6629.zip
Merge pull request #125 from MetaMask/TransactionList
Add transaction history to account detail view
-rw-r--r--CHANGELOG.md2
-rw-r--r--app/scripts/lib/config-manager.js18
-rw-r--r--app/scripts/lib/idStore.js8
-rw-r--r--app/scripts/popup.js11
-rw-r--r--test/unit/config-manager-test.js10
-rw-r--r--test/unit/util_test.js68
-rw-r--r--ui/app/account-detail.js7
-rw-r--r--ui/app/components/transaction-list.js39
-rw-r--r--ui/app/send.js10
-rw-r--r--ui/app/util.js12
-rw-r--r--ui/index.js5
-rw-r--r--ui/lib/explorer-link.js12
12 files changed, 162 insertions, 40 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6a4e7fd3c..c2bcf006f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,7 +4,9 @@
- Pending transactions are now persisted to localStorage and resume even after browser is closed.
- Completed transactions are now persisted and can be displayed via UI.
+- Added transaction list to account detail view.
- Fix bug on config screen where current RPC address was always displayed wrong.
+- Fixed bug where entering a decimal value when sending a transaction would result in sending the wrong amount.
# 1.5.1 2016-04-15
diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js
index 356d53c22..c79dc7a8f 100644
--- a/app/scripts/lib/config-manager.js
+++ b/app/scripts/lib/config-manager.js
@@ -170,14 +170,26 @@ ConfigManager.prototype.rejectTx = function(txId) {
}
ConfigManager.prototype._setTxStatus = function(txId, status) {
+ var tx = this.getTx(txId)
+ tx.status = status
+ this.updateTx(tx)
+}
+
+ConfigManager.prototype.updateTx = function(tx) {
var transactions = this.getTxList()
- transactions.forEach((tx) => {
- if (tx.id === txId) {
- tx.status = status
+ var found, index
+ transactions.forEach((otherTx, i) => {
+ if (otherTx.id === tx.id) {
+ found = true
+ index = i
}
})
+ if (found) {
+ transactions[index] = tx
+ }
this._saveTxList(transactions)
}
+
ConfigManager.prototype.unconfirmedTxs = function() {
var transactions = this.getTxList()
return transactions.filter(tx => tx.status === 'unconfirmed')
diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js
index b451fd6d4..7763d33d8 100644
--- a/app/scripts/lib/idStore.js
+++ b/app/scripts/lib/idStore.js
@@ -135,6 +135,7 @@ IdentityStore.prototype.addUnconfirmedTransaction = function(txParams, cb){
// create txData obj with parameters and meta data
var time = (new Date()).getTime()
var txId = createId()
+ txParams.metamaskId = txId
var txData = {
id: txId,
txParams: txParams,
@@ -337,6 +338,13 @@ function IdManagement(opts) {
txParams.gasLimit = ethUtil.addHexPrefix(txParams.gasLimit || txParams.gas)
txParams.nonce = ethUtil.addHexPrefix(txParams.nonce)
var tx = new Transaction(txParams)
+
+ // Add the tx hash to the persisted meta-tx object
+ var hash = '0x' + tx.hash().toString('hex')
+ var metaTx = configManager.getTx(txParams.metamaskId)
+ metaTx.hash = hash
+ configManager.updateTx(metaTx)
+
var rawTx = '0x'+tx.serialize().toString('hex')
return '0x'+LightwalletSigner.signTx(this.keyStore, this.derivedKey, rawTx, txParams.from, this.hdPathString)
}
diff --git a/app/scripts/popup.js b/app/scripts/popup.js
index 85b3e30f9..6a39da661 100644
--- a/app/scripts/popup.js
+++ b/app/scripts/popup.js
@@ -17,7 +17,7 @@ injectCss(css)
async.parallel({
currentDomain: getCurrentDomain,
accountManager: connectToAccountManager,
-}, setupApp)
+}, getNetworkVersion)
function connectToAccountManager(cb){
// setup communication with background
@@ -65,6 +65,13 @@ function getCurrentDomain(cb){
})
}
+function getNetworkVersion(cb, results) {
+ web3.version.getNetwork(function(err, result) {
+ results.networkVersion = result
+ setupApp(err, results)
+ })
+}
+
function setupApp(err, opts){
if (err) {
alert(err.stack)
@@ -78,6 +85,6 @@ function setupApp(err, opts){
container: container,
accountManager: opts.accountManager,
currentDomain: opts.currentDomain,
+ networkVersion: opts.networkVersion,
})
-
}
diff --git a/test/unit/config-manager-test.js b/test/unit/config-manager-test.js
index 84632b0ea..e414ecb9e 100644
--- a/test/unit/config-manager-test.js
+++ b/test/unit/config-manager-test.js
@@ -126,6 +126,16 @@ describe('config-manager', function() {
})
})
+ describe('#updateTx', function() {
+ it('replaces the tx with the same id', function() {
+ configManager.addTx({ id: '1', status: 'unconfirmed' })
+ configManager.addTx({ id: '2', status: 'confirmed' })
+ configManager.updateTx({ id: '1', status: 'blah', hash: 'foo' })
+ var result = configManager.getTx('1')
+ assert.equal(result.hash, 'foo')
+ })
+ })
+
describe('#unconfirmedTxs', function() {
it('returns unconfirmed txs in a hash', function() {
configManager.addTx({ id: '1', status: 'unconfirmed' })
diff --git a/test/unit/util_test.js b/test/unit/util_test.js
index 7f8103d3b..3f46d4e9b 100644
--- a/test/unit/util_test.js
+++ b/test/unit/util_test.js
@@ -82,33 +82,47 @@ describe('util', function() {
})
- describe('#normalizeToWei', function() {
- it('should convert an eth to the appropriate equivalent values', function() {
- var valueTable = {
- wei: '1000000000000000000',
- kwei: '1000000000000000',
- mwei: '1000000000000',
- gwei: '1000000000',
- szabo: '1000000',
- finney:'1000',
- ether: '1',
- kether:'0.001',
- mether:'0.000001',
- // AUDIT: We're getting BN numbers on these ones.
- // I think they're big enough to ignore for now.
- // gether:'0.000000001',
- // tether:'0.000000000001',
- }
- var oneEthBn = new ethUtil.BN(ethInWei, 10)
-
- for(var currency in valueTable) {
-
- var value = new ethUtil.BN(valueTable[currency], 10)
- var output = util.normalizeToWei(value, currency)
- assert.equal(output.toString(10), valueTable.wei, `value of ${output.toString(10)} ${currency} should convert to ${oneEthBn}`)
-
- }
+ describe('normalizing values', function() {
+
+ describe('#normalizeToWei', function() {
+ it('should convert an eth to the appropriate equivalent values', function() {
+ var valueTable = {
+ wei: '1000000000000000000',
+ kwei: '1000000000000000',
+ mwei: '1000000000000',
+ gwei: '1000000000',
+ szabo: '1000000',
+ finney:'1000',
+ ether: '1',
+ // kether:'0.001',
+ // mether:'0.000001',
+ // AUDIT: We're getting BN numbers on these ones.
+ // I think they're big enough to ignore for now.
+ // gether:'0.000000001',
+ // tether:'0.000000000001',
+ }
+ var oneEthBn = new ethUtil.BN(ethInWei, 10)
+
+ for(var currency in valueTable) {
+
+ var value = new ethUtil.BN(valueTable[currency], 10)
+ var output = util.normalizeToWei(value, currency)
+ assert.equal(output.toString(10), valueTable.wei, `value of ${output.toString(10)} ${currency} should convert to ${oneEthBn}`)
+ }
+ })
})
- })
+ describe('#normalizeNumberToWei', function() {
+
+ it('should convert a kwei number to the appropriate equivalent wei', function() {
+ var result = util.normalizeNumberToWei(1.111, 'kwei')
+ assert.equal(result.toString(10), '1111', 'accepts decimals')
+ })
+
+ it('should convert a ether number to the appropriate equivalent wei', function() {
+ var result = util.normalizeNumberToWei(1.111, 'ether')
+ assert.equal(result.toString(10), '1111000000000000000', 'accepts decimals')
+ })
+ })
+ })
})
diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js
index 6ed23d482..025644efe 100644
--- a/ui/app/account-detail.js
+++ b/ui/app/account-detail.js
@@ -5,6 +5,7 @@ const connect = require('react-redux').connect
const copyToClipboard = require('copy-to-clipboard')
const actions = require('./actions')
const AccountPanel = require('./components/account-panel')
+const transactionList = require('./components/transaction-list')
module.exports = connect(mapStateToProps)(AccountDetailScreen)
@@ -15,6 +16,8 @@ function mapStateToProps(state) {
accounts: state.metamask.accounts,
address: state.appState.currentView.context,
accountDetail: accountDetail,
+ transactions: state.metamask.transactions,
+ networkVersion: state.networkVersion,
}
}
@@ -29,6 +32,7 @@ AccountDetailScreen.prototype.render = function() {
var identity = state.identities[state.address]
var account = state.accounts[state.address]
var accountDetail = state.accountDetail
+ var transactions = state.transactions
return (
@@ -71,6 +75,9 @@ AccountDetailScreen.prototype.render = function() {
]),
]),
+ transactionList(transactions
+ .filter(tx => tx.txParams.from === state.address)
+ .sort((a, b) => b.time - a.time), state.networkVersion),
this.exportedAccount(accountDetail),
// transaction table
diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js
new file mode 100644
index 000000000..99a325e35
--- /dev/null
+++ b/ui/app/components/transaction-list.js
@@ -0,0 +1,39 @@
+const h = require('react-hyperscript')
+const formatBalance = require('../util').formatBalance
+const addressSummary = require('../util').addressSummary
+const explorerLink = require('../../lib/explorer-link')
+
+module.exports = function(transactions, network) {
+ return h('details', [
+
+ h('summary', [
+ h('div.font-small', {style: {display: 'inline'}}, 'Transactions'),
+ ]),
+
+ h('.flex-row.flex-space-around', [
+ h('div.font-small','To'),
+ h('div.font-small','Amount'),
+ ]),
+
+ h('.tx-list', {
+ style: {
+ overflowY: 'auto',
+ height: '180px',
+ },
+ },
+
+ transactions.map((transaction) => {
+ return h('.tx.flex-row.flex-space-around', [
+ h('a.font-small',
+ {
+ href: explorerLink(transaction.hash, parseInt(network)),
+ target: '_blank',
+ },
+ addressSummary(transaction.txParams.to)),
+ h('div.font-small', formatBalance(transaction.txParams.value))
+ ])
+ })
+ )
+
+ ])
+}
diff --git a/ui/app/send.js b/ui/app/send.js
index 3cb56cb6e..d34accddc 100644
--- a/ui/app/send.js
+++ b/ui/app/send.js
@@ -96,7 +96,7 @@ SendTransactionScreen.prototype.render = function() {
}, 'Send')
]),
- state.warning ? h('span.error', state.warning) : null,
+ state.warning ? h('span.error', state.warning.split('.')[0]) : null,
])
)
}
@@ -108,11 +108,11 @@ SendTransactionScreen.prototype.back = function() {
SendTransactionScreen.prototype.onSubmit = function(event) {
var recipient = document.querySelector('input.address').value
- var amount = new ethUtil.BN(document.querySelector('input.ether').value, 10)
+
+ var inputAmount = parseFloat(document.querySelector('input.ether').value)
var currency = document.querySelector('select.currency').value
- var txData = document.querySelector('textarea.txData').value
+ var value = util.normalizeNumberToWei(inputAmount, currency)
- var value = util.normalizeToWei(amount, currency)
var balance = this.props.balance
if (value.gt(balance)) {
@@ -132,6 +132,8 @@ SendTransactionScreen.prototype.onSubmit = function(event) {
from: this.props.address,
value: '0x' + value.toString(16),
}
+
+ var txData = document.querySelector('textarea.txData').value
if (txData) txParams.data = txData
this.props.dispatch(actions.signTx(txParams))
diff --git a/ui/app/util.js b/ui/app/util.js
index 18862fade..5dbcffa7e 100644
--- a/ui/app/util.js
+++ b/ui/app/util.js
@@ -28,6 +28,7 @@ module.exports = {
ethToWei: ethToWei,
weiToEth: weiToEth,
normalizeToWei: normalizeToWei,
+ normalizeNumberToWei: normalizeNumberToWei,
valueTable: valueTable,
bnTable: bnTable,
}
@@ -85,13 +86,18 @@ function dataSize(data) {
// returns a BN in wei
function normalizeToWei(amount, currency) {
try {
- var ether = amount.div(bnTable[currency])
- var wei = ether.mul(bnTable.wei)
- return wei
+ return amount.mul(bnTable.wei).div(bnTable[currency])
} catch (e) {}
return amount
}
+var multiple = new ethUtil.BN('1000', 10)
+function normalizeNumberToWei(n, currency) {
+ var enlarged = n * 1000
+ 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()
diff --git a/ui/index.js b/ui/index.js
index 05d30d8d3..4ecce2fbe 100644
--- a/ui/index.js
+++ b/ui/index.js
@@ -32,7 +32,10 @@ function startApp(metamaskState, accountManager, opts){
// appState represents the current tab's popup state
appState: {
currentDomain: opts.currentDomain,
- }
+ },
+
+ // Which blockchain we are using:
+ networkVersion: opts.networkVersion,
})
// if unconfirmed txs, start on txConf page
diff --git a/ui/lib/explorer-link.js b/ui/lib/explorer-link.js
new file mode 100644
index 000000000..a2e7872f9
--- /dev/null
+++ b/ui/lib/explorer-link.js
@@ -0,0 +1,12 @@
+module.exports = function(hash, network) {
+ let prefix
+ switch (network) {
+ case 1: // main net
+ prefix = ''
+ case 2: // morden test net
+ prefix = 'testnet.'
+ default:
+ prefix = ''
+ }
+ return `http://${prefix}etherscan.io/tx/${hash}`
+}