better wallet
This commit is contained in:
Generated
+13
@@ -3724,6 +3724,11 @@
|
|||||||
"minimalistic-crypto-utils": "^1.0.0"
|
"minimalistic-crypto-utils": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"emitter-component": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-Bl4tvtaVm/RwZ57avq95gdEAOrY="
|
||||||
|
},
|
||||||
"emoji-regex": {
|
"emoji-regex": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
||||||
@@ -9138,6 +9143,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||||
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
|
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
|
||||||
},
|
},
|
||||||
|
"stream": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/stream/-/stream-0.0.2.tgz",
|
||||||
|
"integrity": "sha1-f1Nj8Ff2WSxVlfALyAon9c7B8O8=",
|
||||||
|
"requires": {
|
||||||
|
"emitter-component": "^1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"stream-browserify": {
|
"stream-browserify": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"key-file-storage": "^2.2.4",
|
"key-file-storage": "^2.2.4",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"rxjs": "~6.5.2",
|
"rxjs": "~6.5.2",
|
||||||
|
"stream": "0.0.2",
|
||||||
"systemjs": "^0.21.3",
|
"systemjs": "^0.21.3",
|
||||||
"tslib": "^1.9.0",
|
"tslib": "^1.9.0",
|
||||||
"uuid": "^3.3.2",
|
"uuid": "^3.3.2",
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ declare const fb
|
|||||||
<clr-dg-row *clrDgItems="let line of plugins">
|
<clr-dg-row *clrDgItems="let line of plugins">
|
||||||
<clr-dg-cell>{{line.name}}</clr-dg-cell>
|
<clr-dg-cell>{{line.name}}</clr-dg-cell>
|
||||||
<clr-dg-cell>
|
<clr-dg-cell>
|
||||||
<span *ngIf="line.installed != line.available" class="label label-light-blue">{{line.available}}</span>
|
<span *ngIf="line.installed != line.available" class="label info">{{line.available}}</span>
|
||||||
<span *ngIf="line.installed == line.available">{{line.available}}</span>
|
<span *ngIf="line.installed == line.available">{{line.available}}</span>
|
||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
<clr-dg-cell>{{line.installed}}</clr-dg-cell>
|
<clr-dg-cell>{{line.installed}}</clr-dg-cell>
|
||||||
|
|||||||
@@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
import { Component, OnInit, isDevMode } from '@angular/core';
|
import { Component, OnInit, isDevMode } from '@angular/core';
|
||||||
import { PluginsComponent } from './btc.component';
|
import { PluginsComponent } from './btc.component';
|
||||||
|
import { ClrDatagridStringFilterInterface, ClrDatagridNumericFilterInterface, ClrDropdownModule } from '@clr/angular';
|
||||||
declare const fb
|
declare const fb
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'address-viewer', //!!!!
|
selector: 'address-viewer', //!!!!
|
||||||
template: `
|
template: `
|
||||||
|
<div class="clr-row">
|
||||||
|
<div *ngIf="regularAddresses.length != 0" class="clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-12 clr-col-xl-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Addresses
|
Addresses
|
||||||
@@ -20,23 +23,37 @@ declare const fb
|
|||||||
|
|
||||||
<clr-datagrid class="datagrid-compact ">
|
<clr-datagrid class="datagrid-compact ">
|
||||||
<clr-dg-column>Address</clr-dg-column>
|
<clr-dg-column>Address</clr-dg-column>
|
||||||
<clr-dg-column>Balance</clr-dg-column>
|
<clr-dg-column>
|
||||||
<clr-dg-column>Pending</clr-dg-column>
|
Balance
|
||||||
<clr-dg-column>Estimate total</clr-dg-column>
|
</clr-dg-column>
|
||||||
|
<clr-dg-column>
|
||||||
|
Pending
|
||||||
|
</clr-dg-column>
|
||||||
|
<clr-dg-column>
|
||||||
|
Estimate total
|
||||||
|
<clr-dg-numeric-filter [clrDgNumericFilter]="otherBalanceFilter" [clrFilterValue]="[0, null]"></clr-dg-numeric-filter>
|
||||||
|
</clr-dg-column>
|
||||||
|
|
||||||
<clr-dg-row *clrDgItems="let line of regularAddresses">
|
<clr-dg-row *clrDgItems="let line of regularAddresses">
|
||||||
<clr-dg-cell style="word-break: break-all">{{line.address}}</clr-dg-cell>
|
<clr-dg-cell class="monospace" style="word-break: break-all">{{line.address}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{line.confirmed.balance}}</clr-dg-cell>
|
<clr-dg-cell class="monospace">{{line.confirmed.balance | number: '1.8-18'}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{line.unconfirmed.balance}}</clr-dg-cell>
|
<clr-dg-cell class="monospace">
|
||||||
<clr-dg-cell>{{line.total.balance}}</clr-dg-cell>
|
<span *ngIf="line.unconfirmed.balance != 0">
|
||||||
|
{{line.unconfirmed.balance | number: '1.8-18'}}
|
||||||
|
</span>
|
||||||
|
</clr-dg-cell>
|
||||||
|
<clr-dg-cell class="monospace">{{line.total.balance | number: '1.8-18'}}</clr-dg-cell>
|
||||||
|
|
||||||
<clr-dg-row-detail *clrIfExpanded >
|
<clr-dg-row-detail *clrIfExpanded >
|
||||||
<div class="clr-row">
|
<div class="clr-row">
|
||||||
<div class="clr-col-3">
|
<div class="clr-col-3">
|
||||||
<button class="btn btn-info-outline">Explorer</button>
|
<button class="btn btn-info-outline" (click)="parent.addrExplorer(line.address)">Explorer</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="parent.keys[line.address] != null" class="clr-col-9" style="word-break:break-all">
|
<div *ngIf="parent.keys[line.address] != null" class="clr-col-9" style="word-break:break-all">
|
||||||
<h6 style="margin-top: 0"> Public key </h6>
|
<h6 style="margin-top: 0">Derivation </h6>
|
||||||
|
{{parent.keys[line.address].derivation}}
|
||||||
|
<h6> Public key </h6>
|
||||||
{{parent.keys[line.address].publicExtendedKey}}
|
{{parent.keys[line.address].publicExtendedKey}}
|
||||||
<h6> Private key </h6>
|
<h6> Private key </h6>
|
||||||
{{parent.keys[line.address].privateExtendedKey}}
|
{{parent.keys[line.address].privateExtendedKey}}
|
||||||
@@ -46,33 +63,63 @@ declare const fb
|
|||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
|
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="5">
|
<clr-dg-pagination #pagination2 [clrDgPageSize]="10">
|
||||||
<clr-dg-page-size [clrPageSizeOptions]="[5,10,20,50,100]">per page</clr-dg-page-size>
|
<clr-dg-page-size [clrPageSizeOptions]="[5,10,20,50,100]">per page</clr-dg-page-size>
|
||||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
{{pagination2.firstItem + 1}} - {{pagination2.lastItem + 1}}
|
||||||
of {{pagination.totalItems}}
|
of {{pagination2.totalItems}}
|
||||||
</clr-dg-pagination>
|
</clr-dg-pagination>
|
||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="changeAddresses.length != 0" class="clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-12 clr-col-xl-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
Change Addresses
|
||||||
|
</div>
|
||||||
|
<clr-alert *ngFor="let entry of alerts" [clrAlertType]="line.severity">
|
||||||
|
<clr-alert-item>
|
||||||
|
<span class="alert-text">
|
||||||
|
{{line.message}}
|
||||||
|
</span>
|
||||||
|
</clr-alert-item>
|
||||||
|
</clr-alert>
|
||||||
|
|
||||||
<clr-datagrid class="datagrid-compact">
|
<clr-datagrid class="datagrid-compact">
|
||||||
<clr-dg-column>Address</clr-dg-column>
|
<clr-dg-column>Address</clr-dg-column>
|
||||||
<clr-dg-column>Balance</clr-dg-column>
|
<clr-dg-column>
|
||||||
<clr-dg-column>Pending</clr-dg-column>
|
Balance
|
||||||
<clr-dg-column>Estimate total</clr-dg-column>
|
</clr-dg-column>
|
||||||
|
<clr-dg-column>
|
||||||
|
Pending
|
||||||
|
</clr-dg-column>
|
||||||
|
<clr-dg-column>
|
||||||
|
Estimate total
|
||||||
|
<clr-dg-numeric-filter [clrDgNumericFilter]="balanceFilter" [clrFilterValue]="[0.00000001, null]"></clr-dg-numeric-filter>
|
||||||
|
</clr-dg-column>
|
||||||
|
|
||||||
<clr-dg-row *clrDgItems="let line of changeAddresses">
|
<clr-dg-row *clrDgItems="let line of changeAddresses">
|
||||||
<clr-dg-cell style="word-break: break-all">{{line.address}}</clr-dg-cell>
|
<clr-dg-cell class="monospace" style="word-break: break-all">{{line.address}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{line.confirmed.balance}}</clr-dg-cell>
|
<clr-dg-cell class="monospace">{{line.confirmed.balance | number: '1.8-18'}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{line.unconfirmed.balance}}</clr-dg-cell>
|
<clr-dg-cell class="monospace">
|
||||||
<clr-dg-cell>{{line.total.balance}}</clr-dg-cell>
|
<span *ngIf="line.unconfirmed.balance != 0">
|
||||||
|
{{line.unconfirmed.balance | number: '1.8-18'}}
|
||||||
|
</span>
|
||||||
|
</clr-dg-cell>
|
||||||
|
<clr-dg-cell class="monospace">{{line.total.balance | number: '1.8-18'}}</clr-dg-cell>
|
||||||
|
|
||||||
<clr-dg-row-detail *clrIfExpanded >
|
<clr-dg-row-detail *clrIfExpanded >
|
||||||
<div class="clr-row">
|
<div class="clr-row">
|
||||||
<div class="clr-col-3">
|
<div class="clr-col-3">
|
||||||
<button class="btn btn-info-outline">Explorer</button>
|
<button class="btn btn-info-outline" (click)="parent.addrExplorer(line.address)">Explorer</button>
|
||||||
|
<p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="parent.keys[line.address] != null" class="clr-col-9" style="word-break:break-all">
|
<div *ngIf="parent.keys[line.address] != null" class="clr-col-9" style="word-break:break-all">
|
||||||
<h6 style="margin-top: 0"> Public key </h6>
|
<h6 style="margin-top: 0">Derivation </h6>
|
||||||
|
{{parent.keys[line.address].derivation}}
|
||||||
|
<h6> Public key </h6>
|
||||||
{{parent.keys[line.address].publicExtendedKey}}
|
{{parent.keys[line.address].publicExtendedKey}}
|
||||||
<h6> Private key </h6>
|
<h6> Private key </h6>
|
||||||
{{parent.keys[line.address].privateExtendedKey}}
|
{{parent.keys[line.address].privateExtendedKey}}
|
||||||
@@ -82,7 +129,7 @@ declare const fb
|
|||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
|
|
||||||
<clr-dg-footer>
|
<clr-dg-footer>
|
||||||
<clr-dg-pagination #pagination [clrDgPageSize]="5">
|
<clr-dg-pagination #pagination [clrDgPageSize]="10">
|
||||||
<clr-dg-page-size [clrPageSizeOptions]="[5,10,20,50,100]">per page</clr-dg-page-size>
|
<clr-dg-page-size [clrPageSizeOptions]="[5,10,20,50,100]">per page</clr-dg-page-size>
|
||||||
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
|
||||||
of {{pagination.totalItems}}
|
of {{pagination.totalItems}}
|
||||||
@@ -90,10 +137,13 @@ declare const fb
|
|||||||
</clr-dg-footer>
|
</clr-dg-footer>
|
||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class AddressViewerComponent implements OnInit{
|
export class AddressViewerComponent implements OnInit{
|
||||||
|
balanceFilter = new BalanceFilter()
|
||||||
|
otherBalanceFilter = new BalanceFilter()
|
||||||
regularAddresses = []
|
regularAddresses = []
|
||||||
changeAddresses = []
|
changeAddresses = []
|
||||||
keys = {}
|
keys = {}
|
||||||
@@ -113,3 +163,12 @@ export class AddressViewerComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class BalanceFilter implements ClrDatagridNumericFilterInterface<any>{
|
||||||
|
accepts(item: any, low: number, high: number): boolean {
|
||||||
|
high = parseFloat(""+high)
|
||||||
|
low = parseFloat(""+low)
|
||||||
|
const balance = (parseFloat(item.unconfirmed.balance) + parseFloat(item.confirmed.balance))
|
||||||
|
return (Number.isNaN(low) || balance >= low)
|
||||||
|
&& (Number.isNaN(high) || balance <= high)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import { HDKey } from "btc-hdkey"
|
|||||||
import { AddressViewerComponent } from './address-viewer.component';
|
import { AddressViewerComponent } from './address-viewer.component';
|
||||||
const fetch = require("node-fetch")
|
const fetch = require("node-fetch")
|
||||||
const coinselect = require('coinselect/accumulative')
|
const coinselect = require('coinselect/accumulative')
|
||||||
import { TransactionBuilder } from 'bitcoinjs-lib'
|
import { TransactionBuilder, Signer } from 'bitcoinjs-lib'
|
||||||
import { networks } from 'bitcoinjs-lib'
|
import { networks } from 'bitcoinjs-lib'
|
||||||
let feeRate = 55 // satoshis per byte
|
let feeRate = 55 // satoshis per byte
|
||||||
|
|
||||||
@@ -17,8 +17,43 @@ declare const fb
|
|||||||
|
|
||||||
<wallet-generator></wallet-generator>
|
<wallet-generator></wallet-generator>
|
||||||
|
|
||||||
|
<!-- loading -->
|
||||||
|
<clr-modal [clrModalSize]="'md'" [(clrModalOpen)]="loading">
|
||||||
|
|
||||||
|
<div class="modal-body ">
|
||||||
|
<span class="spinner spinner-inverse spinner-md">
|
||||||
|
Loading...
|
||||||
|
</span>
|
||||||
|
<h3>Checking addresses</h3> <br>
|
||||||
|
Checking the first {{loadingN*115}} addresses. <br>
|
||||||
|
Found addresses containing balance: {{regaddresses.length + changeaddresses.length}}
|
||||||
|
</div>
|
||||||
|
</clr-modal>
|
||||||
|
<!-- / loading -->
|
||||||
|
|
||||||
|
<!-- row 0 -->
|
||||||
|
<div *ngIf="mode.net == 'testnet'" class="clr-all-12">
|
||||||
|
<div class="card">
|
||||||
|
|
||||||
|
<div class="card-header">
|
||||||
|
Faucet
|
||||||
|
</div>
|
||||||
|
<div class="card-block" >
|
||||||
|
<button class="btn btn-icon btn-info-outline" onclick="window.open('https://testnet-faucet.mempool.co/', '_blank')"><clr-icon shape="fuel"></clr-icon></button>
|
||||||
|
<button class="btn btn-icon btn-info-outline" onclick="window.open('https://bitcoinfaucet.uo1.net/', '_blank')"><clr-icon shape="fuel"></clr-icon></button>
|
||||||
|
<button class="btn btn-icon btn-info-outline" onclick="window.open('https://coinfaucet.eu/en/btc-testnet/', '_blank')"><clr-icon shape="fuel"></clr-icon></button>
|
||||||
|
<button class="btn btn-icon btn-success-outline" onclick="window.open('https://www.google.com/search?q=btc+testnet+faucet&oq=btc+testnet+faucet', '_blank')"><clr-icon shape="plus"></clr-icon> more</button>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer" >
|
||||||
|
Get free test-BTC
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- row 1 -->
|
<!-- row 1 -->
|
||||||
<div class="clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-12 clr-col-xl-12">
|
<div class="clr-all-12">
|
||||||
|
|
||||||
<!-- wallet picker + send box + balance box -->
|
<!-- wallet picker + send box + balance box -->
|
||||||
<div class="clr-row">
|
<div class="clr-row">
|
||||||
@@ -28,26 +63,42 @@ declare const fb
|
|||||||
|
|
||||||
<!-- Wallet picker -->
|
<!-- Wallet picker -->
|
||||||
<div class="clr-row">
|
<div class="clr-row">
|
||||||
<walletpicker class="clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-12 clr-col-xl-12"></walletpicker>
|
<walletpicker class="clr-all-12"></walletpicker>
|
||||||
</div>
|
</div>
|
||||||
<!-- /Wallet picker -->
|
<!-- /Wallet picker -->
|
||||||
|
|
||||||
<!-- Send box -->
|
<!-- Send box -->
|
||||||
<div class="clr-row">
|
<div *ngIf="mode.type=='private'" class="clr-row">
|
||||||
|
|
||||||
<div class="clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-12 clr-col-xl-12">
|
<div class="clr-all-12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Send
|
Send
|
||||||
</div>
|
</div>
|
||||||
|
<clr-alert *ngFor="let error of errors" [clrAlertType]="'danger'">
|
||||||
|
<clr-alert-item>
|
||||||
|
<span class="alert-text">
|
||||||
|
{{error}}
|
||||||
|
</span>
|
||||||
|
</clr-alert-item>
|
||||||
|
</clr-alert>
|
||||||
|
<clr-alert *ngFor="let success of successes" [clrAlertType]="'success'">
|
||||||
|
<clr-alert-item>
|
||||||
|
<span class="alert-text">
|
||||||
|
{{success}}
|
||||||
|
</span>
|
||||||
|
</clr-alert-item>
|
||||||
|
</clr-alert>
|
||||||
<div class="card-block" >
|
<div class="card-block" >
|
||||||
<input [(ngModel)]="sendTo" type="text" placeholder="To address" clrInput />
|
|
||||||
<input [(ngModel)]="sendAmount" type="number" min="0" placeholder="Amount" clrInput />
|
|
||||||
|
|
||||||
|
<div class="clr-row" style="padding-left:12px; padding-right:12px">
|
||||||
|
<input [(ngModel)]="sendTo" type="text" placeholder="To address" class="clr-input clr-col-12" />
|
||||||
|
<input [(ngModel)]="sendAmount" type="text" min="0" placeholder="Amount" class="clr-input clr-col-12" style="margin-top:12px; margin-borrom:12px" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer" >
|
<div class="card-footer" >
|
||||||
<button class="btn btn-success-outline" (click)="createTx(sendTo, sendAmount)">send</button>
|
<button class="btn btn-success-outline" (click)="createAndSendTx(sendTo, sendAmount)">send</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -63,9 +114,9 @@ declare const fb
|
|||||||
<div class="clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-7 clr-col-xl-7" >
|
<div class="clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-7 clr-col-xl-7" >
|
||||||
|
|
||||||
<!-- Balance box -->
|
<!-- Balance box -->
|
||||||
<div class="card">
|
<div *ngIf="rootkey.publicExtendedKey != ''" class="card">
|
||||||
<div class="card-header" style="word-break: break-all">
|
<div class="card-header" style="word-break: break-all">
|
||||||
{{rootkey.publicExtendedKey}}
|
<span *ngIf="mode.net=='testnet'" class="label label-danger">Testnet</span>{{rootkey.publicExtendedKey}}
|
||||||
</div>
|
</div>
|
||||||
<clr-alert *ngFor="let entry of alerts" [clrAlertType]="line.severity">
|
<clr-alert *ngFor="let entry of alerts" [clrAlertType]="line.severity">
|
||||||
<clr-alert-item>
|
<clr-alert-item>
|
||||||
@@ -76,11 +127,18 @@ declare const fb
|
|||||||
</clr-alert>
|
</clr-alert>
|
||||||
|
|
||||||
<div class="card-block">
|
<div class="card-block">
|
||||||
<h3 style="margin-top:12px">Balance: {{balance.confirmed}}</h3>
|
<h3 style="margin-top:12px">{{balanceDisplay.total | number: '1.8-18'}} BTC </h3>
|
||||||
<p>
|
<p class="monospace">
|
||||||
Unconfirmed: {{balance.unconfirmed}}<br />
|
<span *ngIf="balanceDisplay.unconfirmed < 0"> </span>{{balanceDisplay.confirmed | number: '1.18'}} BTC confirmed<br />
|
||||||
Estimated total: {{balance.total}}
|
{{balanceDisplay.unconfirmed | number: '1.18'}} BTC pending
|
||||||
</p>
|
</p>
|
||||||
|
<p *ngIf="mode.type=='private'">
|
||||||
|
<clr-icon shape="key"></clr-icon> Private key available
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-footer" >
|
||||||
|
<button class="btn btn-icon" (click)="reload()"> <clr-icon shape="refresh"></clr-icon> Reload </button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Balance box-->
|
<!-- Balance box-->
|
||||||
@@ -91,50 +149,39 @@ declare const fb
|
|||||||
</div>
|
</div>
|
||||||
<!-- /row wallet picker + send box + balance box -->
|
<!-- /row wallet picker + send box + balance box -->
|
||||||
|
|
||||||
<div class="clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-12 clr-col-xl-12" style="padding-left:0px; padding-right: 0px">
|
<div class="clr-all-12" style="padding-left:0px; padding-right: 0px">
|
||||||
<address-viewer></address-viewer>
|
<address-viewer></address-viewer>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /row 1 -->
|
<!-- /row 1 -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class PluginsComponent implements AfterViewInit {
|
export class PluginsComponent implements AfterViewInit {
|
||||||
|
errors:string[] = []
|
||||||
wallets:{
|
successes:string[] = []
|
||||||
[someLabel in string]:{
|
wallets:WalletStore = {}
|
||||||
key:string
|
|
||||||
name:string
|
|
||||||
}
|
|
||||||
} = {}
|
|
||||||
txToSend:any
|
txToSend:any
|
||||||
rootkey = {
|
rootkey:bip32Keypair = {publicExtendedKey: "",privateExtendedKey: ""}
|
||||||
publicExtendedKey: "",
|
keys:KeyStore = {}
|
||||||
privateExtendedKey: ""
|
regaddresses:AddressLine[] = []
|
||||||
}
|
changeaddresses:AddressLine[] = []
|
||||||
keys = {}
|
balanceDisplay = {
|
||||||
regaddresses = []
|
|
||||||
changeaddresses = []
|
|
||||||
balance = {
|
|
||||||
confirmed: 0,
|
confirmed: 0,
|
||||||
total: 0,
|
total: 0,
|
||||||
unconfirmed: 0
|
unconfirmed: 0
|
||||||
}
|
}
|
||||||
mode : {
|
mode : {
|
||||||
net:network
|
type:keyType,
|
||||||
|
net:networkType
|
||||||
} = {
|
} = {
|
||||||
net: "testnet"
|
net: "testnet",
|
||||||
|
type: "public"
|
||||||
}
|
}
|
||||||
sendto:string
|
sendTo:string
|
||||||
amount:number
|
sendAmount:number
|
||||||
|
loading = false
|
||||||
|
loadingN = 1
|
||||||
|
|
||||||
constructor(){
|
|
||||||
window["btc"] = () => this
|
|
||||||
}
|
|
||||||
@ViewChild(AddressViewerComponent, {static: false})
|
@ViewChild(AddressViewerComponent, {static: false})
|
||||||
AddressViewerComponent:AddressViewerComponent
|
AddressViewerComponent:AddressViewerComponent
|
||||||
|
|
||||||
@@ -149,8 +196,8 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
this.WalletPickerComponent.setParent(this)
|
this.WalletPickerComponent.setParent(this)
|
||||||
this.AddressViewerComponent.setParent(this)
|
this.AddressViewerComponent.setParent(this)
|
||||||
|
|
||||||
//tprv8cXm1S7PGS2fHuLjZajuDZZsvxerzv4zZJJAhkLAWZzwz5rE7efHm31xsqpzfoGMHBNC8bkRcsjiMdmkSuNn5C1qNqk7rrk1pCuhk4HfVak
|
window['btc'] = this
|
||||||
//tpubD9Do9r9dQoiLBNNXTEQVcyDzVzAoAFFu8btwzGNTvqoLpa6zk3UswXdq3zeArrakUu8huCtG1L5pTqNYNftanuutf57fn1C74rBzFybH1xe
|
|
||||||
this.loadKey("tprv8cXm1S7PGS2fHuLjZajuDZZsvxerzv4zZJJAhkLAWZzwz5rE7efHm31xsqpzfoGMHBNC8bkRcsjiMdmkSuNn5C1qNqk7rrk1pCuhk4HfVak")
|
this.loadKey("tprv8cXm1S7PGS2fHuLjZajuDZZsvxerzv4zZJJAhkLAWZzwz5rE7efHm31xsqpzfoGMHBNC8bkRcsjiMdmkSuNn5C1qNqk7rrk1pCuhk4HfVak")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,50 +216,46 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
loadKey(key:string){
|
loadKey(key:string){
|
||||||
this.wallets = {}
|
this.wallets = {}
|
||||||
this.txToSend = null
|
this.txToSend = null
|
||||||
this.sendto = ""
|
this.sendTo = ""
|
||||||
this.regaddresses = []
|
this.regaddresses = []
|
||||||
|
|
||||||
const t = hdkey.checkHDKey(key)
|
const t = hdkey.checkHDKey(key)
|
||||||
if(t){
|
if(t){
|
||||||
|
console.log(t)
|
||||||
this.mode = t
|
this.mode = t
|
||||||
}
|
}
|
||||||
|
|
||||||
this.rootkey = hdkey.HDKeyFromExtendedKey(key)
|
this.rootkey = hdkey.HDKeyFromExtendedKey(key)
|
||||||
this.refresh()
|
this.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
async refresh(){
|
async reload():Promise<void>{
|
||||||
|
this.loading = true
|
||||||
|
this.loadingN = 1
|
||||||
this.keys = {}
|
this.keys = {}
|
||||||
this.changeaddresses = []
|
this.balanceDisplay.total = 0
|
||||||
this.regaddresses = []
|
this.balanceDisplay.unconfirmed = 0
|
||||||
this.AddressViewerComponent.setChangeAddresses([])
|
this.balanceDisplay.confirmed = 0
|
||||||
this.AddressViewerComponent.setRegularAddresses([])
|
await this.refresh()
|
||||||
this.balance.total = 0
|
this.loading = false
|
||||||
this.balance.unconfirmed = 0
|
}
|
||||||
this.balance.confirmed = 0
|
|
||||||
|
|
||||||
|
async refresh():Promise<void>{
|
||||||
let p1 = this.updateChange()
|
let p1 = this.updateChange()
|
||||||
let p2 = this.update()
|
let p2 = this.updateBalance()
|
||||||
|
|
||||||
let balances:any[] = await Promise.all([p1,p2])
|
let balances:GrandTotal[] = await Promise.all([p1,p2])
|
||||||
balances.forEach(balance => {
|
balances.forEach(balance => {
|
||||||
this.balance.confirmed += balance.confirmed
|
this.balanceDisplay.confirmed += balance.confirmed
|
||||||
this.balance.total += balance.total
|
this.balanceDisplay.total += balance.total
|
||||||
this.balance.unconfirmed += balance.unconfirmed
|
this.balanceDisplay.unconfirmed += balance.unconfirmed
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(this.changeaddresses)
|
|
||||||
|
|
||||||
this.AddressViewerComponent.setChangeAddresses(this.changeaddresses)
|
this.AddressViewerComponent.setChangeAddresses(this.changeaddresses)
|
||||||
this.AddressViewerComponent.setRegularAddresses(this.regaddresses)
|
this.AddressViewerComponent.setRegularAddresses(this.regaddresses)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAddresses(rootAddr: string, n = 10, skip = 0, changeAddresses = false): string[] | null{
|
||||||
async getInfo(rootAddr: string, n = 10, skip = 0, changeAddresses = false): Promise<any>{
|
|
||||||
const t = hdkey.checkHDKey(rootAddr)
|
|
||||||
if(!t){
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let addresses: string[] = []
|
let addresses: string[] = []
|
||||||
for(let i = skip; i < skip+n; i++){
|
for(let i = skip; i < skip+n; i++){
|
||||||
let addr
|
let addr
|
||||||
@@ -222,13 +265,17 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
addr = hdkey.deriveAddress(rootAddr, i)
|
addr = hdkey.deriveAddress(rootAddr, i)
|
||||||
}
|
}
|
||||||
if(!addr){
|
if(!addr){
|
||||||
return false
|
return
|
||||||
}
|
}
|
||||||
addresses.push(addr)
|
addresses.push(addr)
|
||||||
}
|
}
|
||||||
|
return addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchAddresses(addresses:string[], network:networkType): Promise<{success:boolean, address?:any, addresses?:any}>{
|
||||||
let lookupstr = addresses.join(',')
|
let lookupstr = addresses.join(',')
|
||||||
try{
|
try{
|
||||||
let r = await fetch(api[t.net]+'/address/'+lookupstr, {
|
let r = await fetch(api[network]+'/address/'+lookupstr, {
|
||||||
'method':'GET',
|
'method':'GET',
|
||||||
'mode':'cors',
|
'mode':'cors',
|
||||||
'data': {limit: 200}
|
'data': {limit: 200}
|
||||||
@@ -244,7 +291,18 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTxs(address: string, type:network){
|
async getAddressInfos(rootAddr: string, n = 10, skip = 0, changeAddresses = false): Promise<any>{
|
||||||
|
const t = hdkey.checkHDKey(rootAddr)
|
||||||
|
if(!t){
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const addresses = this.getAddresses(rootAddr, n, skip, changeAddresses)
|
||||||
|
return await this.fetchAddresses(addresses, t.net)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async getTxs(address: string, type:networkType){
|
||||||
|
try{
|
||||||
let r = await fetch(api[type]+'/address/'+address, {
|
let r = await fetch(api[type]+'/address/'+address, {
|
||||||
'method':'GET',
|
'method':'GET',
|
||||||
'mode':'cors'
|
'mode':'cors'
|
||||||
@@ -254,10 +312,14 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (await r).json()
|
return (await r).json()
|
||||||
|
}catch(e){
|
||||||
|
console.warn ("getTxs", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUnspentTxs(addresses:string[], type:network):Promise<any>{
|
async getUnspentTxs(addresses:string[], type:networkType):Promise<any>{
|
||||||
let lookupstr = addresses.join(',')
|
let lookupstr = addresses.join(',')
|
||||||
|
|
||||||
try{
|
try{
|
||||||
let r = await fetch(api[type]+'/address/'+lookupstr+'/unspent', {
|
let r = await fetch(api[type]+'/address/'+lookupstr+'/unspent', {
|
||||||
'method':'GET',
|
'method':'GET',
|
||||||
@@ -269,6 +331,7 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
|
|
||||||
return (await r).json()
|
return (await r).json()
|
||||||
}catch(e){
|
}catch(e){
|
||||||
|
console.warn ("getUnspentTxs", e)
|
||||||
return {success: false}
|
return {success: false}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,30 +341,51 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
return this.keys[keyName]
|
return this.keys[keyName]
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(){
|
calculateTotal(addresses:AddressLine[]):GrandTotal{
|
||||||
let n = 1
|
const resMap: any = addresses.reduce((o1, o2)=>{o1[o2.address] = o2; return o1}, {})
|
||||||
let regAddresses
|
const total: any = Object.values(resMap).reduce((accum:GrandTotal, obj:AddressLine) => {
|
||||||
|
accum.confirmed += parseFloat(<any>obj.confirmed.balance)
|
||||||
|
accum.unconfirmed += parseFloat(<any>obj.unconfirmed.balance)
|
||||||
|
accum.total += parseFloat(<any>obj.confirmed.balance) + parseFloat(<any>obj.unconfirmed.balance)
|
||||||
|
return accum
|
||||||
|
},{
|
||||||
|
confirmed: 0,
|
||||||
|
unconfirmed: 0,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateBalance():Promise<GrandTotal>{
|
||||||
|
let n = 1
|
||||||
|
let res: { success: boolean; addresses: any; address: any; }
|
||||||
|
this.regaddresses = []
|
||||||
while(true){
|
while(true){
|
||||||
|
this.loadingN = n
|
||||||
try{
|
try{
|
||||||
regAddresses = await this.getInfo(this.rootkey.publicExtendedKey, 115*n, 115*(n-1))
|
res = await this.getAddressInfos(this.rootkey.publicExtendedKey, 115*n, 115*(n-1))
|
||||||
}catch(e){
|
}catch(e){
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if(regAddresses.success === true){
|
if(res.success === true){
|
||||||
if('addresses' in regAddresses){ // multiple
|
if('addresses' in res){ // multiple
|
||||||
this.regaddresses = [...this.regaddresses, ...regAddresses.addresses]
|
this.regaddresses = [...this.regaddresses, ...res.addresses]
|
||||||
}
|
}
|
||||||
if('address' in regAddresses){
|
if('address' in res){
|
||||||
this.regaddresses.push(regAddresses.address)
|
this.regaddresses.push(res.address)
|
||||||
}
|
}
|
||||||
n++
|
n++
|
||||||
}else{
|
}else{
|
||||||
|
console.warn(`This error is a result of a failed fetch request.
|
||||||
|
These are always shown by the browser and cannot be hidden (a design decision)
|
||||||
|
They are completely safe and mean no more addresses were found`)
|
||||||
console.log('No more balance found after attempting ', 115*n, 'addresses')
|
console.log('No more balance found after attempting ', 115*n, 'addresses')
|
||||||
if(this.rootkey.privateExtendedKey != null){
|
if(this.mode.type == "private"){
|
||||||
for(let i = 0; i < 115*n; i++){
|
for(let i = 0; i < 115*n+1; i++){
|
||||||
const keyN = hdkey.deriveKey(this.rootkey.privateExtendedKey, i)
|
const keyN = hdkey.deriveKey(this.rootkey.privateExtendedKey, i)
|
||||||
const addrN = hdkey.addressFromHDKey(keyN._publicKey, this.mode.net)
|
const addrN = hdkey.addressFromHDKey(keyN._publicKey, this.mode.net)
|
||||||
|
keyN.derivation = i
|
||||||
this.keys[addrN] = keyN
|
this.keys[addrN] = keyN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -309,46 +393,25 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.regaddresses.length === 0){
|
//add an extra empty address at the end
|
||||||
const addr = hdkey.deriveAddress(this.rootkey.publicExtendedKey, 0)
|
const extraAddr = hdkey.deriveAddress(this.rootkey.publicExtendedKey, this.regaddresses.length)
|
||||||
this.regaddresses.push({
|
this.regaddresses.push({
|
||||||
address: addr,
|
address: <string>extraAddr,
|
||||||
confirmed: {balance: 0},
|
confirmed: {balance: 0},
|
||||||
unconfirmed: {balance: 0},
|
unconfirmed: {balance: 0},
|
||||||
total: {balance: 0},
|
total: {balance: 0},
|
||||||
})
|
})
|
||||||
return {
|
|
||||||
total: 0,
|
|
||||||
unconfirmed: 0,
|
|
||||||
confirmed: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const resMap: any = {}
|
|
||||||
this.regaddresses.forEach(a => {
|
|
||||||
resMap[a.address] = a
|
|
||||||
})
|
|
||||||
|
|
||||||
const confirmed = <number>Object.values(resMap).reduce((accum:any, obj:any) => {
|
return this.calculateTotal(this.regaddresses)
|
||||||
return accum + parseFloat(obj.confirmed.balance)
|
|
||||||
}, 0)
|
|
||||||
const unconfirmed = <number>Object.values(resMap).reduce((accum:any, obj:any) => {
|
|
||||||
return accum + parseFloat(obj.unconfirmed.balance)
|
|
||||||
}, 0)
|
|
||||||
|
|
||||||
return {
|
|
||||||
total: confirmed+unconfirmed,
|
|
||||||
unconfirmed: unconfirmed,
|
|
||||||
confirmed: confirmed
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateChange(){
|
async updateChange():Promise<GrandTotal>{
|
||||||
let n = 1
|
let n = 1
|
||||||
let res
|
this.changeaddresses = []
|
||||||
|
|
||||||
while(true){
|
while(true){
|
||||||
|
let res
|
||||||
try{
|
try{
|
||||||
res = await this.getInfo(this.rootkey.publicExtendedKey, 115*n, 115*(n-1), true)
|
res = await this.getAddressInfos(this.rootkey.publicExtendedKey, 115*n, 115*(n-1), true)
|
||||||
}catch(e){
|
}catch(e){
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -361,11 +424,16 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
n++
|
n++
|
||||||
}else{
|
}else{
|
||||||
console.log('No more balance found after attempting ', 115*n, 'addresses')
|
console.warn(`This error is a result of a failed fetch request.
|
||||||
if(this.rootkey.privateExtendedKey != null){
|
These are always shown by the browser and cannot be hidden (a design decision)
|
||||||
|
They are completely safe and mean no more addresses were found`)
|
||||||
|
console.log('No more change balance found after attempting ', 115*n, 'addresses')
|
||||||
|
if(this.mode.type == "private"){
|
||||||
|
//make keypairs for addresses
|
||||||
for(let i = 0; i < 115*n; i++){
|
for(let i = 0; i < 115*n; i++){
|
||||||
const keyN = hdkey.deriveKey(this.rootkey.privateExtendedKey, i, 'm/1/')
|
const keyN = hdkey.deriveKey(this.rootkey.privateExtendedKey, i, 'm/1/')
|
||||||
const addrN = hdkey.addressFromHDKey(keyN._publicKey, this.mode.net)
|
const addrN = hdkey.addressFromHDKey(keyN._publicKey, this.mode.net)
|
||||||
|
keyN.derivation = i
|
||||||
this.keys[addrN] = keyN
|
this.keys[addrN] = keyN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,60 +441,26 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.changeaddresses.length === 0){
|
return this.calculateTotal(this.changeaddresses)
|
||||||
const addr = hdkey.deriveAddress(this.rootkey.publicExtendedKey, 0, 'm/1/')
|
|
||||||
this.changeaddresses.push({
|
|
||||||
address: addr,
|
|
||||||
confirmed: {balance: 0},
|
|
||||||
unconfirmed: {balance: 0},
|
|
||||||
total: {balance: 0},
|
|
||||||
})
|
|
||||||
return {
|
|
||||||
total: 0,
|
|
||||||
unconfirmed: 0,
|
|
||||||
confirmed: 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const resMap: any = {}
|
async createAndSendTx(target:string, value:number){
|
||||||
this.changeaddresses.forEach(a => {
|
|
||||||
resMap[a.address] = a
|
|
||||||
})
|
|
||||||
|
|
||||||
const confirmed = <number>Object.values(resMap).reduce((accum:any, obj:any) => {
|
|
||||||
return accum + parseFloat(obj.confirmed.balance)
|
|
||||||
}, 0)
|
|
||||||
const unconfirmed = <number>Object.values(resMap).reduce((accum:any, obj:any) => {
|
|
||||||
return accum + parseFloat(obj.unconfirmed.balance)
|
|
||||||
}, 0)
|
|
||||||
|
|
||||||
return {
|
|
||||||
confirmed: confirmed,
|
|
||||||
unconfirmed: unconfirmed,
|
|
||||||
total: unconfirmed + confirmed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async createTx(target:string, value:number){
|
|
||||||
|
|
||||||
console.log(target, value)
|
|
||||||
|
|
||||||
if(target == null || typeof target !== 'string' || target === '' || value == null || value <= 0 ){
|
if(target == null || typeof target !== 'string' || target === '' || value == null || value <= 0 ){
|
||||||
//this.error = 'Bad inputs. Expected bitcoin address and number'
|
this.errors.push('Bad inputs. Expected bitcoin address and number')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if(value > this.balance.confirmed){
|
if(value > this.balanceDisplay.confirmed){
|
||||||
//this.error = 'Insufficient funds'
|
this.errors.push('Insufficient funds')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let addresses: string[] = this.regaddresses.map(a => a.address)
|
let addresses: string[] = [...this.regaddresses.map(a => a.address), ...this.changeaddresses.map(a => a.address)]
|
||||||
addresses = [...addresses, ...this.changeaddresses.map(a => a.address)]
|
|
||||||
const txs = await this.getUnspentTxs(addresses, this.mode.net)
|
const txs = await this.getUnspentTxs(addresses, this.mode.net)
|
||||||
|
|
||||||
if(txs == null || txs.success !== true || txs.unspent.length === 0){
|
if(txs == null || txs.success !== true || txs.unspent.length === 0){
|
||||||
//this.error = 'No UTXOs found'
|
this.errors.push('No UTXOs found')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,7 +477,7 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
|
|
||||||
// .inputs and .outputs will be undefined if no solution was found
|
// .inputs and .outputs will be undefined if no solution was found
|
||||||
if (!inputs || !outputs){
|
if (!inputs || !outputs){
|
||||||
//this.error = 'Could not build a valid transaction'
|
this.errors.push('Could not build a valid transaction')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,7 +495,7 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
txb.addOutput(output.address, output.value)
|
txb.addOutput(output.address, output.value)
|
||||||
})
|
})
|
||||||
inputs.forEach((input, i) => {
|
inputs.forEach((input, i) => {
|
||||||
txb.sign(i, this.keys[input.address])
|
txb.sign(i, <Signer>this.keys[input.address])
|
||||||
})
|
})
|
||||||
|
|
||||||
this.txToSend = txb.build()
|
this.txToSend = txb.build()
|
||||||
@@ -469,37 +503,61 @@ export class PluginsComponent implements AfterViewInit {
|
|||||||
this.sendTx()
|
this.sendTx()
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendTx(){
|
private async sendTx(){
|
||||||
if(this.txToSend == null){
|
if(this.txToSend == null){
|
||||||
//this.error = 'No transaction to send!'
|
this.errors.push('No transaction to send!')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let url
|
let url = api[this.mode.net]+"/pushtx"
|
||||||
if(this.mode.net === 'mainnet'){
|
let r
|
||||||
url = 'https://api.smartbit.com.au/v1/blockchain/pushtx'
|
try{
|
||||||
}else{
|
r = await fetch(url, {
|
||||||
url = 'https://testnet-api.smartbit.com.au/v1/blockchain/pushtx'
|
|
||||||
}
|
|
||||||
let r = await fetch(url, {
|
|
||||||
'method':'POST',
|
'method':'POST',
|
||||||
'body': JSON.stringify({'hex': this.txToSend.toHex()})
|
'body': JSON.stringify({'hex': this.txToSend.toHex()})
|
||||||
})
|
})
|
||||||
|
}catch(e){
|
||||||
|
console.warn("sendTx", e)
|
||||||
|
return
|
||||||
|
}
|
||||||
this.txToSend = null
|
this.txToSend = null
|
||||||
if(r.status === 200){
|
if(r.status === 200){
|
||||||
console.log(r)
|
this.errors = []
|
||||||
this.refresh()
|
this.successes.push("Sent "+this.sendAmount+" to "+this.sendTo)
|
||||||
|
this.reload()
|
||||||
}else{
|
}else{
|
||||||
//this.error = 'The API '+url+' returned a non-200 error code '+r.status+' '+r.statusText
|
this.errors.push('The API '+url+' returned a non-200 error code '+r.status+' '+r.statusText)
|
||||||
console.log(r)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addrExplorer(address){
|
||||||
|
const url = this.mode.net === 'testnet'?'https://live.blockcypher.com/btc-testnet/address/':'https://live.blockcypher.com/btc/address/'
|
||||||
|
window.open(url+address, '_blank')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type network = 'testnet' | 'mainnet'
|
export type KeyStore = {[keyname in string]: bip32Keypair & Signer}
|
||||||
|
|
||||||
|
export type AddressLine = {
|
||||||
|
address: string,
|
||||||
|
confirmed: {balance: number},
|
||||||
|
unconfirmed: {balance: number},
|
||||||
|
total: {balance: number},
|
||||||
|
}
|
||||||
|
|
||||||
|
type networkType = 'testnet' | 'mainnet'
|
||||||
type keyType = 'public' | 'private'
|
type keyType = 'public' | 'private'
|
||||||
|
type WalletStore = {
|
||||||
|
[address in string]:{
|
||||||
|
key:string
|
||||||
|
name:string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type GrandTotal = {
|
||||||
|
confirmed: number,
|
||||||
|
unconfirmed: number,
|
||||||
|
total: number
|
||||||
|
}
|
||||||
type bip32Keypair = { publicExtendedKey: string, privateExtendedKey: string }
|
type bip32Keypair = { publicExtendedKey: string, privateExtendedKey: string }
|
||||||
|
|
||||||
const api = {
|
const api = {
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ declare const fb
|
|||||||
</clr-checkbox-wrapper>
|
</clr-checkbox-wrapper>
|
||||||
<ng-template clrPageButtons>
|
<ng-template clrPageButtons>
|
||||||
<clr-wizard-button [type]="'cancel'">Cancel</clr-wizard-button>
|
<clr-wizard-button [type]="'cancel'">Cancel</clr-wizard-button>
|
||||||
|
<clr-wizard-button [type]="'back'">Back</clr-wizard-button>
|
||||||
<clr-wizard-button class="btn btn-success" [type]="'myfinish'">Finish</clr-wizard-button>
|
<clr-wizard-button class="btn btn-success" [type]="'myfinish'">Finish</clr-wizard-button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</clr-wizard-page>
|
</clr-wizard-page>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ declare const fb
|
|||||||
selector: 'walletpicker', //!!!!
|
selector: 'walletpicker', //!!!!
|
||||||
|
|
||||||
template: `
|
template: `
|
||||||
<div class="card" style="overflow:hidden">
|
<div class="card" style="overflow:hidden; padding-bottom:12px">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Wallets
|
Wallets
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
.heightmax{
|
|
||||||
height: 100%
|
|
||||||
}
|
|
||||||
.break-word {
|
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
|
||||||
.monospace {
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 90%
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
<div style="overflow:hidden" class="content-area clr-col-12 clr-col-sm-12 clr-col-lg-12 clr-col-xl-12">
|
<div class="content-area" style="max-height: 100%">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet class="clr-all-12" ></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1 +1,52 @@
|
|||||||
/* You can add global styles to this file, and also import other style files */
|
/* You can add global styles to this file, and also import other style files */
|
||||||
|
@import "../node_modules/@clr/ui/src/utils/components.clarity";
|
||||||
|
|
||||||
|
.heightmax{
|
||||||
|
height: 100%
|
||||||
|
}
|
||||||
|
.break-word {
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.monospace {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 90%
|
||||||
|
}
|
||||||
|
*::-webkit-scrollbar-track
|
||||||
|
{
|
||||||
|
box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||||
|
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||||
|
background-color: rgba(0,0,0,0);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar
|
||||||
|
{
|
||||||
|
width: 7px;
|
||||||
|
background-color: rgba(0,0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-thumb
|
||||||
|
{
|
||||||
|
border-radius: 7px;
|
||||||
|
background-color: #0079B8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clr-all-12{
|
||||||
|
@extend .clr-col-12, .clr-col-sm-12, .clr-col-md-12, .clr-col-lg-12, .clr-col-xl-12
|
||||||
|
}
|
||||||
|
|
||||||
|
.clr-all-4{
|
||||||
|
@extend .clr-col-4, .clr-col-sm-4, .clr-col-md-4, .clr-col-lg-4, .clr-col-xl-4
|
||||||
|
}
|
||||||
|
|
||||||
|
.clr-all-6{
|
||||||
|
@extend .clr-col-6, .clr-col-sm-6, .clr-col-md-6, .clr-col-lg-6, .clr-col-xl-6
|
||||||
|
}
|
||||||
|
|
||||||
|
.clr-all-3{
|
||||||
|
@extend .clr-col-3, .clr-col-sm-3, .clr-col-md-3, .clr-col-lg-3, .clr-col-xl-3
|
||||||
|
}
|
||||||
|
|
||||||
|
.clr-all-2{
|
||||||
|
@extend .clr-col-2, .clr-col-sm-2, .clr-col-md-2, .clr-col-lg-2, .clr-col-xl-2
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user