1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-22 17:33:23 +01:00

Add ability to add tokens to token list

Fiex #1616
This commit is contained in:
Dan Finlay 2017-06-15 16:22:53 -07:00
parent 711a4def86
commit 48789f2a3d
7 changed files with 78 additions and 21 deletions

View File

@ -3,6 +3,7 @@
## Current Master ## Current Master
- Add list of popular tokens held to the account detail view. - Add list of popular tokens held to the account detail view.
- Add ability to add Tokens to token list.
- Add a warning to JSON file import. - Add a warning to JSON file import.
## 3.7.8 2017-6-12 ## 3.7.8 2017-6-12

View File

@ -8,13 +8,11 @@ class PreferencesController {
const initState = extend({ const initState = extend({
frequentRpcList: [], frequentRpcList: [],
currentAccountTab: 'history', currentAccountTab: 'history',
tokens: [],
}, opts.initState) }, opts.initState)
this.store = new ObservableStore(initState) this.store = new ObservableStore(initState)
} }
//
// PUBLIC METHODS // PUBLIC METHODS
//
setSelectedAddress (_address) { setSelectedAddress (_address) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -28,6 +26,29 @@ class PreferencesController {
return this.store.getState().selectedAddress return this.store.getState().selectedAddress
} }
addToken (rawAddress, symbol, decimals) {
const address = normalizeAddress(rawAddress)
const newEntry = { address, symbol, decimals }
const tokens = this.store.getState().tokens
const previousIndex = tokens.find((token, index) => {
return token.address === address
})
if (previousIndex) {
tokens[previousIndex] = newEntry
} else {
tokens.push(newEntry)
}
this.store.updateState({ tokens })
return Promise.resolve()
}
getTokens () {
return this.store.getState().tokens
}
updateFrequentRpcList (_url) { updateFrequentRpcList (_url) {
return this.addToFrequentRpcList(_url) return this.addToFrequentRpcList(_url)
.then((rpcList) => { .then((rpcList) => {

View File

@ -275,6 +275,7 @@ module.exports = class MetamaskController extends EventEmitter {
// PreferencesController // PreferencesController
setSelectedAddress: nodeify(preferencesController.setSelectedAddress).bind(preferencesController), setSelectedAddress: nodeify(preferencesController.setSelectedAddress).bind(preferencesController),
addToken: nodeify(preferencesController.addToken).bind(preferencesController),
setCurrentAccountTab: nodeify(preferencesController.setCurrentAccountTab).bind(preferencesController), setCurrentAccountTab: nodeify(preferencesController.setCurrentAccountTab).bind(preferencesController),
setDefaultRpc: nodeify(this.setDefaultRpc).bind(this), setDefaultRpc: nodeify(this.setDefaultRpc).bind(this),
setCustomRpc: nodeify(this.setCustomRpc).bind(this), setCustomRpc: nodeify(this.setCustomRpc).bind(this),

View File

@ -35,6 +35,7 @@ function mapStateToProps (state) {
conversionRate: state.metamask.conversionRate, conversionRate: state.metamask.conversionRate,
currentCurrency: state.metamask.currentCurrency, currentCurrency: state.metamask.currentCurrency,
currentAccountTab: state.metamask.currentAccountTab, currentAccountTab: state.metamask.currentAccountTab,
tokens: state.metamask.tokens,
} }
} }
@ -273,13 +274,14 @@ AccountDetailScreen.prototype.tabSections = function () {
AccountDetailScreen.prototype.tabSwitchView = function () { AccountDetailScreen.prototype.tabSwitchView = function () {
const props = this.props const props = this.props
const { address, network } = props const { address, network } = props
const { currentAccountTab } = this.props const { currentAccountTab, tokens } = this.props
switch (currentAccountTab) { switch (currentAccountTab) {
case 'tokens': case 'tokens':
return h(TokenList, { return h(TokenList, {
userAddress: address, userAddress: address,
network, network,
tokens,
addToken: () => this.props.dispatch(actions.showAddTokenPage()), addToken: () => this.props.dispatch(actions.showAddTokenPage()),
}) })
default: default:

View File

@ -124,6 +124,7 @@ var actions = {
showConfigPage, showConfigPage,
SHOW_ADD_TOKEN_PAGE: 'SHOW_ADD_TOKEN_PAGE', SHOW_ADD_TOKEN_PAGE: 'SHOW_ADD_TOKEN_PAGE',
showAddTokenPage, showAddTokenPage,
addToken,
setRpcTarget: setRpcTarget, setRpcTarget: setRpcTarget,
setDefaultRpcTarget: setDefaultRpcTarget, setDefaultRpcTarget: setDefaultRpcTarget,
setProviderType: setProviderType, setProviderType: setProviderType,
@ -636,6 +637,19 @@ function showAddTokenPage (transitionForward = true) {
} }
} }
function addToken (address, symbol, decimals) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
background.addToken(address, symbol, decimals, (err) => {
dispatch(actions.hideLoadingIndication())
if (err) {
return dispatch(actions.displayWarning(err.message))
}
dispatch(actions.goHome())
})
}
}
function goBackToInitView () { function goBackToInitView () {
return { return {
type: actions.BACK_TO_INIT_MENU, type: actions.BACK_TO_INIT_MENU,

View File

@ -30,10 +30,8 @@ function AddTokenScreen () {
} }
AddTokenScreen.prototype.render = function () { AddTokenScreen.prototype.render = function () {
const props = this.props
const state = this.state const state = this.state
const { warning, address, symbol, decimals } = state const { warning, symbol, decimals } = state
return ( return (
h('.flex-column.flex-grow', [ h('.flex-column.flex-grow', [
@ -138,12 +136,12 @@ AddTokenScreen.prototype.render = function () {
style: { style: {
alignSelf: 'center', alignSelf: 'center',
}, },
onClick (event) { onClick: (event) => {
const valid = this.validateInputs() const valid = this.validateInputs()
if (!valid) return if (!valid) return
const { address, symbol, decimals } = state const { address, symbol, decimals } = this.state
this.props.dispatch(addToken(address.trim(), symbol.trim(), decimals)) this.props.dispatch(actions.addToken(address.trim(), symbol.trim(), decimals))
}, },
}, 'Add'), }, 'Add'),
]), ]),

View File

@ -4,13 +4,14 @@ const inherits = require('util').inherits
const TokenTracker = require('eth-token-tracker') const TokenTracker = require('eth-token-tracker')
const TokenCell = require('./token-cell.js') const TokenCell = require('./token-cell.js')
const contracts = require('eth-contract-metadata') const contracts = require('eth-contract-metadata')
const normalizeAddress = require('eth-sig-util').normalize
const tokens = [] const defaultTokens = []
for (const address in contracts) { for (const address in contracts) {
const contract = contracts[address] const contract = contracts[address]
if (contract.erc20) { if (contract.erc20) {
contract.address = address contract.address = address
tokens.push(contract) defaultTokens.push(contract)
} }
} }
@ -18,22 +19,23 @@ module.exports = TokenList
inherits(TokenList, Component) inherits(TokenList, Component)
function TokenList () { function TokenList () {
this.state = { tokens, isLoading: true, network: null } this.state = {
tokens: null,
isLoading: true,
network: null,
}
Component.call(this) Component.call(this)
} }
TokenList.prototype.render = function () { TokenList.prototype.render = function () {
const state = this.state const state = this.state
const { tokens, isLoading } = state const { isLoading, tokens } = state
const { userAddress, network } = this.props
const { userAddress } = this.props
if (isLoading) { if (isLoading) {
return this.message('Loading') return this.message('Loading')
} }
const network = this.props.network
const tokenViews = tokens.map((tokenData) => { const tokenViews = tokens.map((tokenData) => {
tokenData.network = network tokenData.network = network
tokenData.userAddress = userAddress tokenData.userAddress = userAddress
@ -120,7 +122,7 @@ TokenList.prototype.createFreshTokenTracker = function () {
this.tracker = new TokenTracker({ this.tracker = new TokenTracker({
userAddress, userAddress,
provider: global.ethereumProvider, provider: global.ethereumProvider,
tokens: tokens, tokens: uniqueMergeTokens(defaultTokens, this.props.tokens),
pollingInterval: 8000, pollingInterval: 8000,
}) })
@ -149,7 +151,12 @@ TokenList.prototype.componentWillUpdate = function (nextProps) {
} }
TokenList.prototype.updateBalances = function (tokenData) { TokenList.prototype.updateBalances = function (tokenData) {
const heldTokens = tokenData.filter(token => token.balance !== '0' && token.string !== '0.000') const desired = this.props.tokens.map(token => token.address)
const heldTokens = tokenData.filter(token => {
const held = token.balance !== '0' && token.string !== '0.000'
const preferred = desired.includes(normalizeAddress(token.address))
return held || preferred
})
this.setState({ tokens: heldTokens, isLoading: false }) this.setState({ tokens: heldTokens, isLoading: false })
} }
@ -158,3 +165,16 @@ TokenList.prototype.componentWillUnmount = function () {
this.tracker.stop() this.tracker.stop()
} }
function uniqueMergeTokens (tokensA, tokensB) {
const uniqueAddresses = []
const result = []
tokensA.concat(tokensB).forEach((token) => {
const normal = normalizeAddress(token.address)
if (!uniqueAddresses.includes(normal)) {
uniqueAddresses.push(normal)
result.push(token)
}
})
return result
}