Browse Source

update LND

renovate/lint-staged-8.x
Jack Mallers 7 years ago
parent
commit
c142517ad2
  1. 1
      .gitattributes
  2. 133
      app/components/Channels/NetworkChannels.js
  3. 114
      app/components/Channels/NetworkChannels.scss
  4. 4
      app/components/LndSyncing/LndSyncing.js
  5. 1
      app/components/Nav/Nav.js
  6. 86
      app/components/Peers/Peers.js
  7. 59
      app/components/Peers/Peers.scss
  8. 13
      app/components/Wallet/ReceiveModal.js
  9. 13
      app/components/Wallet/ReceiveModal.scss
  10. 7
      app/components/Wallet/Wallet.js
  11. 67
      app/containers/Root.js
  12. BIN
      app/icons/1024x1024.png
  13. BIN
      app/icons/128x128.png
  14. BIN
      app/icons/16x16.png
  15. BIN
      app/icons/24x24.png
  16. BIN
      app/icons/256x256.png
  17. BIN
      app/icons/32x32.png
  18. BIN
      app/icons/48x48.png
  19. BIN
      app/icons/512x512.png
  20. BIN
      app/icons/64x64.png
  21. BIN
      app/icons/96x96.png
  22. 1
      app/icons/globe.svg
  23. 20
      app/lnd/config/index.js
  24. 14
      app/lnd/methods/index.js
  25. 2
      app/lnd/methods/paymentsController.js
  26. 42
      app/lnd/utils/index.js
  27. 2
      app/main.dev.js
  28. 4
      app/reducers/address.js
  29. 26
      app/reducers/channels.js
  30. 8
      app/reducers/info.js
  31. 6
      app/reducers/lnd.js
  32. 43
      app/reducers/network.js
  33. 18
      app/routes/activity/components/Activity.js
  34. 6
      app/routes/activity/components/Activity.scss
  35. 9
      app/routes/activity/containers/ActivityContainer.js
  36. 22
      app/routes/app/components/App.js
  37. 177
      app/routes/channels/components/Channels.js
  38. 52
      app/routes/channels/components/Channels.scss
  39. 75
      app/routes/peers/components/Peers.js
  40. 55
      app/routes/peers/components/Peers.scss
  41. 2
      app/routes/peers/containers/PeersContainer.js
  42. 1
      app/variables.scss
  43. 8
      package.json
  44. BIN
      resources/bin/darwin/lnd
  45. BIN
      resources/bin/linux/lnd
  46. BIN
      resources/bin/win32/lnd.exe
  47. 51
      resources/zap_2.svg
  48. 95
      yarn.lock

1
.gitattributes

