commit
e85418b11a
@ -1 +1,2 @@ |
||||
app/scripts/lib/extension-instance.js |
||||
ui/app/conversion-util.js |
||||
|
@ -0,0 +1,10 @@ |
||||
{ |
||||
"appName": { |
||||
"message": "MetaMask", |
||||
"description": "The name of the application" |
||||
}, |
||||
"appDescription": { |
||||
"message": "Administración de identidad en Ethereum", |
||||
"description": "The description of the application" |
||||
} |
||||
} |
@ -0,0 +1,10 @@ |
||||
{ |
||||
"appName": { |
||||
"message": "MetaMask", |
||||
"description": "The name of the application" |
||||
}, |
||||
"appDescription": { |
||||
"message": "Administración de identidad en Ethereum", |
||||
"description": "The description of the application" |
||||
} |
||||
} |
@ -0,0 +1,10 @@ |
||||
{ |
||||
"appName": { |
||||
"message": "MetaMask", |
||||
"description": "The name of the application" |
||||
}, |
||||
"appDescription": { |
||||
"message": "以太坊身份管理", |
||||
"description": "The description of the application" |
||||
} |
||||
} |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 41 KiB |
@ -0,0 +1,16 @@ |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<title>MetaMask Notification</title> |
||||
<style> |
||||
body { |
||||
overflow: hidden; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
<div id="app-content"></div> |
||||
<script src="./scripts/popup.js" type="text/javascript" charset="utf-8"></script> |
||||
</body> |
||||
</html> |
@ -1,24 +0,0 @@ |
||||
module.exports = ensnare |
||||
|
||||
// creates a proxy object that calls cb everytime the obj's properties/fns are accessed
|
||||
function ensnare (obj, cb) { |
||||
var proxy = {} |
||||
Object.keys(obj).forEach(function (key) { |
||||
var val = obj[key] |
||||
switch (typeof val) { |
||||
case 'function': |
||||
proxy[key] = function () { |
||||
cb() |
||||
val.apply(obj, arguments) |
||||
} |
||||
return |
||||
default: |
||||
Object.defineProperty(proxy, key, { |
||||
get: function () { cb(); return obj[key] }, |
||||
set: function (val) { cb(); obj[key] = val; return val }, |
||||
}) |
||||
return |
||||
} |
||||
}) |
||||
return proxy |
||||
} |
@ -0,0 +1,8 @@ |
||||
module.exports = function isPopupOrNotification() { |
||||
const url = window.location.href |
||||
if (url.match(/popup.html$/)) { |
||||
return 'popup' |
||||
} else { |
||||
return 'notification' |
||||
} |
||||
} |
@ -1,56 +0,0 @@ |
||||
const Duplex = require('readable-stream').Duplex |
||||
const inherits = require('util').inherits |
||||
|
||||
module.exports = LocalMessageDuplexStream |
||||
|
||||
inherits(LocalMessageDuplexStream, Duplex) |
||||
|
||||
function LocalMessageDuplexStream (opts) { |
||||
Duplex.call(this, { |
||||
objectMode: true, |
||||
}) |
||||
|
||||
// this._origin = opts.origin
|
||||
this._name = opts.name |
||||
this._target = opts.target |
||||
|
||||
// console.log('LocalMessageDuplexStream ('+this._name+') - initialized...')
|
||||
window.addEventListener('message', this._onMessage.bind(this), false) |
||||
} |
||||
|
||||
// private
|
||||
|
||||
LocalMessageDuplexStream.prototype._onMessage = function (event) { |
||||
var msg = event.data |
||||
// console.log('LocalMessageDuplexStream ('+this._name+') - heard message...', event)
|
||||
// validate message
|
||||
if (event.origin !== location.origin) return // console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (event.origin !== location.origin) ')
|
||||
if (typeof msg !== 'object') return // console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (typeof msg !== "object") ')
|
||||
if (msg.target !== this._name) return // console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (msg.target !== this._name) ', msg.target, this._name)
|
||||
if (!msg.data) return // console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (!msg.data) ')
|
||||
// console.log('LocalMessageDuplexStream ('+this._name+') - accepted', msg.data)
|
||||
// forward message
|
||||
try { |
||||
this.push(msg.data) |
||||
} catch (err) { |
||||
this.emit('error', err) |
||||
} |
||||
} |
||||
|
||||
// stream plumbing
|
||||
|
||||
LocalMessageDuplexStream.prototype._read = noop |
||||
|
||||
LocalMessageDuplexStream.prototype._write = function (data, encoding, cb) { |
||||
// console.log('LocalMessageDuplexStream ('+this._name+') - sending message...')
|
||||
var message = { |
||||
target: this._target, |
||||
data: data, |
||||
} |
||||
window.postMessage(message, location.origin) |
||||
cb() |
||||
} |
||||
|
||||
// util
|
||||
|
||||
function noop () {} |
@ -1,159 +1,48 @@ |
||||
const createId = require('hat') |
||||
const extend = require('xtend') |
||||
const unmountComponentAtNode = require('react-dom').unmountComponentAtNode |
||||
const findDOMNode = require('react-dom').findDOMNode |
||||
const render = require('react-dom').render |
||||
const h = require('react-hyperscript') |
||||
const PendingTxDetails = require('../../../ui/app/components/pending-tx-details') |
||||
const PendingMsgDetails = require('../../../ui/app/components/pending-msg-details') |
||||
const MetaMaskUiCss = require('../../../ui/css') |
||||
const extension = require('./extension') |
||||
var notificationHandlers = {} |
||||
|
||||
const notifications = { |
||||
createUnlockRequestNotification: createUnlockRequestNotification, |
||||
createTxNotification: createTxNotification, |
||||
createMsgNotification: createMsgNotification, |
||||
show, |
||||
getPopup, |
||||
closePopup, |
||||
} |
||||
module.exports = notifications |
||||
window.METAMASK_NOTIFIER = notifications |
||||
|
||||
setupListeners() |
||||
|
||||
function setupListeners () { |
||||
// guard for extension bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!extension.notifications) return console.error('Chrome notifications API missing...') |
||||
|
||||
// notification button press
|
||||
extension.notifications.onButtonClicked.addListener(function (notificationId, buttonIndex) { |
||||
var handlers = notificationHandlers[notificationId] |
||||
if (buttonIndex === 0) { |
||||
handlers.confirm() |
||||
} else { |
||||
handlers.cancel() |
||||
function show () { |
||||
getPopup((popup) => { |
||||
if (popup) { |
||||
return extension.windows.update(popup.id, { focused: true }) |
||||
} |
||||
extension.notifications.clear(notificationId) |
||||
}) |
||||
|
||||
// notification teardown
|
||||
extension.notifications.onClosed.addListener(function (notificationId) { |
||||
delete notificationHandlers[notificationId] |
||||
}) |
||||
} |
||||
|
||||
// creation helper
|
||||
function createUnlockRequestNotification (opts) { |
||||
// guard for extension bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!extension.notifications) return console.error('Chrome notifications API missing...') |
||||
var message = 'An Ethereum app has requested a signature. Please unlock your account.' |
||||
|
||||
var id = createId() |
||||
extension.notifications.create(id, { |
||||
type: 'basic', |
||||
iconUrl: '/images/icon-128.png', |
||||
title: opts.title, |
||||
message: message, |
||||
}) |
||||
} |
||||
|
||||
function createTxNotification (state) { |
||||
// guard for extension bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!extension.notifications) return console.error('Chrome notifications API missing...') |
||||
|
||||
renderTxNotificationSVG(state, function (err, notificationSvgSource) { |
||||
if (err) throw err |
||||
|
||||
showNotification(extend(state, { |
||||
title: 'New Unsigned Transaction', |
||||
imageUrl: toSvgUri(notificationSvgSource), |
||||
})) |
||||
}) |
||||
} |
||||
|
||||
function createMsgNotification (state) { |
||||
// guard for extension bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!extension.notifications) return console.error('Chrome notifications API missing...') |
||||
|
||||
renderMsgNotificationSVG(state, function (err, notificationSvgSource) { |
||||
if (err) throw err |
||||
|
||||
showNotification(extend(state, { |
||||
title: 'New Unsigned Message', |
||||
imageUrl: toSvgUri(notificationSvgSource), |
||||
})) |
||||
extension.windows.create({ |
||||
url: 'notification.html', |
||||
type: 'detached_panel', |
||||
focused: true, |
||||
width: 360, |
||||
height: 500, |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
function showNotification (state) { |
||||
// guard for extension bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!extension.notifications) return console.error('Chrome notifications API missing...') |
||||
function getPopup(cb) { |
||||
|
||||
var id = createId() |
||||
extension.notifications.create(id, { |
||||
type: 'image', |
||||
requireInteraction: true, |
||||
iconUrl: '/images/icon-128.png', |
||||
imageUrl: state.imageUrl, |
||||
title: state.title, |
||||
message: '', |
||||
buttons: [{ |
||||
title: 'Approve', |
||||
}, { |
||||
title: 'Reject', |
||||
}], |
||||
}) |
||||
notificationHandlers[id] = { |
||||
confirm: state.onConfirm, |
||||
cancel: state.onCancel, |
||||
// Ignore in test environment
|
||||
if (!extension.windows) { |
||||
return cb(null) |
||||
} |
||||
} |
||||
|
||||
function renderTxNotificationSVG (state, cb) { |
||||
var content = h(PendingTxDetails, state) |
||||
renderNotificationSVG(content, cb) |
||||
} |
||||
extension.windows.getAll({}, (windows) => { |
||||
let popup = windows.find((win) => { |
||||
return win.type === 'popup' |
||||
}) |
||||
|
||||
function renderMsgNotificationSVG (state, cb) { |
||||
var content = h(PendingMsgDetails, state) |
||||
renderNotificationSVG(content, cb) |
||||
} |
||||
|
||||
function renderNotificationSVG (content, cb) { |
||||
var container = document.createElement('div') |
||||
var confirmView = h('div.app-primary', { |
||||
style: { |
||||
width: '360px', |
||||
height: '240px', |
||||
padding: '16px', |
||||
// background: '#F7F7F7',
|
||||
background: 'white', |
||||
}, |
||||
}, [ |
||||
h('style', MetaMaskUiCss()), |
||||
content, |
||||
]) |
||||
|
||||
render(confirmView, container, function ready() { |
||||
var rootElement = findDOMNode(this) |
||||
var viewSource = rootElement.outerHTML |
||||
unmountComponentAtNode(container) |
||||
var svgSource = svgWrapper(viewSource) |
||||
// insert content into svg wrapper
|
||||
cb(null, svgSource) |
||||
cb(popup) |
||||
}) |
||||
} |
||||
|
||||
function svgWrapper (content) { |
||||
var wrapperSource = ` |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="240"> |
||||
<foreignObject x="0" y="0" width="100%" height="100%"> |
||||
<body xmlns="http://www.w3.org/1999/xhtml" height="100%">{{content}}</body> |
||||
</foreignObject> |
||||
</svg> |
||||
` |
||||
return wrapperSource.split('{{content}}').join(content) |
||||
} |
||||
|
||||
function toSvgUri (content) { |
||||
return 'data:image/svg+xml;utf8,' + encodeURIComponent(content) |
||||
function closePopup() { |
||||
getPopup((popup) => { |
||||
if (!popup) return |
||||
extension.windows.remove(popup.id, console.error) |
||||
}) |
||||
} |
||||
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,163 @@ |
||||
{ |
||||
"metamask": { |
||||
"currentFiat": "USD", |
||||
"conversionRate": 11.06608791, |
||||
"conversionDate": 1470421024, |
||||
"isInitialized": true, |
||||
"isUnlocked": true, |
||||
"currentDomain": "example.com", |
||||
"rpcTarget": "https://rawtestrpc.metamask.io/", |
||||
"shapeShiftTxList":[ |
||||
{ |
||||
"depositAddress": "1L8BJCR6KHkCiVceDqibt7zJscqPpH7pFw", |
||||
"depositType": "BTC", |
||||
"key": "shapeshift", |
||||
"time": 1471564825772, |
||||
"response": { |
||||
"status": "complete", |
||||
"outgoingCoin": "100.00", |
||||
"incomingCoin": "1.000", |
||||
"transaction": "0x3701e0ac344a12a1fc5417cf251109a7c41f3edab922310202630d9c012414c8" |
||||
} |
||||
}, |
||||
{ |
||||
"depositAddress": "1L8BJCR6KHkCiVceDqibt7zJscqPpH7pFw", |
||||
"depositType": "BTC", |
||||
"key": "shapeshift", |
||||
"time": 1471566579224, |
||||
"response": { |
||||
"status": "no_deposits", |
||||
"depositAddress": "1L8BJCR6KHkCiVceDqibt7zJscqPpH7pFw" |
||||
} |
||||
}, |
||||
{ |
||||
"depositAddress": "1L8BJCR6KHkCiVceDqibt7zJscqPpH7pFw", |
||||
"depositType": "BTC", |
||||
"key": "shapeshift", |
||||
"time": 1471566565378, |
||||
"response": { |
||||
"status": "received", |
||||
"depositAddress": "1L8BJCR6KHkCiVceDqibt7zJscqPpH7pFw" |
||||
} |
||||
} |
||||
], |
||||
"transactions": [ { |
||||
"id": 1467921503489592, |
||||
"txParams": { |
||||
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", |
||||
"to": "0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761", |
||||
"value": "0x66c899104aa57038000", |
||||
"origin": "thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com", |
||||
"metamaskId": 1467921503489592, |
||||
"metamaskNetworkId": "2" |
||||
}, |
||||
"time": 1467921503489, |
||||
"status": "rejected", |
||||
"containsDelegateCall": false |
||||
}, |
||||
{ |
||||
"id": 1467923203344608, |
||||
"txParams": { |
||||
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", |
||||
"to": "0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761", |
||||
"value": "0x0", |
||||
"origin": "thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com", |
||||
"metamaskId": 1467923203344608, |
||||
"metamaskNetworkId": "2" |
||||
}, |
||||
"time": 1467923203344, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": false, |
||||
"hash": "0x957bbba51e2732a86c10c5e7e8a484a093795a06f2e2c38ad02da1b20aeca620" |
||||
}, |
||||
{ |
||||
"id": 1467921503489592, |
||||
"txParams": { |
||||
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", |
||||
"to": "0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761", |
||||
"value": "0x66c899104aa57038000", |
||||
"origin": "thelongestdomainnameintheworldandthensomeandthensomemoreandmore.com", |
||||
"metamaskId": 1467921503489592, |
||||
"metamaskNetworkId": "2" |
||||
}, |
||||
"time": 1467921503489, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": false |
||||
}], |
||||
"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": "0x0", |
||||
"nonce": "0x0", |
||||
"address": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc" |
||||
}, |
||||
"0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b": { |
||||
"code": "0x", |
||||
"nonce": "0x0", |
||||
"balance": "0x0", |
||||
"address": "0xec1adf982415d2ef5ec55899b9bfb8bc0f29251b" |
||||
}, |
||||
"0xeb9e64b93097bc15f01f13eae97015c57ab64823": { |
||||
"code": "0x", |
||||
"nonce": "0x0", |
||||
"balance": "0x0", |
||||
"address": "0xeb9e64b93097bc15f01f13eae97015c57ab64823" |
||||
}, |
||||
"0x704107d04affddd9b66ab9de3dd7b095852e9b69": { |
||||
"code": "0x", |
||||
"balance": "0x0", |
||||
"nonce": "0x0", |
||||
"address": "0x704107d04affddd9b66ab9de3dd7b095852e9b69" |
||||
} |
||||
}, |
||||
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", |
||||
"network": "1", |
||||
"seedWords": null, |
||||
"isConfirmed": true, |
||||
"unconfMsgs": {}, |
||||
"messages": [], |
||||
"provider": { |
||||
"type": "mainnet" |
||||
}, |
||||
"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
@ -0,0 +1,406 @@ |
||||
{ |
||||
"metamask": { |
||||
"isInitialized": true, |
||||
"isUnlocked": true, |
||||
"isEthConfirmed": true, |
||||
"currentDomain": "example.com", |
||||
"rpcTarget": "https://rawtestrpc.metamask.io/", |
||||
"identities": { |
||||
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { |
||||
"name": "Wallet 1", |
||||
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"mayBeFauceting": false |
||||
}, |
||||
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { |
||||
"name": "Wallet 2", |
||||
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb", |
||||
"mayBeFauceting": false |
||||
}, |
||||
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { |
||||
"name": "Wallet 3", |
||||
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d", |
||||
"mayBeFauceting": false |
||||
} |
||||
}, |
||||
"unconfTxs": {}, |
||||
"currentFiat": "USD", |
||||
"conversionRate": 11.02269525, |
||||
"conversionDate": 1472076963, |
||||
"accounts": { |
||||
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { |
||||
"balance": "0x056ace16d84b1c7e78", |
||||
"nonce": "0x17", |
||||
"code": "0x0", |
||||
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" |
||||
}, |
||||
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { |
||||
"balance": "0x00000000000000056bc75e2d63100000", |
||||
"nonce": "0x0", |
||||
"code": "0x0", |
||||
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb" |
||||
}, |
||||
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { |
||||
"balance": "0x00000000000000056bc75e2d63100000", |
||||
"nonce": "0x0", |
||||
"code": "0x0", |
||||
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d" |
||||
} |
||||
}, |
||||
"transactions": [ |
||||
{ |
||||
"id": 1471975421223082, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb000000000000000000000000000000000000000000000000000000000000000a", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471975421223082, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471975421223, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0xd0fe393e2586ebded866c9f13b90494e902bc49047fbf25ba2ac96c805a2f5d3" |
||||
}, |
||||
{ |
||||
"id": 1471975427199819, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb000000000000000000000000000000000000000000000000000000000000000a", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471975427199819, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471975427199, |
||||
"status": "rejected", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0xb1f2f63f3e265f05d7c353ab38dd8b73fce8e7214489037311ee1f58a994dae3" |
||||
}, |
||||
{ |
||||
"id": 1471975806981442, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb000000000000000000000000000000000000000000000000000000000000000a", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471975806981442, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471975806981, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0xeeb89e91aaeea14c4950016c45d60df8ee8874daa6f414de5cf267ea2c17bc6e" |
||||
}, |
||||
{ |
||||
"id": 1471975810133789, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb000000000000000000000000000000000000000000000000000000000000000a", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471975810133789, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471975810133, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0xe54cab2e54b8495691b6d8315ca24a190cba546a9fcb056642479ce5770cec8b" |
||||
}, |
||||
{ |
||||
"id": 1471976546865348, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb000000000000000000000000000000000000000000000000000000000000000a", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471976546865348, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471976546865, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0x54e10f77e17f28f4d12751749a2ca22f9b528592d1140ef53c6430a68e731542" |
||||
}, |
||||
{ |
||||
"id": 1471976930101889, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000005", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471976930101889, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471976930101, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0x60b5af26fad18c5549949064b67c8f965c9f20cd3e890c69512ca3acad10ed8b" |
||||
}, |
||||
{ |
||||
"id": 1471977268048169, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000002", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471977268048169, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471977268048, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0x1f96e29305ef11a9c993302c29e5419d87017e8222d4034daea0d86e155dc3aa" |
||||
}, |
||||
{ |
||||
"id": 1471977310778630, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000005", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471977310778630, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471977310778, |
||||
"status": "rejected", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef" |
||||
}, |
||||
{ |
||||
"id": 1471977316241561, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000005", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471977316241561, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471977316240, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0xdbd610c92d77a07c76b82e14e32674d382c45c4780dd2a550888b5cc40d54bcc" |
||||
}, |
||||
{ |
||||
"id": 1471977344018510, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000004", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471977344018510, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471977344018, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0x709d871d9ded0108de9f7718a7490b19d45e5e7562b1ba6c5bf6cce56e767d48" |
||||
}, |
||||
{ |
||||
"id": 1471977403830380, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000001", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471977403830380, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471977403830, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0x94f5088a127bba181b303d6427ae93cbfa9867997bea1326f30da311e36c6aca" |
||||
}, |
||||
{ |
||||
"id": 1471977431563703, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000001", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471977431563703, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471977431563, |
||||
"status": "rejected", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef" |
||||
}, |
||||
{ |
||||
"id": 1471977436074587, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000001", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471977436074587, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471977436074, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0x5f514dfe3bd48f6f301c809a7a75f73f0fc93bc3a0e469368b84dce032aff9ec" |
||||
}, |
||||
{ |
||||
"id": 1471991826717707, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000004", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471991826717707, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471991826717, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0xab1e706f8981680a6c921f9f57f8ce573392bbb4f0fe85cf45e5cbf858fa5f3e" |
||||
}, |
||||
{ |
||||
"id": 1471991851917592, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000004", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471991851917592, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471991851917, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0xdea144f7a6f06969739f676d8702a9a11efc689e032f1981fe67afc9261dd4de" |
||||
}, |
||||
{ |
||||
"id": 1471992032999543, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000005", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471992032999543, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471992032999, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef", |
||||
"hash": "0xdf31b8cc0fbd2ab6727e0b63536bd4eab51a147aa29e04691e68fae28b866fb3" |
||||
}, |
||||
{ |
||||
"id": 1471992043490878, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"to": "0x48ff0cbac0acefedf152281ee80e9a0a01d5da63", |
||||
"data": "0x90b98a11000000000000000000000000c5b8dbac4c1d3f152cdeb400e2313f309c410acb0000000000000000000000000000000000000000000000000000000000000005", |
||||
"origin": "localhost", |
||||
"metamaskId": 1471992043490878, |
||||
"metamaskNetworkId": "1471904489432" |
||||
}, |
||||
"time": 1471992043490, |
||||
"status": "rejected", |
||||
"containsDelegateCall": true, |
||||
"estimatedGas": "0x89ef" |
||||
}, |
||||
{ |
||||
"id": 1472068030402279, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"value": "0x3782dace9d90000", |
||||
"gas": "0x493e0", |
||||
"to": "0x18a672e11d637fffadccc99b152f4895da069601", |
||||
"data": "0x5b7d47a900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", |
||||
"origin": "www.rouleth.com", |
||||
"metamaskId": 1472068030402279, |
||||
"metamaskNetworkId": "1" |
||||
}, |
||||
"time": 1472068030402, |
||||
"status": "rejected", |
||||
"containsDelegateCall": false, |
||||
"estimatedGas": "0x24704" |
||||
}, |
||||
{ |
||||
"id": 1472068061833258, |
||||
"txParams": { |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"value": "0x16345785d8a0000", |
||||
"gas": "0x493e0", |
||||
"to": "0x18a672e11d637fffadccc99b152f4895da069601", |
||||
"data": "0x5b7d47a900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", |
||||
"origin": "www.rouleth.com", |
||||
"metamaskId": 1472068061833258, |
||||
"metamaskNetworkId": "1" |
||||
}, |
||||
"time": 1472068061833, |
||||
"status": "confirmed", |
||||
"containsDelegateCall": false, |
||||
"estimatedGas": "0x24704", |
||||
"hash": "0xb6e6ff57e7b5f6bd7f2e6dc44c39f4e858a227c9509586634ca547179345a13e" |
||||
} |
||||
], |
||||
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"network": "1471904489432", |
||||
"seedWords": null, |
||||
"isConfirmed": true, |
||||
"unconfMsgs": { |
||||
"1472076978535283": { |
||||
"id": 1472076978535283, |
||||
"msgParams": { |
||||
"origin": "localhost", |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"data": "hello" |
||||
}, |
||||
"time": 1472076978535, |
||||
"status": "unconfirmed" |
||||
} |
||||
}, |
||||
"messages": [ |
||||
{ |
||||
"id": 1472076978535283, |
||||
"msgParams": { |
||||
"origin": "localhost", |
||||
"from": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"data": "hello" |
||||
}, |
||||
"time": 1472076978535, |
||||
"status": "unconfirmed" |
||||
} |
||||
], |
||||
"shapeShiftTxList": [], |
||||
"provider": { |
||||
"type": "rpc", |
||||
"rpcTarget": "http://localhost:8545" |
||||
}, |
||||
"selectedAccount": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" |
||||
}, |
||||
"appState": { |
||||
"menuOpen": false, |
||||
"currentView": { |
||||
"name": "confTx", |
||||
"detailView": null, |
||||
"context": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" |
||||
}, |
||||
"accountDetail": { |
||||
"subview": "transactions" |
||||
}, |
||||
"currentDomain": "ebjbdknjcgcbchkagneicjfpneaghdhb", |
||||
"transForward": true, |
||||
"isLoading": false, |
||||
"warning": null |
||||
}, |
||||
"identities": {} |
||||
} |
@ -0,0 +1,39 @@ |
||||
{ |
||||
"metamask": { |
||||
"isInitialized": false, |
||||
"isUnlocked": false, |
||||
"isEthConfirmed": false, |
||||
"currentDomain": "example.com", |
||||
"rpcTarget": "https://rawtestrpc.metamask.io/", |
||||
"identities": {}, |
||||
"unconfTxs": {}, |
||||
"currentFiat": "USD", |
||||
"conversionRate": 0, |
||||
"conversionDate": "N/A", |
||||
"accounts": {}, |
||||
"transactions": [], |
||||
"seedWords": null, |
||||
"isConfirmed": true, |
||||
"unconfMsgs": {}, |
||||
"messages": [], |
||||
"shapeShiftTxList": [], |
||||
"provider": { |
||||
"type": "testnet" |
||||
}, |
||||
"network": "2" |
||||
}, |
||||
"appState": { |
||||
"menuOpen": false, |
||||
"currentView": { |
||||
"name": "restoreVault" |
||||
}, |
||||
"accountDetail": { |
||||
"subview": "transactions" |
||||
}, |
||||
"currentDomain": "extensions", |
||||
"transForward": true, |
||||
"isLoading": false, |
||||
"warning": null |
||||
}, |
||||
"identities": {} |
||||
} |
@ -0,0 +1,76 @@ |
||||
{ |
||||
"metamask": { |
||||
"isInitialized": true, |
||||
"isUnlocked": true, |
||||
"isEthConfirmed": false, |
||||
"currentDomain": "example.com", |
||||
"rpcTarget": "https://rawtestrpc.metamask.io/", |
||||
"identities": { |
||||
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { |
||||
"name": "Wallet 1", |
||||
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"mayBeFauceting": false |
||||
}, |
||||
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { |
||||
"name": "Wallet 2", |
||||
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb", |
||||
"mayBeFauceting": false |
||||
}, |
||||
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { |
||||
"name": "Wallet 3", |
||||
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d", |
||||
"mayBeFauceting": false |
||||
} |
||||
}, |
||||
"unconfTxs": {}, |
||||
"currentFiat": "USD", |
||||
"conversionRate": 11.21283484, |
||||
"conversionDate": 1472158984, |
||||
"accounts": { |
||||
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { |
||||
"code": "0x", |
||||
"balance": "0x34693f54a1e25900", |
||||
"nonce": "0x100013", |
||||
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" |
||||
}, |
||||
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { |
||||
"code": "0x", |
||||
"nonce": "0x100000", |
||||
"balance": "0x18af912cee770000", |
||||
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb" |
||||
}, |
||||
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { |
||||
"code": "0x", |
||||
"nonce": "0x100000", |
||||
"balance": "0x2386f26fc10000", |
||||
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d" |
||||
} |
||||
}, |
||||
"transactions": [], |
||||
"network": "2", |
||||
"seedWords": null, |
||||
"isConfirmed": true, |
||||
"unconfMsgs": {}, |
||||
"messages": [], |
||||
"shapeShiftTxList": [], |
||||
"provider": { |
||||
"type": "testnet" |
||||
}, |
||||
"selectedAccount": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" |
||||
}, |
||||
"appState": { |
||||
"menuOpen": false, |
||||
"currentView": { |
||||
"name": "sendTransaction" |
||||
}, |
||||
"accountDetail": { |
||||
"subview": "transactions" |
||||
}, |
||||
"currentDomain": "127.0.0.1:9966", |
||||
"transForward": true, |
||||
"isLoading": false, |
||||
"warning": null, |
||||
"detailView": {} |
||||
}, |
||||
"identities": {} |
||||
} |
@ -0,0 +1,348 @@ |
||||
{ |
||||
"metamask": { |
||||
"isInitialized": true, |
||||
"isUnlocked": true, |
||||
"isEthConfirmed": true, |
||||
"currentDomain": "example.com", |
||||
"rpcTarget": "https://rawtestrpc.metamask.io/", |
||||
"identities": { |
||||
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { |
||||
"name": "Wallet 1", |
||||
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"mayBeFauceting": false |
||||
}, |
||||
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { |
||||
"name": "Wallet 2", |
||||
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb", |
||||
"mayBeFauceting": false |
||||
}, |
||||
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { |
||||
"name": "Wallet 3", |
||||
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d", |
||||
"mayBeFauceting": false |
||||
} |
||||
}, |
||||
"unconfTxs": {}, |
||||
"currentFiat": "USD", |
||||
"conversionRate": 11.21274318, |
||||
"conversionDate": 1472159644, |
||||
"accounts": { |
||||
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { |
||||
"code": "0x", |
||||
"nonce": "0x13", |
||||
"balance": "0x461d4a64e937d3d1", |
||||
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" |
||||
}, |
||||
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { |
||||
"code": "0x", |
||||
"nonce": "0x0", |
||||
"balance": "0x0", |
||||
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb" |
||||
}, |
||||
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { |
||||
"code": "0x", |
||||
"balance": "0x0", |
||||
"nonce": "0x0", |
||||
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d" |
||||
} |
||||
}, |
||||
"transactions": [], |
||||
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"network": "1", |
||||
"seedWords": null, |
||||
"isConfirmed": true, |
||||
"unconfMsgs": {}, |
||||
"messages": [], |
||||
"shapeShiftTxList": [], |
||||
"provider": { |
||||
"type": "mainnet" |
||||
}, |
||||
"selectedAccount": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" |
||||
}, |
||||
"appState": { |
||||
"menuOpen": false, |
||||
"currentView": { |
||||
"name": "buyEth", |
||||
"context": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" |
||||
}, |
||||
"accountDetail": { |
||||
"subview": "transactions" |
||||
}, |
||||
"currentDomain": "127.0.0.1:9966", |
||||
"transForward": true, |
||||
"isLoading": false, |
||||
"detailView": {}, |
||||
"buyView": { |
||||
"subview": "buyForm", |
||||
"formView": { |
||||
"coinbase": false, |
||||
"shapeshift": true, |
||||
"marketinfo": { |
||||
"pair": "btc_eth", |
||||
"rate": 51.14252949, |
||||
"minerFee": 0.01, |
||||
"limit": 2.60306578, |
||||
"minimum": 0.00038935, |
||||
"maxLimit": 8.67688592 |
||||
}, |
||||
"coinOptions": { |
||||
"BTC": { |
||||
"name": "Bitcoin", |
||||
"symbol": "BTC", |
||||
"image": "https://shapeshift.io/images/coins/bitcoin.png", |
||||
"status": "available" |
||||
}, |
||||
"BCY": { |
||||
"name": "BitCrystals", |
||||
"symbol": "BCY", |
||||
"image": "https://shapeshift.io/images/coins/bitcrystals.png", |
||||
"status": "available" |
||||
}, |
||||
"BLK": { |
||||
"name": "Blackcoin", |
||||
"symbol": "BLK", |
||||
"image": "https://shapeshift.io/images/coins/blackcoin.png", |
||||
"status": "available" |
||||
}, |
||||
"BTS": { |
||||
"name": "Bitshares", |
||||
"symbol": "BTS", |
||||
"specialReturn": false, |
||||
"specialOutgoing": true, |
||||
"specialIncoming": true, |
||||
"fieldName": "destTag", |
||||
"fieldKey": "destTag", |
||||
"image": "https://shapeshift.io/images/coins/bitshares.png", |
||||
"status": "available" |
||||
}, |
||||
"CLAM": { |
||||
"name": "Clams", |
||||
"symbol": "CLAM", |
||||
"image": "https://shapeshift.io/images/coins/clams.png", |
||||
"status": "available" |
||||
}, |
||||
"DASH": { |
||||
"name": "Dash", |
||||
"symbol": "DASH", |
||||
"image": "https://shapeshift.io/images/coins/dash.png", |
||||
"status": "available" |
||||
}, |
||||
"DGB": { |
||||
"name": "Digibyte", |
||||
"symbol": "DGB", |
||||
"image": "https://shapeshift.io/images/coins/digibyte.png", |
||||
"status": "available" |
||||
}, |
||||
"DAO": { |
||||
"name": "TheDao", |
||||
"symbol": "DAO", |
||||
"image": "https://shapeshift.io/images/coins/thedao.png", |
||||
"status": "available" |
||||
}, |
||||
"DGD": { |
||||
"name": "DigixDao", |
||||
"symbol": "DGD", |
||||
"image": "https://shapeshift.io/images/coins/digixdao.png", |
||||
"status": "available" |
||||
}, |
||||
"DOGE": { |
||||
"name": "Dogecoin", |
||||
"symbol": "DOGE", |
||||
"image": "https://shapeshift.io/images/coins/dogecoin.png", |
||||
"status": "available" |
||||
}, |
||||
"EMC": { |
||||
"name": "Emercoin", |
||||
"symbol": "EMC", |
||||
"image": "https://shapeshift.io/images/coins/emercoin.png", |
||||
"status": "available" |
||||
}, |
||||
"ETH": { |
||||
"name": "Ether", |
||||
"symbol": "ETH", |
||||
"image": "https://shapeshift.io/images/coins/ether.png", |
||||
"status": "available" |
||||
}, |
||||
"ETC": { |
||||
"name": "Ether Classic", |
||||
"symbol": "ETC", |
||||
"image": "https://shapeshift.io/images/coins/etherclassic.png", |
||||
"status": "available" |
||||
}, |
||||
"FCT": { |
||||
"name": "Factoids", |
||||
"symbol": "FCT", |
||||
"image": "https://shapeshift.io/images/coins/factoids.png", |
||||
"status": "available" |
||||
}, |
||||
"LBC": { |
||||
"name": "LBRY Credits", |
||||
"symbol": "LBC", |
||||
"image": "https://shapeshift.io/images/coins/lbry.png", |
||||
"status": "available" |
||||
}, |
||||
"LSK": { |
||||
"name": "Lisk", |
||||
"symbol": "LSK", |
||||
"image": "https://shapeshift.io/images/coins/lisk.png", |
||||
"status": "available" |
||||
}, |
||||
"LTC": { |
||||
"name": "Litecoin", |
||||
"symbol": "LTC", |
||||
"image": "https://shapeshift.io/images/coins/litecoin.png", |
||||
"status": "available" |
||||
}, |
||||
"MAID": { |
||||
"name": "Maidsafe", |
||||
"symbol": "MAID", |
||||
"image": "https://shapeshift.io/images/coins/maidsafe.png", |
||||
"status": "available" |
||||
}, |
||||
"MINT": { |
||||
"name": "Mintcoin", |
||||
"symbol": "MINT", |
||||
"image": "https://shapeshift.io/images/coins/mintcoin.png", |
||||
"status": "available" |
||||
}, |
||||
"MONA": { |
||||
"name": "Monacoin", |
||||
"symbol": "MONA", |
||||
"image": "https://shapeshift.io/images/coins/monacoin.png", |
||||
"status": "available" |
||||
}, |
||||
"MSC": { |
||||
"name": "Omni", |
||||
"symbol": "MSC", |
||||
"image": "https://shapeshift.io/images/coins/mastercoin.png", |
||||
"status": "available" |
||||
}, |
||||
"NBT": { |
||||
"name": "Nubits", |
||||
"symbol": "NBT", |
||||
"image": "https://shapeshift.io/images/coins/nubits.png", |
||||
"status": "available" |
||||
}, |
||||
"NMC": { |
||||
"name": "Namecoin", |
||||
"symbol": "NMC", |
||||
"image": "https://shapeshift.io/images/coins/namecoin.png", |
||||
"status": "available" |
||||
}, |
||||
"NVC": { |
||||
"name": "Novacoin", |
||||
"symbol": "NVC", |
||||
"image": "https://shapeshift.io/images/coins/novacoin.png", |
||||
"status": "available" |
||||
}, |
||||
"NXT": { |
||||
"name": "Nxt", |
||||
"symbol": "NXT", |
||||
"specialReturn": false, |
||||
"specialOutgoing": true, |
||||
"specialIncoming": true, |
||||
"specialIncomingStatus": false, |
||||
"fieldName": "Public Key (only for unfunded accounts!)", |
||||
"fieldKey": "rsAddress", |
||||
"image": "https://shapeshift.io/images/coins/nxt.png", |
||||
"status": "available" |
||||
}, |
||||
"PPC": { |
||||
"name": "Peercoin", |
||||
"symbol": "PPC", |
||||
"image": "https://shapeshift.io/images/coins/peercoin.png", |
||||
"status": "available" |
||||
}, |
||||
"RDD": { |
||||
"name": "Reddcoin", |
||||
"symbol": "RDD", |
||||
"image": "https://shapeshift.io/images/coins/reddcoin.png", |
||||
"status": "available" |
||||
}, |
||||
"SDC": { |
||||
"name": "Shadowcash", |
||||
"symbol": "SDC", |
||||
"image": "https://shapeshift.io/images/coins/shadowcash.png", |
||||
"status": "available" |
||||
}, |
||||
"SC": { |
||||
"name": "Siacoin", |
||||
"symbol": "SC", |
||||
"image": "https://shapeshift.io/images/coins/siacoin.png", |
||||
"status": "available" |
||||
}, |
||||
"SJCX": { |
||||
"name": "StorjX", |
||||
"symbol": "SJCX", |
||||
"image": "https://shapeshift.io/images/coins/storjcoinx.png", |
||||
"status": "available" |
||||
}, |
||||
"START": { |
||||
"name": "Startcoin", |
||||
"symbol": "START", |
||||
"image": "https://shapeshift.io/images/coins/startcoin.png", |
||||
"status": "available" |
||||
}, |
||||
"STEEM": { |
||||
"name": "Steem", |
||||
"symbol": "STEEM", |
||||
"specialReturn": false, |
||||
"specialOutgoing": true, |
||||
"specialIncoming": true, |
||||
"fieldName": "destTag", |
||||
"fieldKey": "destTag", |
||||
"image": "https://shapeshift.io/images/coins/steem.png", |
||||
"status": "available" |
||||
}, |
||||
"USDT": { |
||||
"name": "Tether", |
||||
"symbol": "USDT", |
||||
"image": "https://shapeshift.io/images/coins/tether.png", |
||||
"status": "available" |
||||
}, |
||||
"VOX": { |
||||
"name": "Voxels", |
||||
"symbol": "VOX", |
||||
"image": "https://shapeshift.io/images/coins/voxels.png", |
||||
"status": "available" |
||||
}, |
||||
"VRC": { |
||||
"name": "Vericoin", |
||||
"symbol": "VRC", |
||||
"image": "https://shapeshift.io/images/coins/vericoin.png", |
||||
"status": "available" |
||||
}, |
||||
"VTC": { |
||||
"name": "Vertcoin", |
||||
"symbol": "VTC", |
||||
"image": "https://shapeshift.io/images/coins/vertcoin.png", |
||||
"status": "available" |
||||
}, |
||||
"XCP": { |
||||
"name": "Counterparty", |
||||
"symbol": "XCP", |
||||
"image": "https://shapeshift.io/images/coins/counterparty.png", |
||||
"status": "available" |
||||
}, |
||||
"XMR": { |
||||
"name": "Monero", |
||||
"symbol": "XMR", |
||||
"specialReturn": false, |
||||
"specialOutgoing": true, |
||||
"specialIncoming": true, |
||||
"fieldName": "Payment Id", |
||||
"qrName": "tx_payment_id", |
||||
"fieldKey": "paymentId", |
||||
"image": "https://shapeshift.io/images/coins/monero.png", |
||||
"status": "available" |
||||
} |
||||
} |
||||
}, |
||||
"buyAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", |
||||
"amount": "5.00", |
||||
"warning": null |
||||
}, |
||||
"isSubLoading": false |
||||
}, |
||||
"identities": {} |
||||
} |
@ -0,0 +1,28 @@ |
||||
# Form Persisting Architecture |
||||
|
||||
Since: |
||||
- The popup is torn down completely on every click outside of it. |
||||
- We have forms with multiple fields (like passwords & seed phrases) that might encourage a user to leave our panel to refer to a password manager. |
||||
|
||||
We cause user friction when we lose the contents of certain forms. |
||||
|
||||
This calls for an architecture of a form component that can completely persist its values to LocalStorage on every relevant change, and restore those values on reopening. |
||||
|
||||
To achieve this, we have defined a class, a subclass of `React.Component`, called `PersistentForm`, and it's stored at `ui/lib/persistent-form.js`. |
||||
|
||||
To use this class, simply take your form component (the component that renders `input`, `select`, or `textarea` elements), and make it subclass from `PersistentForm` instead of `React.Component`. |
||||
|
||||
You can see an example of this in use in `ui/app/first-time/restore-vault.js`. |
||||
|
||||
Additionally, any field whose value should be persisted, should have a `persistentFormId` attribute, which needs to be assigned under a `dataset` key on the main `attributes` hash. For example: |
||||
|
||||
```javascript |
||||
return h('textarea.twelve-word-phrase.letter-spacey', { |
||||
dataset: { |
||||
persistentFormId: 'wallet-seed', |
||||
}, |
||||
}) |
||||
``` |
||||
|
||||
That's it! This field should be persisted to `localStorage` on each `keyUp`, those values should be restored on view load, and the cached values should be cleared when navigating deliberately away from the form. |
||||
|
@ -0,0 +1,12 @@ |
||||
var assert = require('assert') |
||||
var linkGen = require('../../ui/lib/account-link') |
||||
|
||||
describe('account-link', function() { |
||||
|
||||
it('adds testnet prefix to morden test network', function() { |
||||
var result = linkGen('account', '2') |
||||
assert.notEqual(result.indexOf('testnet'), -1, 'testnet injected') |
||||
assert.notEqual(result.indexOf('account'), -1, 'account included') |
||||
}) |
||||
|
||||
}) |
@ -0,0 +1,140 @@ |
||||
const Component = require('react').Component |
||||
const h = require('react-hyperscript') |
||||
const inherits = require('util').inherits |
||||
const connect = require('react-redux').connect |
||||
const formatBalance = require('../util').formatBalance |
||||
const generateBalanceObject = require('../util').generateBalanceObject |
||||
const Tooltip = require('./tooltip.js') |
||||
|
||||
module.exports = connect(mapStateToProps)(EthBalanceComponent) |
||||
|
||||
function mapStateToProps (state) { |
||||
return { |
||||
conversionRate: state.metamask.conversionRate, |
||||
conversionDate: state.metamask.conversionDate, |
||||
currentFiat: state.metamask.currentFiat, |
||||
} |
||||
} |
||||
|
||||
inherits(EthBalanceComponent, Component) |
||||
function EthBalanceComponent () { |
||||
Component.call(this) |
||||
} |
||||
|
||||
EthBalanceComponent.prototype.render = function () { |
||||
var state = this.props |
||||
var style = state.style |
||||
|
||||
const value = formatBalance(state.value, 6) |
||||
var width = state.width |
||||
|
||||
return ( |
||||
|
||||
h('.ether-balance', { |
||||
style: style, |
||||
}, [ |
||||
h('.ether-balance-amount', { |
||||
style: { |
||||
display: 'inline', |
||||
width: width, |
||||
}, |
||||
}, this.renderBalance(value, state)), |
||||
]) |
||||
|
||||
) |
||||
} |
||||
EthBalanceComponent.prototype.renderBalance = function (value, state) { |
||||
if (value === 'None') return value |
||||
var balanceObj = generateBalanceObject(value, state.shorten ? 1 : 3) |
||||
var balance, fiatDisplayNumber, fiatTooltipNumber |
||||
var splitBalance = value.split(' ') |
||||
var ethNumber = splitBalance[0] |
||||
var ethSuffix = splitBalance[1] |
||||
|
||||
|
||||
if (state.conversionRate !== 0) { |
||||
fiatTooltipNumber = Number(splitBalance[0]) * state.conversionRate |
||||
fiatDisplayNumber = fiatTooltipNumber.toFixed(2) |
||||
} else { |
||||
fiatDisplayNumber = 'N/A' |
||||
} |
||||
|
||||
var fiatSuffix = state.currentFiat |
||||
|
||||
if (state.shorten) { |
||||
balance = balanceObj.shortBalance |
||||
} else { |
||||
balance = balanceObj.balance |
||||
} |
||||
|
||||
var label = balanceObj.label |
||||
|
||||
return ( |
||||
h('.flex-column', [ |
||||
h(Tooltip, { |
||||
position: 'bottom', |
||||
title: `${ethNumber} ${ethSuffix}`, |
||||
}, [ |
||||
h('.flex-row', { |
||||
style: { |
||||
alignItems: 'flex-end', |
||||
lineHeight: '13px', |
||||
fontFamily: 'Montserrat Light', |
||||
textRendering: 'geometricPrecision', |
||||
marginBottom: '5px', |
||||
}, |
||||
}, [ |
||||
h('div', { |
||||
style: { |
||||
width: '100%', |
||||
textAlign: 'right', |
||||
}, |
||||
}, balance), |
||||
h('div', { |
||||
style: { |
||||
color: '#AEAEAE', |
||||
marginLeft: '5px', |
||||
}, |
||||
}, label), |
||||
]), |
||||
]), |
||||
h(Tooltip, { |
||||
position: 'bottom', |
||||
title: `${fiatTooltipNumber} ${fiatSuffix}`, |
||||
}, [ |
||||
fiatDisplay(fiatDisplayNumber, fiatSuffix), |
||||
]), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
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') |
||||
} |
||||
} |
@ -0,0 +1,42 @@ |
||||
const Component = require('react').Component |
||||
const h = require('react-hyperscript') |
||||
const inherits = require('util').inherits |
||||
const Tooltip = require('./tooltip') |
||||
const genAccountLink = require('../../lib/account-link') |
||||
const extension = require('../../../app/scripts/lib/extension') |
||||
|
||||
module.exports = AccountInfoLink |
||||
|
||||
inherits(AccountInfoLink, Component) |
||||
function AccountInfoLink () { |
||||
Component.call(this) |
||||
} |
||||
|
||||
AccountInfoLink.prototype.render = function () { |
||||
const { selected, network } = this.props |
||||
const title = 'View account on etherscan' |
||||
const url = genAccountLink(selected, network) |
||||
|
||||
if (!url) { |
||||
return null |
||||
} |
||||
|
||||
return h('.account-info-link', { |
||||
style: { |
||||
display: 'flex', |
||||
alignItems: 'center', |
||||
}, |
||||
}, [ |
||||
|
||||
h(Tooltip, { |
||||
title, |
||||
}, [ |
||||
h('i.fa.fa-info-circle.cursor-pointer.color-orange', { |
||||
style: { |
||||
margin: '5px', |
||||
}, |
||||
onClick () { extension.tabs.create({ url }) }, |
||||
}), |
||||
]), |
||||
]) |
||||
} |
@ -0,0 +1,123 @@ |
||||
const Component = require('react').Component |
||||
const h = require('react-hyperscript') |
||||
const inherits = require('util').inherits |
||||
const connect = require('react-redux').connect |
||||
const actions = require('../actions') |
||||
const CoinbaseForm = require('./coinbase-form') |
||||
const ShapeshiftForm = require('./shapeshift-form') |
||||
const extension = require('../../../app/scripts/lib/extension') |
||||
|
||||
module.exports = connect(mapStateToProps)(BuyButtonSubview) |
||||
|
||||
function mapStateToProps (state) { |
||||
return { |
||||
selectedAccount: state.selectedAccount, |
||||
warning: state.appState.warning, |
||||
buyView: state.appState.buyView, |
||||
network: state.metamask.network, |
||||
provider: state.metamask.provider, |
||||
} |
||||
} |
||||
|
||||
inherits(BuyButtonSubview, Component) |
||||
function BuyButtonSubview () { |
||||
Component.call(this) |
||||
} |
||||
|
||||
BuyButtonSubview.prototype.render = function () { |
||||
const props = this.props |
||||
const currentForm = props.buyView.formView |
||||
|
||||
return ( |
||||
h('.buy-eth-section', [ |
||||
// back button
|
||||
h('.flex-row', { |
||||
style: { |
||||
alignItems: 'center', |
||||
justifyContent: 'center', |
||||
}, |
||||
}, [ |
||||
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', { |
||||
onClick: () => props.dispatch(actions.backToAccountDetail(props.selectedAccount)), |
||||
style: { |
||||
position: 'absolute', |
||||
left: '10px', |
||||
}, |
||||
}), |
||||
h('h2.page-subtitle', 'Buy Eth'), |
||||
]), |
||||
h('h3.flex-row.text-transform-uppercase', { |
||||
style: { |
||||
background: '#EBEBEB', |
||||
color: '#AEAEAE', |
||||
paddingTop: '4px', |
||||
justifyContent: 'space-around', |
||||
}, |
||||
}, [ |
||||
h(currentForm.coinbase ? '.activeForm' : '.inactiveForm.pointer', { |
||||
onClick: () => props.dispatch(actions.coinBaseSubview()), |
||||
}, 'Coinbase'), |
||||
h('a', { |
||||
onClick: (event) => this.navigateTo('https://github.com/MetaMask/faq/blob/master/COINBASE.md'), |
||||
}, [ |
||||
h('i.fa.fa-question-circle', { |
||||
style: { |
||||
position: 'relative', |
||||
right: '33px', |
||||
}, |
||||
}), |
||||
]), |
||||
h(currentForm.shapeshift ? '.activeForm' : '.inactiveForm.pointer', { |
||||
onClick: () => props.dispatch(actions.shapeShiftSubview(props.provider.type)), |
||||
}, 'Shapeshift'), |
||||
|
||||
h('a', { |
||||
href: 'https://github.com/MetaMask/faq/blob/master/COINBASE.md', |
||||
onClick: (event) => this.navigateTo('https://info.shapeshift.io/about'), |
||||
}, [ |
||||
h('i.fa.fa-question-circle', { |
||||
style: { |
||||
position: 'relative', |
||||
right: '28px', |
||||
}, |
||||
}), |
||||
]), |
||||
]), |
||||
this.formVersionSubview(), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
BuyButtonSubview.prototype.formVersionSubview = function () { |
||||
if (this.props.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) |
||||
} |
||||
} else { |
||||
return h('div.flex-column', { |
||||
style: { |
||||
alignItems: 'center', |
||||
margin: '50px', |
||||
}, |
||||
}, [ |
||||
h('h3.text-transform-uppercase', { |
||||
style: { |
||||
width: '225px', |
||||
}, |
||||
}, 'In order to access this feature please switch too the Main Network'), |
||||
h('h3.text-transform-uppercase', 'or:'), |
||||
this.props.network === '2' ? h('button.text-transform-uppercase', { |
||||
onClick: () => this.props.dispatch(actions.buyEth()), |
||||
style: { |
||||
marginTop: '15px', |
||||
}, |
||||
}, 'Go To Test Faucet') : null, |
||||
]) |
||||
} |
||||
} |
||||
|
||||
BuyButtonSubview.prototype.navigateTo = function (url) { |
||||
extension.tabs.create({ url }) |
||||
} |
@ -0,0 +1,162 @@ |
||||
const Component = require('react').Component |
||||
const h = require('react-hyperscript') |
||||
const inherits = require('util').inherits |
||||
const connect = require('react-redux').connect |
||||
const actions = require('../actions') |
||||
|
||||
const isValidAddress = require('../util').isValidAddress |
||||
module.exports = connect(mapStateToProps)(CoinbaseForm) |
||||
|
||||
function mapStateToProps(state) { |
||||
return { |
||||
selectedAccount: state.selectedAccount, |
||||
warning: state.appState.warning, |
||||
} |
||||
} |
||||
|
||||
inherits(CoinbaseForm, Component) |
||||
|
||||
function CoinbaseForm() { |
||||
Component.call(this) |
||||
} |
||||
|
||||
CoinbaseForm.prototype.render = function () { |
||||
var props = this.props |
||||
var amount = props.buyView.amount |
||||
var address = props.buyView.buyAddress |
||||
|
||||
return h('.flex-column', { |
||||
style: { |
||||
// margin: '10px',
|
||||
padding: '25px', |
||||
}, |
||||
}, [ |
||||
h('.flex-column', { |
||||
style: { |
||||
alignItems: 'flex-start', |
||||
}, |
||||
}, [ |
||||
h('.flex-row', [ |
||||
h('div', 'Address:'), |
||||
h('.ellip-address', address), |
||||
]), |
||||
h('.flex-row', [ |
||||
h('div', 'Amount: $'), |
||||
h('.input-container', [ |
||||
h('input.buy-inputs', { |
||||
style: { |
||||
width: '3em', |
||||
boxSizing: 'border-box', |
||||
}, |
||||
defaultValue: amount, |
||||
onChange: this.handleAmount.bind(this), |
||||
}), |
||||
h('i.fa.fa-pencil-square-o.edit-text', { |
||||
style: { |
||||
fontSize: '12px', |
||||
color: '#F7861C', |
||||
position: 'relative', |
||||
bottom: '5px', |
||||
right: '11px', |
||||
}, |
||||
}), |
||||
]), |
||||
]), |
||||
]), |
||||
|
||||
h('.info-gray', { |
||||
style: { |
||||
fontSize: '10px', |
||||
fontFamily: 'Montserrat Light', |
||||
margin: '15px', |
||||
lineHeight: '13px', |
||||
}, |
||||
}, |
||||
`there is a USD$ 5 a day max and a USD$ 50
|
||||
dollar limit per the life time of an account without a |
||||
coinbase account. A fee of 3.75% will be aplied to debit/credit cards.`),
|
||||
|
||||
!props.warning ? h('div', { |
||||
style: { |
||||
width: '340px', |
||||
height: '22px', |
||||
}, |
||||
}) : props.warning && h('span.error.flex-center', props.warning), |
||||
|
||||
|
||||
h('.flex-row', { |
||||
style: { |
||||
justifyContent: 'space-around', |
||||
margin: '33px', |
||||
}, |
||||
}, [ |
||||
h('button', { |
||||
onClick: this.toCoinbase.bind(this), |
||||
}, 'Continue to Coinbase'), |
||||
|
||||
h('button', { |
||||
onClick: () => props.dispatch(actions.backTobuyView(props.accounts.address)), |
||||
}, 'Cancel'), |
||||
]), |
||||
]) |
||||
} |
||||
CoinbaseForm.prototype.handleAmount = function (event) { |
||||
this.props.dispatch(actions.updateCoinBaseAmount(event.target.value)) |
||||
} |
||||
CoinbaseForm.prototype.handleAddress = function (event) { |
||||
this.props.dispatch(actions.updateBuyAddress(event.target.value)) |
||||
} |
||||
CoinbaseForm.prototype.toCoinbase = function () { |
||||
var props = this.props |
||||
var amount = props.buyView.amount |
||||
var address = props.buyView.buyAddress |
||||
var message |
||||
|
||||
if (isValidAddress(address) && isValidAmountforCoinBase(amount).valid) { |
||||
props.dispatch(actions.buyEth(address, props.buyView.amount)) |
||||
} else if (!isValidAmountforCoinBase(amount).valid) { |
||||
message = isValidAmountforCoinBase(amount).message |
||||
return props.dispatch(actions.showWarning(message)) |
||||
} else { |
||||
message = 'Receiving address is invalid.' |
||||
return props.dispatch(actions.showWarning(message)) |
||||
} |
||||
} |
||||
|
||||
CoinbaseForm.prototype.renderLoading = function () { |
||||
|
||||
return h('img', { |
||||
style: { |
||||
width: '27px', |
||||
marginRight: '-27px', |
||||
}, |
||||
src: 'images/loading.svg', |
||||
}) |
||||
} |
||||
|
||||
function isValidAmountforCoinBase(amount) { |
||||
amount = parseFloat(amount) |
||||
|
||||
if (amount) { |
||||
if (amount <= 5 && amount > 0) { |
||||
return { |
||||
valid: true, |
||||
} |
||||
} else if (amount > 5) { |
||||
return { |
||||
valid: false, |
||||
message: 'The amount can not be greater then $5', |
||||
} |
||||
} else { |
||||
return { |
||||
valid: false, |
||||
message: 'Can not buy amounts less then $0', |
||||
} |
||||
} |
||||
} else { |
||||
return { |
||||
valid: false, |
||||
message: 'The amount entered is not a number', |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,71 @@ |
||||
const Component = require('react').Component |
||||
const h = require('react-hyperscript') |
||||
const inherits = require('util').inherits |
||||
const connect = require('react-redux').connect |
||||
const CopyButton = require('./copyButton') |
||||
|
||||
module.exports = connect(mapStateToProps)(QrCodeView) |
||||
|
||||
function mapStateToProps (state) { |
||||
return { |
||||
Qr: state.appState.Qr, |
||||
buyView: state.appState.buyView, |
||||
warning: state.appState.warning, |
||||
} |
||||
} |
||||
|
||||
inherits(QrCodeView, Component) |
||||
|
||||
function QrCodeView () { |
||||
Component.call(this) |
||||
} |
||||
|
||||
QrCodeView.prototype.render = function () { |
||||
var props = this.props |
||||
var Qr = props.Qr |
||||
return h('.main-container.flex-column', { |
||||
key: 'qr', |
||||
style: { |
||||
justifyContent: 'center', |
||||
padding: '45px', |
||||
alignItems: 'center', |
||||
}, |
||||
}, [ |
||||
Array.isArray(Qr.message) ? h('.message-container', this.renderMultiMessage()) : h('h3', Qr.message), |
||||
|
||||
this.props.warning ? this.props.warning && h('span.error.flex-center', { |
||||
style: { |
||||
textAlign: 'center', |
||||
width: '229px', |
||||
height: '82px', |
||||
}, |
||||
}, |
||||
this.props.warning) : null, |
||||
|
||||
h('#qr-container.flex-column', { |
||||
style: { |
||||
marginTop: '25px', |
||||
marginBottom: '15px', |
||||
}, |
||||
dangerouslySetInnerHTML: { |
||||
__html: Qr.image, |
||||
}, |
||||
}), |
||||
h('.flex-row', [ |
||||
h('h3.ellip-address', { |
||||
style: { |
||||
width: '247px', |
||||
}, |
||||
}, Qr.data), |
||||
h(CopyButton, { |
||||
value: Qr.data, |
||||
}), |
||||
]), |
||||
]) |
||||
} |
||||
|
||||
QrCodeView.prototype.renderMultiMessage = function () { |
||||
var Qr = this.props.Qr |
||||
var multiMessage = Qr.message.map((message) => h('.qr-message', message)) |
||||
return multiMessage |
||||
} |
@ -0,0 +1,322 @@ |
||||
const PersistentForm = require('../../lib/persistent-form') |
||||
const h = require('react-hyperscript') |
||||
const inherits = require('util').inherits |
||||
const connect = require('react-redux').connect |
||||
const ReactCSSTransitionGroup = require('react-addons-css-transition-group') |
||||
const actions = require('../actions') |
||||
const Qr = require('./qr-code') |
||||
const isValidAddress = require('../util').isValidAddress |
||||
module.exports = connect(mapStateToProps)(ShapeshiftForm) |
||||
|
||||
function mapStateToProps(state) { |
||||
return { |
||||
selectedAccount: state.selectedAccount, |
||||
warning: state.appState.warning, |
||||
isSubLoading: state.appState.isSubLoading, |
||||
qrRequested: state.appState.qrRequested, |
||||
} |
||||
} |
||||
|
||||
inherits(ShapeshiftForm, PersistentForm) |
||||
|
||||
function ShapeshiftForm () { |
||||
PersistentForm.call(this) |
||||
this.persistentFormParentId = 'shapeshift-buy-form' |
||||
} |
||||
|
||||
ShapeshiftForm.prototype.render = function () { |
||||
|
||||
return h(ReactCSSTransitionGroup, { |
||||
className: 'css-transition-group', |
||||
transitionName: 'main', |
||||
transitionEnterTimeout: 300, |
||||
transitionLeaveTimeout: 300, |
||||
}, [ |
||||
this.props.qrRequested ? h(Qr, {key: 'qr'}) : 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: { |
||||
// marginTop: '10px',
|
||||
padding: '25px', |
||||
width: '100%', |
||||
alignItems: 'center', |
||||
}, |
||||
}, [ |
||||
h('.flex-row', { |
||||
style: { |
||||
justifyContent: 'center', |
||||
alignItems: 'baseline', |
||||
}, |
||||
}, [ |
||||
h('img', { |
||||
src: coinOptions[coin].image, |
||||
width: '25px', |
||||
height: '25px', |
||||
style: { |
||||
marginRight: '5px', |
||||
}, |
||||
}), |
||||
|
||||
h('.input-container', [ |
||||
h('input#fromCoin.buy-inputs.ex-coins', { |
||||
type: 'text', |
||||
list: 'coinList', |
||||
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: 'relative', |
||||
bottom: '48px', |
||||
left: '106px', |
||||
}, |
||||
}), |
||||
]), |
||||
|
||||
h('.icon-control', [ |
||||
h('i.fa.fa-refresh.fa-4.orange', { |
||||
style: { |
||||
position: 'relative', |
||||
bottom: '5px', |
||||
left: '5px', |
||||
color: '#F7861C', |
||||
}, |
||||
onClick: this.updateCoin.bind(this), |
||||
}), |
||||
h('i.fa.fa-chevron-right.fa-4.orange', { |
||||
style: { |
||||
position: 'relative', |
||||
bottom: '26px', |
||||
left: '10px', |
||||
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', |
||||
}, |
||||
}), |
||||
]), |
||||
|
||||
this.props.isSubLoading ? this.renderLoading() : null, |
||||
h('.flex-column', { |
||||
style: { |
||||
width: '235px', |
||||
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(), |
||||
]), |
||||
|
||||
h('.flex-row', { |
||||
style: { |
||||
padding: '10px', |
||||
paddingBottom: '2px', |
||||
width: '100%', |
||||
}, |
||||
}, [ |
||||
h('div', 'Receiving address:'), |
||||
h('.ellip-address', this.props.buyView.buyAddress), |
||||
]), |
||||
|
||||
h(this.activeToggle('.input-container'), { |
||||
style: { |
||||
padding: '10px', |
||||
paddingTop: '0px', |
||||
width: '100%', |
||||
}, |
||||
}, [ |
||||
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: '278px', |
||||
height: '20px', |
||||
padding: ' 5px ', |
||||
}, |
||||
}), |
||||
|
||||
h('i.fa.fa-pencil-square-o.edit-text', { |
||||
style: { |
||||
fontSize: '12px', |
||||
color: '#F7861C', |
||||
position: 'relative', |
||||
bottom: '5px', |
||||
right: '11px', |
||||
}, |
||||
}), |
||||
h('.flex-row', { |
||||
style: { |
||||
justifyContent: 'flex-end', |
||||
}, |
||||
}, [ |
||||
h('button', { |
||||
onClick: this.shift.bind(this), |
||||
style: { |
||||
marginTop: '10px', |
||||
}, |
||||
}, |
||||
'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.showWarning(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: { |
||||
marginTop: '15px', |
||||
marginBottom: '15px', |
||||
}, |
||||
}, [ |
||||
h('h3.flex-row.text-transform-uppercase', { |
||||
style: { |
||||
color: '#AEAEAE', |
||||
paddingTop: '4px', |
||||
justifyContent: 'space-around', |
||||
textAlign: 'center', |
||||
fontSize: '14px', |
||||
}, |
||||
}, `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.handleAddress = function (event) { |
||||
this.props.dispatch(actions.updateBuyAddress(event.target.value)) |
||||
} |
||||
|
||||
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', |
||||
}), |
||||
]) |
||||
} |
@ -0,0 +1,202 @@ |
||||
const inherits = require('util').inherits |
||||
const Component = require('react').Component |
||||
const h = require('react-hyperscript') |
||||
const connect = require('react-redux').connect |
||||
const vreme = new (require('vreme')) |
||||
const explorerLink = require('../../lib/explorer-link') |
||||
const extension = require('../../../app/scripts/lib/extension') |
||||
const actions = require('../actions') |
||||
const addressSummary = require('../util').addressSummary |
||||
|
||||
const CopyButton = require('./copyButton') |
||||
const EtherBalance = require('./eth-balance') |
||||
const Tooltip = require('./tooltip') |
||||
|
||||
|
||||
module.exports = connect(mapStateToProps)(ShiftListItem) |
||||
|
||||
function mapStateToProps (state) { |
||||
return {} |
||||
} |
||||
|
||||
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 vreme.format(new Date(date), 'March 16 2014 14:30') |
||||
} |
||||
|
||||
ShiftListItem.prototype.renderUtilComponents = function () { |
||||
var props = this.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(EtherBalance, { |
||||
value: `${props.response.outgoingCoin}`, |
||||
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: () => extension.tabs.create({ |
||||
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 '' |
||||
} |
||||
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,18 @@ |
||||
module.exports = function(address, network) { |
||||
const net = parseInt(network) |
||||
let link |
||||
|
||||
switch (net) { |
||||
case 1: // main net
|
||||
link = `http://etherscan.io/address/${address}` |
||||
break |
||||
case 2: // morden test net
|
||||
link = `http://testnet.etherscan.io/address/${address}` |
||||
break |
||||
default: |
||||
link = '' |
||||
break |
||||
} |
||||
|
||||
return link |
||||
} |
@ -0,0 +1,57 @@ |
||||
const inherits = require('util').inherits |
||||
const Component = require('react').Component |
||||
const defaultKey = 'persistent-form-default' |
||||
const eventName = 'keyup' |
||||
|
||||
module.exports = PersistentForm |
||||
|
||||
function PersistentForm () { |
||||
Component.call(this) |
||||
} |
||||
|
||||
inherits(PersistentForm, Component) |
||||
|
||||
PersistentForm.prototype.componentDidMount = function () { |
||||
const fields = document.querySelectorAll('[data-persistent-formid]') |
||||
const store = this.getPersistentStore() |
||||
fields.forEach((field) => { |
||||
const key = field.getAttribute('data-persistent-formid') |
||||
const cached = store[key] |
||||
if (cached !== undefined) { |
||||
field.value = cached |
||||
} |
||||
|
||||
field.addEventListener(eventName, this.persistentFieldDidUpdate.bind(this)) |
||||
}) |
||||
} |
||||
|
||||
PersistentForm.prototype.getPersistentStore = function () { |
||||
let store = window.localStorage[this.persistentFormParentId || defaultKey] |
||||
if (store && store !== 'null') { |
||||
store = JSON.parse(store) |
||||
} else { |
||||
store = {} |
||||
} |
||||
return store |
||||
} |
||||
|
||||
PersistentForm.prototype.setPersistentStore = function (newStore) { |
||||
window.localStorage[this.persistentFormParentId || defaultKey] = JSON.stringify(newStore) |
||||
} |
||||
|
||||
PersistentForm.prototype.persistentFieldDidUpdate = function (event) { |
||||
const field = event.target |
||||
const store = this.getPersistentStore() |
||||
const key = field.getAttribute('data-persistent-formid') |
||||
const val = field.value |
||||
store[key] = val |
||||
this.setPersistentStore(store) |
||||
} |
||||
|
||||
PersistentForm.prototype.componentWillUnmount = function () { |
||||
const fields = document.querySelectorAll('[data-persistent-formid]') |
||||
fields.forEach((field) => { |
||||
field.removeEventListener(eventName, this.persistentFieldDidUpdate.bind(this)) |
||||
}) |
||||
this.setPersistentStore({}) |
||||
} |
Loading…
Reference in new issue