Lightning.vue
1 <template lang='pug'> 2 3 #nodes 4 div node stuff 5 .breathing 6 .boxy(v-if='$store.state.cash.info.id') 7 div {{ $store.state.cash.info.alias}} 8 .nodeaddress {{ $store.state.cash.info.id }} 9 span @{{ $store.state.cash.info.address }} 10 button.ptr(@click='clicktopay') deposit 11 .price(v-if='sats > 0') 1 CAD = {{ sats }} sats 12 .price(v-else) 1 Bitcoin = 100 000 000 sats 13 .flexrow 14 .third 15 block-info 16 .twothirds.boxy(v-if='$store.state.cash.info.channels') 17 .section(v-if='$store.state.cash.info.id') {{ $store.state.cash.info.channels.length }} ⚡channels 18 div(v-if='Math.abs($store.state.cash.info.lightningblocks - $store.state.cash.info.bitcoinblocks) > 1') warning: desync detected 19 .row.channellimiter 20 .chanfo(v-if='selectedPeer < 0') pubkey: {{ $store.state.cash.info.id }} 21 .ptr(v-for='(n, i) in $store.state.cash.info.channels' :key='n.peer_id') 22 .localremote.bordy(v-show='selectedPeer === i' @click='selectedPeer = false') 23 .localbar.tall(:style='l(n)' :class='{abnormal:n.state !== "CHANNELD_NORMAL"}') {{ (n.amount_msat ).toLocaleString() }} 24 .remotebar.tall(:style='r(n)' :class='{abnormal:n.state !== "CHANNELD_NORMAL"}') {{ ( n.amount_msat - n.our_amount_msat ).toLocaleString() }} 25 .localremote(v-show='selectedPeer !== i' @click='selectPeer(i)') 26 .localbar(:style='l(n, true)' :class='{abnormal:n.state !== "CHANNELD_NORMAL"}') 27 .remotebar(:style='r(n, true)' :class='{abnormal:n.state !== "CHANNELD_NORMAL"}') 28 .chanfo(v-if='selectedPeer >= 0 && areChannels && selectedChannel') 29 label Channel Info: 30 div nodeid: {{ fetchedPeer.nodeid }} 31 div alias: {{fetchedPeer.alias}} 32 div(@click='checkTxid(selectedChannel.funding_txid)') txid: {{ selectedChannel.funding_txid }} 33 div(v-if='selectedChannel.state !== "CHANNELD_NORMAL"') state: {{ selectedChannel.state }} 34 div in: {{ fetchedPeer.channel.in_payments_fulfilled }} / {{ fetchedPeer.channel.in_payments_offered }} out: {{ fetchedPeer.channel.out_payments_fulfilled }} / {{ fetchedPeer.channel.out_payments_offered }} 35 // input(v-model='txnCheck' type='text' placeholder='check txid' @keypress.enter='checkTxid(txnCheck)') 36 // button(v-if='txnCheck' @click='checkTxid(txnCheck)') get transaction 37 </template> 38 39 <script> 40 41 import calculations from '../calculations' 42 import request from 'superagent' 43 import BlockInfo from './BlockInfo.vue' 44 export default { 45 components: { BlockInfo }, 46 data(){ 47 return { 48 showOutputs: false, 49 fetchedTxn: {}, 50 fetchedPeer: {}, 51 txnCheck: '', 52 selectedPeer: false, 53 open: false, 54 sampleIndex: 0, 55 } 56 }, 57 computed: { 58 confirmedBalance(){ 59 let cb = 0 60 this.$store.state.cash.info.outputs.forEach(o => { 61 if (o.status === "confirmed"){ 62 cb += o.value 63 } 64 }) 65 return cb 66 }, 67 selectedChannel(){ 68 return this.$store.state.cash.info.channels[this.selectedPeer] 69 }, 70 filteredOut(){ 71 if (this.fetchedTxn.utxo){ 72 let unspents = this.fetchedTxn.utxo.filter(x => x !== null).map(x => x.txid) 73 return this.fetchedTxn.vout.filter( y => { 74 return unspents.indexOf(y.txid) === -1 75 }) 76 } else { 77 return this.fetchedTxn.vout.filter(() => true) 78 } 79 }, 80 fetchedTxnStatus(){ 81 if (this.fetchedTxn.memPool){ 82 return 'unconfirmed' 83 } 84 if (this.fetchedTxn.utxo){ 85 return 'confirmed, unspent' 86 } 87 return 'confirmed, spent' 88 }, 89 areChannels(){ 90 return this.$store.state.cash.info.channels 91 }, 92 sats(){ 93 return calculations.cadToSats(1, this.$store.state.cash.spot) 94 }, 95 nn(){ 96 let totals = { 97 channel_sat: 0, 98 channel_total_sat: 0, 99 } 100 this.$store.state.cash.info.channels.forEach(n => { 101 if (n.state === "CHANNELD_NORMAL"){ 102 totals.channel_sat += n.our_amount_msat 103 totals.channel_total_sat += n.amount_msat 104 } 105 }) 106 if (totals.channel_sat + totals.channel_total_sat === 0){ 107 totals.channel_sat = 0 108 totals.channel_total_sat = 0 109 } 110 return totals 111 } 112 }, 113 methods:{ 114 clicktopay(){ 115 this.$store.commit("toggleNodeInfo") 116 this.$store.commit("setMode", 3) 117 this.$store.commit("setPayMode", 0) 118 if (!this.$store.getters.contextCard.btcAddr){ 119 this.$store.dispatch("makeEvent", { 120 type: 'address-updated', 121 taskId: this.$store.getters.contextCard.taskId 122 }) 123 124 } 125 }, 126 checkPeer(x){ 127 request 128 .post('/lightning/peer') 129 .send({pubkey: x}) 130 .set("Authorization", this.$store.state.loader.token) 131 .end( (err, res) => { 132 if (!err) { 133 this.fetchedPeer = res.body 134 } 135 }) 136 }, 137 checkTxid(x){ 138 request 139 .post('/bitcoin/transaction') 140 .send({txid : x}) 141 .set("Authorization", this.$store.state.loader.token) 142 .end((err, res)=>{ 143 if (!err){ 144 this.fetchedTxn = res.body 145 } 146 }) 147 this.txnCheck = '' 148 }, 149 selectPeer(pId){ 150 if (pId === this.selectedPeer){ 151 return this.selectedPeer = false 152 } 153 this.selectedPeer = pId 154 this.checkPeer(this.selectedChannel.peer_id) 155 }, 156 r(n, nolimits){ 157 let local = n.our_amount_msat 158 159 let remote = n.amount_msat - n.our_amount_msat 160 161 let capacity = local + remote 162 let remotePercent = remote / capacity 163 164 if (!nolimits && remotePercent < 0.2 && remotePercent > 0) { 165 remotePercent = 0.2 166 } 167 if (!nolimits && remotePercent < 1 && remotePercent > 0.8) { 168 remotePercent = 0.8 169 } 170 171 let w = (remotePercent * 100).toFixed(7) + "%" 172 return { 173 width: w 174 } 175 }, 176 l(n, nolimits){ 177 let local = n.our_amount_msat 178 let remote = n.amount_msat - local 179 180 let capacity = local + remote 181 let localPercent = n.channel_sat / capacity 182 183 if (!nolimits && localPercent > 0.8 && localPercent < 1) { 184 localPercent = 0.8 185 } 186 if (!nolimits && localPercent > 0 && localPercent < 0.2) { 187 localPercent = 0.2 188 } 189 let w = (localPercent * 100).toFixed(7) + "%" 190 return { 191 width: w 192 } 193 }, 194 } 195 } 196 </script> 197 198 <style lang='stylus' scoped> 199 200 @import '../styles/colours' 201 @import '../styles/button' 202 @import '../styles/input' 203 .flexrow 204 display: flex 205 206 .third 207 flex: 1 1 auto 208 .twothirds 209 flex: 4 4 auto 210 .price 211 text-align: center 212 padding-bottom: .9em 213 214 .nodeaddress 215 line-break: anywhere 216 217 .boxy 218 box-shadow: 0 3px 10px rgb(0 0 0 / 0.2) 219 padding: .378em 220 margin-bottom: 1em 221 222 .bordy 223 margin-top:0.2em 224 margin-left: 0.25em 225 226 .fr 227 float: right 228 229 .bg 230 background: lightGrey 231 padding: 0.33em 232 border-radius: 3% 233 234 .section 235 color:main 236 font-size: 0.9em 237 margin-bottom: .9em 238 text-align: left 239 240 .chanfo 241 word-break: break-all 242 overflow-wrap: break-word; 243 text-align: left 244 .ptr 245 cursor: pointer 246 247 .localbar.tall 248 height: 2em 249 .remotebar.tall 250 height: 2em 251 252 #nodes 253 overflow-y: scroll; 254 max-height: 100vh; 255 position: relative; 256 right: 0; 257 margin-bottom: 5em; 258 bottom: 0; 259 background-color: rgba(228,241,242,.667); 260 padding: 2em; 261 262 .inactive 263 opacity: 0.3456 264 265 .center 266 text-align: center 267 word-break: break-all 268 overflow-wrap: break-word; 269 font-size: 0.5em 270 271 .center.nowx 272 margin-top: 0.3em 273 margin-bottom: 0.3em 274 height: 2em 275 276 .fw 277 width: 100% 278 279 .container 280 content-align: center 281 282 h3 283 text-align: center 284 285 a 286 color: purple 287 288 h1 289 text-align: center 290 291 .h 292 height: 2em 293 294 label 295 word-break: break-all 296 297 .break 298 overflow-wrap: break-word; 299 300 #worf 301 height: 23em 302 303 #palm 304 width:110% 305 306 .setupyourown 307 margin-top: 2.2345em 308 padding: 2em 309 color: purple 310 font-size: 1.12em 311 312 .small 313 font-size: .68em 314 word-break: break-all 315 316 p 317 text-align: center 318 319 .fl 320 float: left 321 .fr 322 float: right 323 324 .local 325 margin: 0 0 .1em 0 326 background: lightGrey 327 padding: 1em 328 text-align: center 329 330 .remote 331 margin: 0 0 .1em 0 332 background: none 333 text-align: right 334 padding: 1em 335 text-align: center 336 337 .chain 338 // height: 1.7em 339 // margin: 0 340 // text-align: center 341 // position: relative 342 // padding-top: 0.6em 343 // opacity: 0.8 344 345 .outputs 346 cursor: pointer 347 348 .break 349 overflow-wrap: break-word; 350 351 #worf 352 float: right 353 354 .lim 355 color: black 356 357 .block 358 float: right 359 font-size: .77em 360 361 h5 362 text-align: center 363 color: lightGrey 364 opacity: 0.77 365 366 .bdoge 367 width: 100% 368 opacity: 0.77 369 height: 5em 370 margin-top: 1em 371 372 .localremote 373 width: 100% 374 height: 0.622em 375 376 .localbar 377 height: 0.622em 378 float: left 379 outline-right: solid 380 background: linear-gradient(to right, wrexno 0%, wrexno 98.1337%, black 98.1337%, black) 381 padding-top: 0.23em 382 383 384 .localbar.abnormal 385 background: red 386 387 .remotebar 388 height: 0.622em 389 float: right 390 padding-top: 0.23em 391 .remotebar.abnormal 392 background: red 393 394 .breathing 395 height: 3.5em 396 397 .breathing1 398 height: 1.35em 399 .spacer 400 padding-top: 3.21em 401 margin-bottom: .7654321em 402 .sampler 403 cursor: pointer 404 .channellimiter 405 max-height: 13em 406 overflow-y: scroll; 407 </style> 408