@ -3,3 +3,4 @@
*.ico binary
*.icns binary
resources/bin/* binary
resources/bin/* -text

133
app/components/Channels/NetworkChannels.js

@ -1,133 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { ForceGraph, ForceGraphNode, ForceGraphLink } from 'react-vis-force'
import { FaCircle } from 'react-icons/lib/fa'
import styles from './NetworkChannels.scss'
class NetworkChannels extends Component {
constructor(props) {
super(props)
this.state = {
ready: false
}
}
componentWillMount() {
setTimeout(() => {
this.setState({ ready: true })
}, 1000)
this.props.setCurrentChannel(this.props.channels[0])
}
render() {
const { ready } = this.state
const {
channels,
network: { nodes, edges, selectedChannel, networkLoading },
identity_pubkey,
setCurrentChannel
} = this.props
if (!ready || networkLoading) {
return (
<div className={styles.networkLoading}>
<h1>loading network graph</h1>
</div>
)
}
return (
<div className={styles.networkchannels}>
<div className={styles.network}>
<ForceGraph
simulationOptions={
{
width: 1000,
height: 1000,
strength: {
charge: -750
}
}
}
labelAttr='label'
opacityFactor={1}
zoomOptions={{ minScale: 0.1, maxScale: 5 }}
zoom
animate
highlightDependencies
>
{
nodes.map(node => (
<ForceGraphNode
r={15}
label={node.pub_key}
key={node.pub_key}
node={{ id: node.pub_key }}
className={`${styles.node} ${identity_pubkey === node.pub_key && styles.active}`}
fill={identity_pubkey === node.pub_key ? 'green' : 'silver'}
/>
))
}
{
edges.map(edge => (
<ForceGraphLink
className={`${styles.line} ${selectedChannel.chan_id === edge.channel_id && styles.active}`}
key={edge.channel_id}
link={{ source: edge.node1_pub, target: edge.node2_pub }}
/>
))
}
</ForceGraph>
</div>
<div className={styles.channels}>
<ul>
{
channels.map((channel, index) => (
<li
key={index}
className={`${styles.channel} ${channel.chan_id === selectedChannel.chan_id && styles.active}`}
onClick={() => setCurrentChannel(channel)}
>
<header>
{
channel.active ?
<span className={styles.active}>
<FaCircle />
<i>active</i>
</span>
:
<span className={styles.notactive}>
<FaCircle />
<i>not active</i>
</span>
}
</header>
<div className={styles.content}>
<div>
<h4>Remote Pubkey</h4>
<h2>{`${channel.remote_pubkey.substring(30, channel.remote_pubkey.length)}...`}</h2>
</div>
<div>
<h4>Channel Point</h4>
<h2>{`${channel.channel_point.substring(30, channel.channel_point.length)}...`}</h2>
</div>
</div>
</li>
))
}
</ul>
</div>
</div>
)
}
}
NetworkChannels.propTypes = {
channels: PropTypes.array.isRequired,
network: PropTypes.object.isRequired,
identity_pubkey: PropTypes.string.isRequired,
setCurrentChannel: PropTypes.func.isRequired
}
export default NetworkChannels

114
app/components/Channels/NetworkChannels.scss

@ -1,114 +0,0 @@
@import '../../variables.scss';
@keyframes dash {
to {
stroke-dashoffset: 1000;
}
}
.networkLoading {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: $black;
h1 {
font-size: 22px;
color: $green;
font-family: 'courier';
text-align: center;
margin-top: 25%;
}
}
.networkchannels {
position: relative;
}
.network, .channels {
display: inline-block;
vertical-align: top;
}
.network {
width: 70%;
}
.channels {
width: calc(30% - 2px);
border: 1px solid $darkestgrey;
border-radius: 5px;
}
.node {
r: 15;
fill: $darkestgrey;
.active {
r: 25;
fill: $green;
stroke: $green;
}
}
.line.active {
stroke-width: 10;
opacity: 1;
stroke: $green;
stroke-dasharray: 100;
animation: dash 2.5s infinite linear;
}
.channel {
padding: 10px;
background: rgba(0, 0, 0, 0.7);
cursor: pointer;
transition: all 0.25s;
border-bottom: 1px solid $white;
&.active, &:hover {
background: rgba(255, 255, 255, 0.4);
}
header {
margin-bottom: 10px;
.active {
color: $green;
}
.notactive {
color: $green;
}
span svg {
font-size: 10px;
}
i {
text-transform: uppercase;
font-size: 10px;
margin-left: 5px;
}
}
.content {
div {
margin-bottom: 5px;
}
h4 {
text-transform: uppercase;
margin-bottom: 5px;
font-size: 10px;
color: $main;
}
h2 {
font-size: 14px;
color: $white;
}
}
}

4
app/components/LndSyncing/LndSyncing.js

@ -21,7 +21,7 @@ class LndSyncing extends Component {
},
{
title: 'Onion Routing',
description: 'Onion routing is a technique for anonymous communication over a computer network. In an onion network, messages are encapsulated in layers of encryption, analogous to layers of an onion.' // eslint-diabale-line
description: 'Onion routing is a technique for anonymous communication over a computer network. In an onion network, messages are encapsulated in layers of encryption, analogous to layers of an onion.' // eslint-disable-line
}
],
currentFact: 0
@ -41,7 +41,7 @@ class LndSyncing extends Component {
<div className={styles.container}>
<h3>zap</h3>
<div className={styles.loading}>
{!fetchingBlockHeight && <h4>{syncPercentage}%</h4>}
{!fetchingBlockHeight && <h4>{syncPercentage > 0 && `${syncPercentage}%`}</h4>}
<div className={styles.spinner} />
<h1>syncing your lightning node to the blockchain</h1>
</div>

1
app/components/Nav/Nav.js

@ -6,7 +6,6 @@ import Isvg from 'react-inlinesvg'
import walletIcon from 'icons/wallet.svg'
import peersIcon from 'icons/peers.svg'
import channelsIcon from 'icons/channels.svg'
import settingsIcon from 'icons/settings.svg'
import styles from './Nav.scss'

86
app/components/Peers/Peers.js

@ -1,86 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import { TiPlus } from 'react-icons/lib/ti'
import { FaRepeat } from 'react-icons/lib/fa'
import PeerModal from './PeerModal'
import PeerForm from './PeerForm'
import Peer from './Peer'
import styles from './Peers.scss'
const Peers = ({
fetchPeers,
peersLoading,
peers,
setPeer,
modalPeer,
peerModalOpen,
peerForm,
setPeerForm,
connect,
disconnect
}) => {
const refreshClicked = (event) => {
// store event in icon so we dont get an error when react clears it
const icon = event.currentTarget
// fetch peers
fetchPeers()
// clear animation after the second so we can reuse it
setTimeout(() => { icon.style.animation = '' }, 1000)
// spin icon for 1 sec
icon.style.animation = 'spin 1000ms linear 1'
}
return (
<div className={styles.peers}>
<PeerModal isOpen={peerModalOpen} resetPeer={setPeer} peer={modalPeer} disconnect={disconnect} />
<PeerForm form={peerForm} setForm={setPeerForm} connect={connect} />
<div className={styles.header}>
<h3>Peers</h3>
<span
className={`${styles.refresh} hint--top`}
data-hint='Refresh your peers list'
>
<FaRepeat
style={{ verticalAlign: 'baseline' }}
onClick={refreshClicked}
/>
</span>
<div
className={`${styles.connectPeer} hint--top`}
data-hint='Connect to a peer'
onClick={() => setPeerForm({ isOpen: true })}
>
<TiPlus />
</div>
</div>
<ul>
{
!peersLoading ?
peers.map(peer => <Peer key={peer.peer_id} peer={peer} setPeer={setPeer} />)
:
'Loading...'
}
</ul>
</div>
)
}
Peers.propTypes = {
fetchPeers: PropTypes.func.isRequired,
peersLoading: PropTypes.bool.isRequired,
peers: PropTypes.array.isRequired,
setPeer: PropTypes.func.isRequired,
modalPeer: PropTypes.object,
peerModalOpen: PropTypes.bool.isRequired,
peerForm: PropTypes.object.isRequired,
setPeerForm: PropTypes.func.isRequired,
connect: PropTypes.func.isRequired,
disconnect: PropTypes.func.isRequired
}
export default Peers

59
app/components/Peers/Peers.scss

@ -1,59 +0,0 @@
@import '../../variables.scss';
.peers {
width: 75%;
margin: 50px auto;
.header {
margin-bottom: 10px;
h3, .connectPeer {
display: inline-block;
}
h3 {
text-align: left;
}
.refresh {
cursor: pointer;
margin-left: 5px;
font-size: 12px;
vertical-align: top;
color: $darkestgrey;
line-height: 14px;
transition: color 0.25s;
&:hover {
color: $main;
}
}
.connectPeer {
float: right;
cursor: pointer;
svg {
padding: 3px;
border-radius: 50%;
border: 1px solid $main;
color: $main;
transition: all 0.25s;
&:hover {
border-color: darken($main, 10%);
color: darken($main, 10%);
}
}
}
}
h3 {
text-transform: uppercase;
color: $darkestgrey;
letter-spacing: 1.6px;
font-size: 14px;
font-weight: 400;
margin-bottom: 10px;
}
}

13
app/components/Wallet/ReceiveModal.js

@ -6,7 +6,7 @@ import QRCode from 'qrcode.react'
import { showNotification } from 'notifications'
import styles from './ReceiveModal.scss'
const ReceiveModal = ({ isOpen, hideActivityModal, pubkey, address }) => {
const ReceiveModal = ({ isOpen, hideActivityModal, pubkey, address, newAddress }) => {
const customStyles = {
overlay: {
cursor: 'pointer'
@ -16,7 +16,7 @@ const ReceiveModal = ({ isOpen, hideActivityModal, pubkey, address }) => {
left: '20%',
right: '0',
bottom: 'auto',
width: '40%',
width: '60%',
margin: '50px auto'
}
}
@ -43,8 +43,12 @@ const ReceiveModal = ({ isOpen, hideActivityModal, pubkey, address }) => {
</section>
<section>
<h4>Deposit Address (<span onClick={() => copyOnClick(address)}>Copy</span>)</h4>
<div className={styles.addressHeader}>
<h4>Deposit Address (<span onClick={() => copyOnClick(address)}>Copy</span>)</h4>
<span className={styles.newAddress} onClick={() => newAddress('p2pkh')}>New Address</span>
</div>
<p>{address}</p>
<div className={styles.qrcode}>
<QRCode value={address} />
</div>
@ -58,7 +62,8 @@ ReceiveModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
hideActivityModal: PropTypes.func.isRequired,
pubkey: PropTypes.string.isRequired,
address: PropTypes.string.isRequired
address: PropTypes.string.isRequired,
newAddress: PropTypes.func.isRequired
}
export default ReceiveModal

13
app/components/Wallet/ReceiveModal.scss

@ -35,4 +35,15 @@
padding: 10px;
}
}
}
}
.addressHeader {
display: flex;
flex-direction: row;
justify-content: space-between;
.newAddress {
text-decoration: underline;
font-size: 12px;
}
}

7
app/components/Wallet/Wallet.js

@ -21,7 +21,8 @@ class Wallet extends Component {
const {
balance,
address,
info
info,
newAddress
} = this.props
const { modalOpen } = this.state
@ -35,6 +36,7 @@ class Wallet extends Component {
hideActivityModal={() => this.setState({ modalOpen: false })}
pubkey={info.data.identity_pubkey}
address={address}
newAddress={newAddress}
/>)
}
<div className={styles.content}>
@ -65,7 +67,8 @@ class Wallet extends Component {
Wallet.propTypes = {
balance: PropTypes.object.isRequired,
address: PropTypes.string.isRequired,
info: PropTypes.object.isRequired
info: PropTypes.object.isRequired,
newAddress: PropTypes.func.isRequired
}
export default Wallet

67
app/containers/Root.js

@ -2,6 +2,7 @@
import React from 'react'
import { Provider, connect } from 'react-redux'
import { ConnectedRouter } from 'react-router-redux'
import PropTypes from 'prop-types'
import { fetchBlockHeight, lndSelectors } from 'reducers/lnd'
import LoadingBolt from 'components/LoadingBolt'
import LndSyncing from 'components/LndSyncing'
@ -22,40 +23,42 @@ type RootType = {
history: {}
};
class Root extends React.Component {
render() {
const {
store,
history,
lnd,
fetchBlockHeight,
syncPercentage
} = this.props
console.log('lnd: ', lnd)
console.log('lnd: ', lnd)
if (lnd.syncing) {
return (
<LndSyncing
fetchBlockHeight={fetchBlockHeight}
fetchingBlockHeight={lnd.fetchingBlockHeight}
syncPercentage={syncPercentage}
/>
)
}
if (!lnd.grpcStarted) { return <LoadingBolt /> }
const Root = ({
store,
history,
lnd,
fetchBlockHeight,
syncPercentage
}) => {
// If we are syncing show the syncing screen
if (lnd.syncing) {
return (
<Provider store={store}>
<ConnectedRouter history={history}>
<Routes />
</ConnectedRouter>
</Provider>
<LndSyncing
fetchBlockHeight={fetchBlockHeight}
fetchingBlockHeight={lnd.fetchingBlockHeight}
syncPercentage={syncPercentage}
/>
)
}
}
// Don't launch the app without gRPC connection
if (!lnd.grpcStarted) { return <LoadingBolt /> }
return (
<Provider store={store}>
<ConnectedRouter history={history}>
<Routes />
</ConnectedRouter>
</Provider>
)
}
Root.propTypes = {
store: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
lnd: PropTypes.object.isRequired,
fetchBlockHeight: PropTypes.func.isRequired,
syncPercentage: PropTypes.number.isRequired
}
export default connect(mapStateToProps, mapDispatchToProps)(Root)
export default connect(mapStateToProps, mapDispatchToProps)(Root)

BIN
app/icons/1024x1024.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

BIN
app/icons/128x128.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

BIN
app/icons/16x16.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 B

BIN
app/icons/24x24.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

BIN
app/icons/256x256.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

BIN
app/icons/32x32.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

BIN
app/icons/48x48.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

BIN
app/icons/512x512.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

BIN
app/icons/64x64.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

BIN
app/icons/96x96.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

1
app/icons/globe.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-globe"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>

After

Width:  |  Height:  |  Size: 409 B

20
app/lnd/config/index.js

@ -2,10 +2,26 @@
// Mac OS X: /Users/user/Library/Application Support/Lnd/tls.cert
// Linux: ~/.lnd/tls.cert
// Windows: TODO find out where cert is located for windows machine
import { userInfo } from 'os'
import { userInfo, platform } from 'os'
import { join } from 'path'
let loc
switch (platform()) {
case 'darwin':
loc = 'Library/Application\ Support/Lnd/tls.cert'
break
case 'linux':
loc = '.lnd/tls.cert'
break
case 'win32':
loc = join('Appdata', 'Local', 'Lnd', 'tls.cert')
break
default:
break
}
export default {
lightningRpc: `${__dirname}/rpc.proto`,
lightningHost: 'localhost:10009',
cert: `/Users/${userInfo().username}/Library/Application Support/Lnd/tls.cert`
cert: join(userInfo().homedir, loc)
}

14
app/lnd/methods/index.js

@ -24,7 +24,6 @@ import * as networkController from './networkController'
export default function (lnd, event, msg, data) {
console.log('msg: ', msg)
switch (msg) {
case 'info':
networkController.getInfo(lnd)
@ -32,10 +31,7 @@ export default function (lnd, event, msg, data) {
event.sender.send('receiveInfo', infoData)
event.sender.send('receiveCryptocurrency', infoData.chains[0])
})
.catch(error => {
console.log('error: ', error)
event.sender.send('infoFailed')
})
.catch(() => event.sender.send('infoFailed'))
break
case 'describeNetwork':
networkController.describeGraph(lnd)
@ -129,11 +125,11 @@ export default function (lnd, event, msg, data) {
// Payment looks like { payment_preimage: Buffer, payment_route: Object }
// { paymentRequest } = data
paymentsController.sendPaymentSync(lnd, data)
.then(({ payment_route }) => event.sender.send('paymentSuccessful', Object.assign(data, { payment_route })))
.catch((error) => {
console.log('payinvoice error: ', error)
event.sender.send('paymentFailed', { error: error.toString() })
.then(({ payment_route }) => {
console.log('payinvoice success: ', payment_route)
event.sender.send('paymentSuccessful', Object.assign(data, { payment_route }))
})
.catch(({ error }) => event.sender.send('paymentFailed', { error: error.toString() }))
break
case 'sendCoins':
// Transaction looks like { txid: String }

2
app/lnd/methods/paymentsController.js

@ -9,6 +9,8 @@ export function sendPaymentSync(lnd, { paymentRequest }) {
lnd.sendPaymentSync({ payment_request: paymentRequest }, (err, data) => {
if (err) { reject(err) }
if (!data.payment_route) { reject({ error: data.payment_error }) }
resolve(data)
})
})

42
app/lnd/utils/index.js

@ -1,42 +0,0 @@
import zbase32 from 'zbase32'
function convertBigEndianBufferToLong(longBuffer) {
let longValue = 0
const byteArray = Buffer.from(longBuffer).swap64()
for (let i = byteArray.length - 1; i >= 0; i -= 1) {
longValue = (longValue * 256) + byteArray[i]
}
return longValue
}
export function decodeInvoice(payreq) {
const payreqBase32 = zbase32.decode(payreq)
const bufferHexRotated = Buffer.from(payreqBase32).toString('hex')
const bufferHex = bufferHexRotated.substr(bufferHexRotated.length - 1, bufferHexRotated.length)
+ bufferHexRotated.substr(0, bufferHexRotated.length - 1)
const buffer = Buffer.from(bufferHex, 'hex')
const pubkeyBuffer = buffer.slice(0, 33);
const pubkey = pubkeyBuffer.toString('hex');
const paymentHashBuffer = buffer.slice(33, 65)
const paymentHashHex = paymentHashBuffer.toString('hex')
const valueBuffer = buffer.slice(65, 73)
const amount = convertBigEndianBufferToLong(valueBuffer)
return {
payreq,
pubkey,
amount,
r_hash: paymentHashHex
}
}
export default {
decodeInvoice
}

2
app/main.dev.js

@ -165,7 +165,7 @@ export const startLnd = () => {
'--bitcoin.active',
'--bitcoin.testnet',
'--neutrino.active',
'--neutrino.connect=165.227.7.29:18333',
'--neutrino.connect=faucet.lightning.community:18333',
'--autopilot.active',
'--debuglevel=debug',
'--no-macaroons',

4
app/reducers/address.js

@ -28,9 +28,7 @@ export const newAddress = type => async (dispatch) => {
}
// Receive IPC event for info
export const receiveAddress = (event, address) => dispatch => {
dispatch({ type: RECEIVE_ADDRESS, address })
}
export const receiveAddress = (event, address) => dispatch => dispatch({ type: RECEIVE_ADDRESS, address })
// ------------------------------------
// Action Handlers

26
app/reducers/channels.js

@ -1,10 +1,10 @@
import { createSelector } from 'reselect'
import { ipcRenderer } from 'electron'
import { btc } from 'utils'
import { showNotification } from 'notifications'
import { fetchDescribeNetwork } from './network'
import { closeChannelForm } from './channelform'
import { closeChannelForm, resetChannelForm } from './channelform'
import { setError } from './error'
import { showNotification } from 'notifications'
// ------------------------------------
// Constants
// ------------------------------------
@ -113,28 +113,34 @@ export const openChannel = ({ pubkey, local_amt, push_amt }) => (dispatch) => {
// TODO: Decide how to handle streamed updates for channels
// Receive IPC event for openChannel
export const channelSuccessful = () => (dispatch) => {
console.log('CHANNEL channelSuccessful')
dispatch(fetchChannels())
dispatch(closeChannelForm())
dispatch(resetChannelForm())
}
// Receive IPC event for updated channel
export const pushchannelupdated = () => (dispatch) => {
export const pushchannelupdated = (event, data) => (dispatch) => {
console.log('PUSH CHANNEL UPDATED: ', data)
dispatch(fetchChannels())
}
// Receive IPC event for channel end
export const pushchannelend = event => (dispatch) => { // eslint-disable-line
console.log('PUSH CHANNEL END: ')
dispatch(fetchChannels())
}
// Receive IPC event for channel error
export const pushchannelerror = (event, { error }) => (dispatch) => {
console.log('PUSH CHANNEL ERROR: ', error)
dispatch(openingFailure())
dispatch(setError(error))
}
// Receive IPC event for channel status
export const pushchannelstatus = event => (dispatch) => { // eslint-disable-line
export const pushchannelstatus = (event, data) => (dispatch) => { // eslint-disable-line
console.log('PUSH CHANNEL STATUS: ', data)
dispatch(fetchChannels())
}
@ -194,18 +200,18 @@ export const channelGraphData = (event, data) => (dispatch, getState) => {
dispatch(fetchDescribeNetwork())
// loop through the channel updates
for(let i = 0; i < channel_updates.length; i++) {
let channel_update = channel_updates[i]
let { advertising_node, connecting_node } = channel_update
for (let i = 0; i < channel_updates.length; i++) {
const channel_update = channel_updates[i]
const { advertising_node, connecting_node } = channel_update
// if our node is involved in this update we wanna show a notification
if(info.data.identity_pubkey === advertising_node || info.data.identity_pubkey === connecting_node) {
if (info.data.identity_pubkey === advertising_node || info.data.identity_pubkey === connecting_node) {
// this channel has to do with the user, lets fetch a new channel list for them
// TODO: full fetch is probably not necessary
dispatch(fetchChannels())
// Construct the notification
let otherParty = info.data.identity_pubkey === advertising_node ? connecting_node : advertising_node
const otherParty = info.data.identity_pubkey === advertising_node ? connecting_node : advertising_node
let notifBody = `No new friends, just new channels. Your channel with ${otherParty}` // eslint-disable-line
const notifTitle = 'New channel detected'
@ -217,7 +223,7 @@ export const channelGraphData = (event, data) => (dispatch, getState) => {
}
// IPC event for channel graph status
export const channelGraphStatus = (event, data) => (dispatch) => {
export const channelGraphStatus = (event, data) => () => {
console.log('channelGraphStatus: ', data)
}

8
app/reducers/info.js

@ -19,23 +19,19 @@ export function getInfo() {
// Send IPC event for getinfo
export const fetchInfo = () => async (dispatch) => {
console.log('fetching info')
dispatch(getInfo())
ipcRenderer.send('lnd', { msg: 'info' })
}
// Receive IPC event for info
export const receiveInfo = (event, data) => dispatch => {
console.log('receiving info and fetching other stuff')
export const receiveInfo = (event, data) => (dispatch) => {
dispatch(fetchBalance())
dispatch(newAddress('p2pkh'))
dispatch({ type: RECEIVE_INFO, data })
}
// IPC info fetch failed
export const infoFailed = (event, data) => dispatch => {
console.log('INFO FAILED data: ', data)
}
// export const infoFailed = (event, data) => dispatch => {}
// ------------------------------------
// Action Handlers

6
app/reducers/lnd.js

@ -41,12 +41,12 @@ export const lndSynced = () => (dispatch) => {
showNotification(notifTitle, notifBody)
}
export const grpcDisconnected = () => (dispatch) => dispatch({ type: GRPC_DISCONNECTED })
export const grpcDisconnected = () => dispatch => dispatch({ type: GRPC_DISCONNECTED })
export const grpcConnected = () => (dispatch) => dispatch({ type: GRPC_CONNECTED })
export const grpcConnected = () => dispatch => dispatch({ type: GRPC_CONNECTED })
// Receive IPC event for LND streaming a line
export const lndStdout = (event, line) => dispatch => {
export const lndStdout = (event, line) => (dispatch) => {
let height
let trimmed

43
app/reducers/network.js

@ -14,6 +14,12 @@ export const SET_CURRENT_ROUTE = 'SET_CURRENT_ROUTE'
export const SET_CURRENT_CHANNEL = 'SET_CURRENT_CHANNEL'
export const SET_CURRENT_TAB = 'SET_CURRENT_TAB'
export const SET_CURRENT_PEER = 'SET_CURRENT_PEER'
export const UPDATE_PAY_REQ = 'UPDATE_PAY_REQ'
// ------------------------------------
// Actions
// ------------------------------------
@ -44,6 +50,27 @@ export function setCurrentChannel(selectedChannel) {
}
}
export function setCurrentTab(currentTab) {
return {
type: SET_CURRENT_TAB,
currentTab
}
}
export function setCurrentPeer(currentPeer) {
return {
type: SET_CURRENT_PEER,
currentPeer
}
}
export function updatePayReq(pay_req) {
return {
type: UPDATE_PAY_REQ,
pay_req
}
}
// Send IPC event for describeNetwork
export const fetchDescribeNetwork = () => (dispatch) => {
dispatch(getDescribeNetwork())
@ -83,7 +110,13 @@ const ACTION_HANDLERS = {
}
),
[SET_CURRENT_CHANNEL]: (state, { selectedChannel }) => ({ ...state, selectedChannel })
[SET_CURRENT_CHANNEL]: (state, { selectedChannel }) => ({ ...state, selectedChannel }),
[SET_CURRENT_TAB]: (state, { currentTab }) => ({ ...state, currentTab }),
[SET_CURRENT_PEER]: (state, { currentPeer }) => ({ ...state, currentPeer }),
[UPDATE_PAY_REQ]: (state, { pay_req }) => ({ ...state, pay_req })
}
// ------------------------------------
@ -115,7 +148,13 @@ const initialState = {
routes: [],
currentRoute: {}
},
selectedChannel: {}
selectedChannel: {},
currentTab: 1,
currentPeer: {},
pay_req: ''
}

18
app/routes/activity/components/Activity.js

@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
import { MdSearch } from 'react-icons/lib/md'
import { FaAngleDown } from 'react-icons/lib/fa'
import Wallet from 'components/Wallet'
import Invoice from './components/Invoice'
import Payment from './components/Payment'
import Transaction from './components/Transaction'
@ -44,6 +45,9 @@ class Activity extends Component {
ticker,
searchInvoices,
invoice: { invoicesSearchText, invoiceLoading },
address: { address },
balance,
info,
payment: { paymentLoading },
currentTicker,
activity: { modal, filter, filterPulldown },
@ -51,7 +55,8 @@ class Activity extends Component {
changeFilter,
toggleFilterPulldown,
currentActivity,
nonActiveFilters
nonActiveFilters,
newAddress
} = this.props
if (invoiceLoading || paymentLoading) { return <div>Loading...</div> }
@ -66,6 +71,8 @@ class Activity extends Component {
currentTicker={currentTicker}
/>
<Wallet balance={balance} address={address} info={info} newAddress={newAddress} />
<div className={styles.search}>
<label className={`${styles.label} ${styles.input}`} htmlFor='invoiceSearch'>
<MdSearch />
@ -116,18 +123,25 @@ Activity.propTypes = {
fetchPayments: PropTypes.func.isRequired,
fetchInvoices: PropTypes.func.isRequired,
fetchTransactions: PropTypes.func.isRequired,
ticker: PropTypes.object.isRequired,
searchInvoices: PropTypes.func.isRequired,
invoice: PropTypes.object.isRequired,
payment: PropTypes.object.isRequired,
currentTicker: PropTypes.object.isRequired,
showActivityModal: PropTypes.func.isRequired,
hideActivityModal: PropTypes.func.isRequired,
changeFilter: PropTypes.func.isRequired,
newAddress: PropTypes.func.isRequired,
toggleFilterPulldown: PropTypes.func.isRequired,
activity: PropTypes.object.isRequired,
currentActivity: PropTypes.array.isRequired,
nonActiveFilters: PropTypes.array.isRequired
nonActiveFilters: PropTypes.array.isRequired,
address: PropTypes.object.isRequired,
balance: PropTypes.object.isRequired,
info: PropTypes.object.isRequired
}
export default Activity

6
app/routes/activity/components/Activity.scss

@ -1,7 +1,7 @@
@import '../../../variables.scss';
.search {
height: 75px;
height: 55px;
padding: 2px;
border-bottom: 1px solid $darkgrey;
@ -13,7 +13,7 @@
.label {
width: 5%;
line-height: 70px;
line-height: 50px;
font-size: 25px;
text-align: center;
cursor: pointer;
@ -25,7 +25,7 @@
padding: 0;
border: 0;
border-radius: 0;
height: 68px;
height: 50px;
font-size: 18px;
}
}

9
app/routes/activity/containers/ActivityContainer.js

@ -19,6 +19,8 @@ import {
toggleFilterPulldown,
activitySelectors
} from 'reducers/activity'
import { newAddress } from 'reducers/address'
import Activity from '../components/Activity'
const mapDispatchToProps = {
@ -31,12 +33,17 @@ const mapDispatchToProps = {
showActivityModal,
hideActivityModal,
changeFilter,
toggleFilterPulldown
toggleFilterPulldown,
newAddress
}
const mapStateToProps = state => ({
activity: state.activity,
balance: state.balance,
address: state.address,
info: state.info,
payment: state.payment,
invoice: state.invoice,

22
app/routes/app/components/App.js

@ -1,17 +1,15 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import LndSyncing from 'components/LndSyncing'
import GlobalError from 'components/GlobalError'
import LoadingBolt from 'components/LoadingBolt'
import Form from 'components/Form'
import ModalRoot from 'components/ModalRoot'
import Nav from 'components/Nav'
import Wallet from 'components/Wallet'
import styles from './App.scss'
class App extends Component {
componentWillMount() {
const { fetchTicker, fetchBalance, fetchInfo, newAddress, lnd: { syncing } } = this.props
const { fetchTicker, fetchBalance, fetchInfo, newAddress } = this.props
fetchTicker()
fetchBalance()
@ -21,17 +19,11 @@ class App extends Component {
render() {
const {
lnd,
syncPercentage,
fetchBlockHeight,
modal: { modalType, modalProps },
hideModal,
ticker,
currentTicker,
address: { address },
balance,
info,
form,
openPayForm,
@ -66,11 +58,6 @@ class App extends Component {
/>
<div className={styles.content}>
<Wallet
balance={balance}
address={address}
info={info}
/>
{children}
</div>
</div>
@ -79,16 +66,9 @@ class App extends Component {
}
App.propTypes = {
lnd: PropTypes.object.isRequired,
syncPercentage: PropTypes.number.isRequired,
fetchBlockHeight: PropTypes.func.isRequired,
modal: PropTypes.object.isRequired,
ticker: PropTypes.object.isRequired,
address: PropTypes.object.isRequired,
balance: PropTypes.object.isRequired,
info: PropTypes.object.isRequired,
form: PropTypes.object.isRequired,
formProps: PropTypes.object.isRequired,
closeForm: PropTypes.func.isRequired,

177
app/routes/channels/components/Channels.js

@ -1,24 +1,30 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { FaAlignJustify, FaGlobe, FaAngleDown, FaRepeat } from 'react-icons/lib/fa'
import { FaAngleDown, FaRepeat } from 'react-icons/lib/fa'
import { MdSearch } from 'react-icons/lib/md'
import OpenPendingChannel from 'components/Channels/OpenPendingChannel'
import ClosedPendingChannel from 'components/Channels/ClosedPendingChannel'
import Channel from 'components/Channels/Channel'
import NetworkChannels from 'components/Channels/NetworkChannels'
import ChannelForm from 'components/ChannelForm'
import styles from './Channels.scss'
class Channels extends Component {
componentWillMount() {
const { fetchChannels, fetchPeers, fetchDescribeNetwork } = this.props
constructor(props) {
super(props)
this.state = {
refreshing: false
}
}
componentWillMount() {
const { fetchChannels, fetchPeers } = this.props
fetchChannels()
fetchPeers()
fetchDescribeNetwork()
}
render() {
@ -36,48 +42,61 @@ class Channels extends Component {
toggleFilterPulldown,
changeFilter,
activeChannels,
currentChannels,
openChannels,
updateChannelSearchQuery,
setViewType,
openChannelForm,
ticker,
currentTicker,
channelFormProps,
network,
identity_pubkey,
setCurrentChannel
channelFormProps
} = this.props
const refreshClicked = (event) => {
const refreshClicked = () => {
// turn the spinner on
this.setState({ refreshing: true })
// store event in icon so we dont get an error when react clears it
const icon = event.currentTarget
const icon = this.refs.repeat.childNodes
// fetch peers
fetchChannels()
// clear animation after the second so we can reuse it
setTimeout(() => { icon.style.animation = '' }, 1000)
// spin icon for 1 sec
icon.style.animation = 'spin 1000ms linear 1'
}
// wait for the svg to appear as child
const svgTimeout = setTimeout(() => {
if (icon[0].tagName === 'svg') {
// spin icon for 1 sec
icon[0].style.animation = 'spin 1000ms linear 1'
clearTimeout(svgTimeout)
}
}, 1)
const networkClicked = () => {
if (!activeChannels.length) { return }
setViewType(1)
// clear animation after the second so we can reuse it
const refreshTimeout = setTimeout(() => {
icon[0].style.animation = ''
this.setState({ refreshing: false })
clearTimeout(refreshTimeout)
}, 1000)
}
return (
<div className={`${styles.container} ${viewType === 1 && styles.graphview}`}>
<ChannelForm {...channelFormProps} />
<header className={styles.header}>
<div className={styles.titleContainer}>
<div className={styles.left}>
<h1>Channels</h1>
</div>
</div>
<div className={styles.createChannelContainer}>
<div className={`buttonPrimary ${styles.newChannelButton}`} onClick={openChannelForm}>
Create new channel
</div>
</div>
</header>
<div className={styles.search}>
<label className={`${styles.label} ${styles.input}`} htmlFor='channelSearch'>
<MdSearch />
@ -91,21 +110,6 @@ class Channels extends Component {
id='channelSearch'
/>
</div>
<header className={styles.header}>
<div className={styles.layoutsContainer}>
<span className={viewType === 0 && styles.active} onClick={() => setViewType(0)}>
<FaAlignJustify />
</span>
<span className={viewType === 1 && styles.active} onClick={networkClicked}>
<FaGlobe />
</span>
</div>
<div className={styles.createChannelContainer}>
<div className={`buttonPrimary ${styles.newChannelButton}`} onClick={openChannelForm}>
Create new channel
</div>
</div>
</header>
<div className={styles.filtersContainer}>
<section>
@ -122,62 +126,55 @@ class Channels extends Component {
}
</ul>
</section>
<section className={`${styles.refreshContainer} hint--left`} data-hint='Refresh your channels list'>
<FaRepeat
style={{ verticalAlign: 'baseline' }}
onClick={refreshClicked}
/>
<section className={styles.refreshContainer}>
<span className={styles.refresh} onClick={refreshClicked} ref='repeat'>
{
this.state.refreshing ?
<FaRepeat />
:
'Refresh'
}
</span>
</section>
</div>
<div className={`${styles.channels} ${filterPulldown && styles.fade}`}>
{
viewType === 0 &&
<ul className={viewType === 1 && styles.cardsContainer}>
{
currentChannels.map((channel, index) => {
if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) {
return (
<OpenPendingChannel
key={index}
channel={channel}
ticker={ticker}
currentTicker={currentTicker}
explorerLinkBase={'https://testnet.smartbit.com.au/'}
/>
)
} else if (Object.prototype.hasOwnProperty.call(channel, 'closing_txid')) {
return (
<ClosedPendingChannel
key={index}
channel={channel}
ticker={ticker}
currentTicker={currentTicker}
explorerLinkBase={'https://testnet.smartbit.com.au/'}
/>
)
}
<ul className={viewType === 1 && styles.cardsContainer}>
{
currentChannels.map((channel, index) => {
if (Object.prototype.hasOwnProperty.call(channel, 'blocks_till_open')) {
return (
<Channel
<OpenPendingChannel
key={index}
channel={channel}
ticker={ticker}
currentTicker={currentTicker}
explorerLinkBase={'https://testnet.smartbit.com.au/'}
/>
)
} else if (Object.prototype.hasOwnProperty.call(channel, 'closing_txid')) {
return (
<ClosedPendingChannel
key={index}
channel={channel}
closeChannel={closeChannel}
ticker={ticker}
currentTicker={currentTicker}
explorerLinkBase={'https://testnet.smartbit.com.au/'}
/>
)
})
}
</ul>
}
{ viewType === 1 &&
<NetworkChannels
channels={openChannels}
network={network}
identity_pubkey={identity_pubkey}
setCurrentChannel={setCurrentChannel}
/>
}
}
return (
<Channel
key={index}
ticker={ticker}
channel={channel}
closeChannel={closeChannel}
currentTicker={currentTicker}
/>
)
})
}
</ul>
</div>
</div>
)
@ -186,29 +183,23 @@ class Channels extends Component {
Channels.propTypes = {
fetchChannels: PropTypes.func.isRequired,
fetchPeers: PropTypes.func.isRequired,
channels: PropTypes.object.isRequired,
currentChannels: PropTypes.array.isRequired,
openChannels: PropTypes.array.isRequired,
nonActiveFilters: PropTypes.array.isRequired,
updateChannelSearchQuery: PropTypes.func.isRequired,
setViewType: PropTypes.func.isRequired,
setCurrentChannel: PropTypes.func.isRequired,
openChannelForm: PropTypes.func.isRequired,
closeChannel: PropTypes.func.isRequired,
toggleFilterPulldown: PropTypes.func.isRequired,
changeFilter: PropTypes.func.isRequired,
fetchPeers: PropTypes.func.isRequired,
ticker: PropTypes.object.isRequired,
currentTicker: PropTypes.object.isRequired,
channelFormProps: PropTypes.object.isRequired,
network: PropTypes.object.isRequired,
fetchDescribeNetwork: PropTypes.func.isRequired,
identity_pubkey: PropTypes.string.isRequired
channelFormProps: PropTypes.object.isRequired
}
export default Channels

52
app/routes/channels/components/Channels.scss

@ -5,8 +5,9 @@
}
.search {
height: 75px;
height: 55px;
padding: 2px 25px;
border-top: 1px solid $darkgrey;
border-bottom: 1px solid $darkgrey;
background: $white;
@ -18,8 +19,8 @@
.label {
width: 5%;
line-height: 70px;
font-size: 25px;
line-height: 50px;
font-size: 20px;
text-align: center;
cursor: pointer;
}
@ -30,8 +31,8 @@
padding: 0;
border: 0;
border-radius: 0;
height: 68px;
font-size: 18px;
height: 50px;
font-size: 16px;
}
}
@ -39,6 +40,30 @@
display: flex;
flex-direction: row;
justify-content: space-between;
background: $lightgrey;
.titleContainer {
padding: 20px 40px;
.left {
padding: 10px 0;
h1 {
text-transform: uppercase;
font-size: 26px;
margin-right: 5px;
}
}
}
.createChannelContainer {
padding: 20px 40px;
.createChannelButton {
font-size: 14px;
margin-left: 10px;
}
}
}
.filtersContainer {
@ -46,7 +71,7 @@
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 0 40px;
padding: 20px 40px;
h2, h2 span {
color: $bluegrey;
@ -89,17 +114,22 @@
}
}
}
.refreshContainer {
color: $bluegrey;
text-align: right;
cursor: pointer;
&:hover {
cursor: pointer;
color: lighten($bluegrey, 10%);
.refresh {
text-decoration: underline;
svg {
font-size: 12px;
}
}
}
}
.layoutsContainer {
padding: 40px;

75
app/routes/peers/components/Peers.js

@ -1,9 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Isvg from 'react-inlinesvg'
import userIcon from 'icons/user.svg'
import { FaUser, FaRepeat } from 'react-icons/lib/fa'
import { FaRepeat } from 'react-icons/lib/fa'
import { MdSearch } from 'react-icons/lib/md'
import PeerForm from 'components/Peers/PeerForm'
@ -13,6 +11,14 @@ import Peer from 'components/Peers/Peer'
import styles from './Peers.scss'
class Peers extends Component {
constructor(props) {
super(props)
this.state = {
refreshing: false
}
}
componentWillMount() {
this.props.fetchPeers()
}
@ -28,22 +34,34 @@ class Peers extends Component {
peerModalOpen,
filteredPeers,
peers: { peer, searchQuery },
info: { data: { identity_pubkey } }
peers: { peer, searchQuery }
} = this.props
const refreshClicked = event => {
const refreshClicked = () => {
// turn the spinner on
this.setState({ refreshing: true })
// store event in icon so we dont get an error when react clears it
const icon = event.currentTarget
const icon = this.refs.repeat.childNodes
// fetch peers
fetchPeers()
// clear animation after the second so we can reuse it
setTimeout(() => { icon.style.animation = '' }, 1000)
// wait for the svg to appear as child
const svgTimeout = setTimeout(() => {
if (icon[0].tagName === 'svg') {
// spin icon for 1 sec
icon[0].style.animation = 'spin 1000ms linear 1'
clearTimeout(svgTimeout)
}
}, 1)
// spin icon for 1 sec
icon.style.animation = 'spin 1000ms linear 1'
// clear animation after the second so we can reuse it
const refreshTimeout = setTimeout(() => {
icon[0].style.animation = ''
this.setState({ refreshing: false })
clearTimeout(refreshTimeout)
}, 1000)
}
return (
@ -55,15 +73,7 @@ class Peers extends Component {
<header className={styles.header}>
<div className={styles.titleContainer}>
<div className={styles.left}>
<div className={styles.identityPubkey}>
<section className={styles.userIcon}>
<Isvg src={userIcon} />
</section>
<section>
<h4>Your node public key</h4>
<h2>{identity_pubkey}</h2>
</section>
</div>
<h1>Peers</h1>
</div>
</div>
<div className={styles.addPeerContainer}>
@ -74,7 +84,6 @@ class Peers extends Component {
</header>
<div className={styles.search}>
<label className={`${styles.label} ${styles.input}`} htmlFor='channelSearch'>
<MdSearch />
</label>
@ -89,10 +98,13 @@ class Peers extends Component {
</div>
<div className={styles.refreshContainer}>
<span className={`${styles.refresh} hint--top`} data-hint='Refresh your peers list'>
<FaRepeat
onClick={refreshClicked}
/>
<span className={styles.refresh} onClick={refreshClicked} ref='repeat'>
{
this.state.refreshing ?
<FaRepeat />
:
'Refresh'
}
</span>
</div>
@ -107,7 +119,18 @@ class Peers extends Component {
}
Peers.propTypes = {
fetchPeers: PropTypes.func.isRequired,
peerFormProps: PropTypes.object.isRequired,
setPeerForm: PropTypes.func.isRequired,
setPeer: PropTypes.func.isRequired,
updateSearchQuery: PropTypes.func.isRequired,
disconnectRequest: PropTypes.func.isRequired,
peerModalOpen: PropTypes.bool.isRequired,
filteredPeers: PropTypes.array.isRequired,
peers: PropTypes.object.isRequired,
peer: PropTypes.object,
searchQuery: PropTypes.string
}
export default Peers

55
app/routes/peers/components/Peers.scss

@ -1,7 +1,7 @@
@import '../../../variables.scss';
.search {
height: 75px;
height: 55px;
padding: 2px 25px;
border-top: 1px solid $darkgrey;
border-bottom: 1px solid $darkgrey;
@ -15,8 +15,8 @@
.label {
width: 5%;
line-height: 70px;
font-size: 25px;
line-height: 50px;
font-size: 20px;
text-align: center;
cursor: pointer;
}
@ -27,8 +27,8 @@
padding: 0;
border: 0;
border-radius: 0;
height: 68px;
font-size: 18px;
height: 50px;
font-size: 16px;
}
}
@ -36,58 +36,43 @@
display: flex;
flex-direction: row;
justify-content: space-between;
background: $lightgrey;
.titleContainer {
padding: 40px;
padding: 20px 40px;
.left {
padding: 10px 0;
}
.left, span {
display: inline-block;
}
.identityPubkey {
font-size: 30px;
margin-right: 10px;
display: flex;
flex-direction: row;
.userIcon {
margin-right: 10px;
}
section h4 {
font-size: 10px;
h1 {
text-transform: uppercase;
letter-spacing: 1.2px;
}
section h2 {
font-size: 14px;
margin-top: 5px;
font-size: 26px;
margin-right: 5px;
}
}
}
.addPeerContainer {
padding: 40px;
padding: 20px 40px;
.newPeerButton {
font-size: 14px;
margin-left: 10px;
}
}
}
.refreshContainer {
display: flex;
flex-direction: row;
padding: 20px 40px 0px 40px;
padding: 20px 40px 0 40px;
text-align: right;
cursor: pointer;
.refresh {
cursor: pointer;
color: $bluegrey;
text-decoration: underline;
svg {
font-size: 12px;
}
}
}

2
app/routes/peers/containers/PeersContainer.js

@ -1,7 +1,7 @@
import { withRouter } from 'react-router'
import { connect } from 'react-redux'
import {
import {
fetchPeers,
setPeer,
setPeerForm,

1
app/variables.scss

@ -11,6 +11,7 @@ $darkestgrey: #999999;
$bluegrey: #555459;
$green: #0bb634;
$terminalgreen: #00FF00;
$red: #ff0b00;
$blue: #007bb6;
$curve: cubic-bezier(0.650, 0.000, 0.450, 1.000);

8
package.json

@ -202,7 +202,6 @@
"prop-types": "^15.5.10",
"qrcode.react": "^0.7.1",
"react": "^15.6.1",
"react-addons-css-transition-group": "^15.6.0",
"react-dom": "^15.6.1",
"react-hot-loader": "3.0.0-beta.6",
"react-inlinesvg": "^0.6.2",
@ -212,18 +211,13 @@
"react-router": "^4.1.1",
"react-router-dom": "^4.1.1",
"react-router-redux": "^5.0.0-alpha.6",
"react-svg": "^2.1.21",
"react-svg-morph": "^0.1.10",
"react-vis-force": "^0.3.1",
"react-websocket": "^1.1.7",
"redux": "^3.7.1",
"redux-electron-ipc": "^1.1.10",
"redux-thunk": "^2.2.0",
"reselect": "^3.0.1",
"satoshi-bitcoin": "^1.0.4",
"source-map-support": "^0.4.15",
"xtend": "^4.0.1",
"zbase32": "^0.0.2"
"xtend": "^4.0.1"
},
"devEngines": {
"node": ">=7.x",

BIN
resources/bin/darwin/lnd

Binary file not shown.

BIN
resources/bin/linux/lnd

Binary file not shown.

BIN
resources/bin/win32/lnd.exe

Binary file not shown.

51
resources/zap_2.svg

@ -1,51 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="128" height="128" viewBox="0 0 100 100">
<defs>
<g id="background">
<path fill="url(#background-gradient)" stroke="none" d=" M 90.75 23.05 Q 89.5 23.05 88.85 24.15 88.15 25.25 88.85 26.35 97.25 40.2 95.15 56.15 93.05 71.65 81.75 82.6 70.35 93.7 54.9 95.25 32.95 97.55 17.6 81.85 2.2 66.2 4.85 44.2 6.6 30.2 16.15 19.7 25.65 9.1 39.25 5.8 50.55 3 61.7 5.95 62.85 6.3 63.7 5.65 64.6 5 64.6 3.85 64.6 2.25 62.95 1.7 52.55 -1.1 41.6 0.65 25.55 3.3 14.4 14.85 3.1 26.25 0.65 42.4 -2.95 66.9 14 84.5 30.85 102.1 55.2 99.7 72.6 97.9 85.2 85.4 97.95 72.8 99.7 55.35 101.45 38.55 92.75 24.05 92.05 23.05 90.75 23.05 Z"/>
</g><mask id="mask">
<path fill="#FFFFFF" stroke="none" d=" M 82.2 82.15 Q 95.5 68.85 95.5 49.95 95.5 31.1 82.2 17.8 68.85 4.5 50 4.5 31.15 4.5 17.8 17.8 4.5 31.1 4.5 49.95 4.5 68.85 17.8 82.15 31.15 95.45 50 95.45 68.85 95.45 82.2 82.15 Z"/>
</mask>
<linearGradient id="background-gradient" x1="0" y1="0" y2="1" x2="0" >
<stop stop-color="#1d1d1d" offset="0%"/>
<stop stop-color="#ebb864" offset="100%"/>
</linearGradient>
<g transform="scale(2.0833333333333335)" id="picture"><path d="M38 8c-.8 0-1.5.1-2.2.3C33.6 3.4 28.7 0 23 0 15.9 0 10.1 5.3 9.1 12.1 8.8 12 8.4 12 8 12c-4.4 0-8 3.6-8 8s3.6 8 8 8h30c5.5 0 10-4.5 10-10S43.5 8 38 8zm0 18H8c-3.3 0-6-2.7-6-6s2.7-6 6-6c.3 0 .5 0 .9.1l2 .3.3-2C11.9 6.5 17 2 23 2c4.7 0 9 2.8 10.9 7.1l.7 1.5 1.6-.4c.6-.1 1.2-.2 1.8-.2 4.4 0 8 3.6 8 8s-3.6 8-8 8zm-10.7 8l1.9-4H18.7L16 35.5c-.1.2 0 .5.3.5h4.5L16 47.8c0 .1 0 .2.1.2 0 0 .1 0 .2-.1l15.6-13.6c.2-.2.2-.3-.1-.3h-4.5zm-3.9 3.8l.3-.6.1-.1h.6l-1 .7z"/></g>
<linearGradient id="picture-gradient" x1="0" y1="0" y2="1" x2="0" >
<stop stop-color="#1d1d1d" offset="0%"/>
<stop stop-color="#ebb864" offset="100%"/>
</linearGradient>
</defs>
<use xlink:href="#background" fill="url(#background-gradient)" />
<g mask="url(#mask)">
<g transform="
translate(
50 50
)
translate(0 0) scale(0.5)
translate(
-50 -50
)">
<use xlink:href="#picture" fill="url(#picture-gradient)" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

95
yarn.lock

@ -1837,10 +1837,6 @@ center-align@^0.1.1:
align-text "^0.1.3"
lazy-cache "^1.0.3"
chain-function@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc"
chainsaw@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98"
@ -2532,31 +2528,6 @@ currently-unhandled@^0.4.1:
dependencies:
array-find-index "^1.0.1"
d3-collection@1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.4.tgz#342dfd12837c90974f33f1cc0a785aea570dcdc2"
d3-dispatch@1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.3.tgz#46e1491eaa9b58c358fce5be4e8bed626e7871f8"
d3-force@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.1.0.tgz#cebf3c694f1078fcc3d4daf8e567b2fbd70d4ea3"
dependencies:
d3-collection "1"
d3-dispatch "1"
d3-quadtree "1"
d3-timer "1"
d3-quadtree@1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.3.tgz#ac7987e3e23fe805a990f28e1b50d38fcb822438"
d3-timer@1:
version "1.0.7"
resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.7.tgz#df9650ca587f6c96607ff4e60cc38229e8dd8531"
d@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
@ -2778,10 +2749,6 @@ dom-converter@~0.1:
dependencies:
utila "~0.3"
dom-helpers@^3.2.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a"
dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
@ -5603,7 +5570,7 @@ lodash.range@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/lodash.range/-/lodash.range-3.2.0.tgz#f461e588f66683f7eadeade513e38a69a565a15d"
lodash.reduce@^4.4.0, lodash.reduce@^4.6.0:
lodash.reduce@^4.4.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b"
@ -6973,7 +6940,7 @@ promise@^7.1.1:
dependencies:
asap "~2.0.3"
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.8:
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8:
version "15.5.10"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
dependencies:
@ -7096,12 +7063,6 @@ rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.1.7, rc@^1.2.1:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
react-addons-css-transition-group@^15.6.0:
version "15.6.0"
resolved "https://registry.yarnpkg.com/react-addons-css-transition-group/-/react-addons-css-transition-group-15.6.0.tgz#69887cf6e4874d25cd66e22a699e29f0d648aba0"
dependencies:
react-transition-group "^1.2.0"
react-addons-test-utils@^15.6.0:
version "15.6.0"
resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.6.0.tgz#062d36117fe8d18f3ba5e06eb33383b0b85ea5b9"
@ -7182,10 +7143,6 @@ react-redux@^5.0.5:
loose-envify "^1.1.0"
prop-types "^15.5.10"
react-render-to-json@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/react-render-to-json/-/react-render-to-json-0.0.4.tgz#0db588e2952cea05a66a3390554c46c3ea74d006"
react-router-dom@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.1.1.tgz#3021ade1f2c160af97cf94e25594c5f294583025"
@ -7215,19 +7172,6 @@ react-router@^4.1.1:
prop-types "^15.5.4"
warning "^3.0.0"
react-svg-morph@^0.1.10:
version "0.1.10"
resolved "https://registry.yarnpkg.com/react-svg-morph/-/react-svg-morph-0.1.10.tgz#780cf6823a6ab640a1367e43b7c9509d68157bf3"
dependencies:
react-render-to-json "0.0.4"
svgpath "^2.1.0"
react-svg@^2.1.21:
version "2.1.21"
resolved "https://registry.yarnpkg.com/react-svg/-/react-svg-2.1.21.tgz#0caf34002649542967f04e197480d784768e914c"
dependencies:
svg-injector "^1.1.3"
react-test-renderer@^15.6.1:
version "15.6.1"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-15.6.1.tgz#026f4a5bb5552661fd2cc4bbcd0d4bc8a35ebf7e"
@ -7246,29 +7190,6 @@ react-transform-hmr@^1.0.3:
global "^4.3.0"
react-proxy "^1.1.7"
react-transition-group@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-1.2.0.tgz#b51fc921b0c3835a7ef7c571c79fc82c73e9204f"
dependencies:
chain-function "^1.0.0"
dom-helpers "^3.2.0"
loose-envify "^1.3.1"
prop-types "^15.5.6"
warning "^3.0.0"
react-vis-force@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/react-vis-force/-/react-vis-force-0.3.1.tgz#c7bc96a4e872409f5d4c0fa93fe89c94554d47b7"
dependencies:
d3-force "^1.0.2"
global "^4.3.0"
lodash.reduce "^4.6.0"
prop-types "^15.5.10"
react-websocket@^1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/react-websocket/-/react-websocket-1.1.7.tgz#0a761f3de354d4731f55343456e03b1f6005b492"
react@^15.6.1:
version "15.6.1"
resolved "https://registry.yarnpkg.com/react/-/react-15.6.1.tgz#baa8434ec6780bde997cdc380b79cd33b96393df"
@ -8388,10 +8309,6 @@ supports-color@^4.2.1:
dependencies:
has-flag "^2.0.0"
svg-injector@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/svg-injector/-/svg-injector-1.1.3.tgz#8fba18d7419e5f818e712c4f82d83ee357610e61"
svg-tags@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
@ -8408,10 +8325,6 @@ svgo@^0.7.0:
sax "~1.2.1"
whet.extend "~0.9.9"
svgpath@^2.1.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/svgpath/-/svgpath-2.2.1.tgz#0834bb67c89a76472b2bd06cc101fa7b517b222c"
symbol-observable@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
@ -9376,10 +9289,6 @@ yauzl@2.4.1:
dependencies:
fd-slicer "~1.0.1"
zbase32@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/zbase32/-/zbase32-0.0.2.tgz#169c6f2130a6c27a84247017538b56826a54b283"
zip-stream@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.1.1.tgz#5216b48bbb4d2651f64d5c6e6f09eb4a7399d557"

Loading…
Cancel
Save