Browse Source

test submodules

master
peter 2 years ago
parent
commit
62eeec9378

+ 1
- 1
package.json View File

@@ -39,7 +39,7 @@
39 39
   },
40 40
   "devDependencies": {
41 41
     "@angular-devkit/build-angular": "~0.802.1",
42
-    "@angular/cli": "^8.2.1",
42
+    "@angular/cli": "^8.2.2",
43 43
     "@angular/compiler-cli": "~8.2.1",
44 44
     "@angular/language-service": "~8.2.1",
45 45
     "@types/jasmine": "~3.4.0",

+ 0
- 93
src/app/ApiClient/apiclient-consumptions.component.ts View File

@@ -1,93 +0,0 @@
1
-import { Component, OnInit, isDevMode } from '@angular/core';
2
-import { SubscriptionResponse, parseResponse, SuccessResponse, Coin } from 'frontblock-generic/Types.js';
3
-import { default as uuid } from 'uuid/v4'
4
-
5
-declare const fb
6
- 
7
-@Component({
8
-    selector: 'consumers',
9
-    template: `
10
-  <div class="clr-row">
11
-    <div class="card clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-auto clr-col-xl-auto">
12
-        <div class="card-header">
13
-        Consumers
14
-        </div>
15
-        <clr-alert *ngFor="let entry of alerts" [clrAlertType]="entry.severity">
16
-            <clr-alert-item>
17
-                <span class="alert-text">
18
-                    {{entry.message}}
19
-                </span>
20
-            </clr-alert-item>
21
-        </clr-alert>
22
-
23
-        <div *ngIf="loading" class="card-block">
24
-        <span class="spinner spinner-inline"></span>
25
-        </div>
26
-        <div *ngIf="entries.length !== 0 && !loading" class="card-block limit-height">
27
-            <div class="card-text limit-height">
28
-                <clr-datagrid>
29
-                    <clr-dg-column>UUID</clr-dg-column>
30
-                    <clr-dg-column>Subscription UUID</clr-dg-column>
31
-                    <clr-dg-column>Expiry</clr-dg-column>
32
-                    <clr-dg-column>Creation</clr-dg-column>
33
-
34
-                    <clr-dg-row *clrDgItems="let line of entries">
35
-                        <clr-dg-cell>{{line.uid}}</clr-dg-cell>
36
-                        <clr-dg-cell>{{line.message}}</clr-dg-cell>
37
-                        <clr-dg-cell>{{line.expiry | date}}</clr-dg-cell>
38
-                        <clr-dg-cell>{{line.created | date}}</clr-dg-cell>
39
-                        
40
-                        <clr-dg-row-detail *clrIfExpanded>
41
-                            <button class="btn btn-icon btn-danger-outline" (click)="quit(line.uid)"><clr-icon shape="times"></clr-icon> Quit</button>
42
-                        </clr-dg-row-detail>
43
-                    </clr-dg-row>
44
-                    <clr-dg-footer>
45
-                        <clr-dg-pagination #pagination [clrDgPageSize]="10">
46
-                            <clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Users per page</clr-dg-page-size>
47
-                            {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
48
-                            of {{pagination.totalItems}} users
49
-                        </clr-dg-pagination>
50
-                    </clr-dg-footer>
51
-                </clr-datagrid>
52
-            </div>
53
-        </div>
54
-        <div class="card-footer">
55
-            <button *ngIf="!loading" class="btn btn-sm btn-link" (click)="load()">{{actionName}}</button>
56
-        </div>
57
-    </div>
58
-  `
59
-})
60
-export class ApiclientConsumptionComponent implements OnInit {
61
-    loading: boolean = false
62
-    actionName: string = "load"
63
-    entries: SubscriptionResponse[] = []
64
-    alerts: {
65
-        severity: "danger" | "warning" | "success"
66
-        message: string
67
-    }[] = []
68
-
69
-    constructor() { }
70
-
71
-    ngOnInit() { }
72
-
73
-    async load() {
74
-        this.loading = true
75
-        this.entries = await fb.ApiClient.getConsumptions()
76
-        if (this.entries.length === 0) {
77
-            this.alerts.push({ severity: "warning", message: "0 results were returned" })
78
-        }
79
-        this.loading = false
80
-        this.actionName = "refresh"
81
-    }
82
-
83
-    async quit(uid: string) {
84
-        const r = await fb.ApiClient.quit(uid)
85
-        const res = parseResponse(r)
86
-        if (res instanceof SuccessResponse) {
87
-            this.alerts.push({ severity: "success", message: "Quit consuming " + uid })
88
-            this.load()
89
-        } else {
90
-            this.alerts.push({ severity: "danger", message: "Error " + res.message })
91
-        }
92
-    }
93
-}

+ 0
- 132
src/app/ApiClient/apiclient-settings-form.component.ts View File

@@ -1,132 +0,0 @@
1
-import { Component, OnInit } from '@angular/core';
2
-import { FrontblockApiConf } from 'frontblock';
3
-import { isDevMode } from '@angular/core';
4
-
5
-declare const fb
6
-
7
-@Component({
8
-    selector: 'settings',
9
-    template: `
10
-    <div class="clr-row">
11
-        <div class="card clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-auto clr-col-xl-auto">
12
-            <div class="card-header">
13
-            Settings
14
-            </div>
15
-            <div class="card-block">
16
-                <div class="card-text">
17
-                    <form clrForm clrLayout="horizontal">
18
-                        <div class="clr-row clr-form-control ng-star-inserted">
19
-                            <label class="clr-col-12 clr-col-md-4 clr-control-label">testnet</label>
20
-                            <div class="clr-col-12 clr-col-md-8">
21
-                                <input type="checkbox" [(ngModel)]="testnet"  (change)="updateTestnet($event)" name="testnetToggle" clrToggle  />
22
-                            </div>
23
-                        </div>
24
-                        
25
-                        <clr-input-container *ngIf="!testnet">
26
-                            <label class="clr-col-12 clr-col-md-4">API key</label>
27
-                            <input class="clr-col-12 clr-col-md-8" clrInput type="text" name="apiKey" required />
28
-                        </clr-input-container>
29
-                    
30
-                        <clr-input-container *ngIf="advanced" class="clr-row">
31
-                            <label class="clr-col-12 clr-col-md-4">API address</label>
32
-                            <input class="clr-col-12 clr-col-md-8" type="text" [(ngModel)]="data.apiHost" (change)="updatePort($event)" clrInput name="apiHost" required />
33
-                            <clr-control-error>This field is required!</clr-control-error>
34
-                        </clr-input-container>
35
-
36
-                        <div class="clr-row clr-form-control ng-star-inserted" *ngIf="advanced">
37
-                            <label class="clr-col-12 clr-col-md-4 clr-control-label">Use TLS</label>
38
-                            <div class="clr-col-12 clr-col-md-8">
39
-                                <input [(ngModel)]="data.tls" type="checkbox" clrCheckbox value="tls" name="options" />
40
-                            </div>
41
-                        </div>
42
-                        
43
-                        <clr-input-container class="clr-row" *ngIf="advanced">
44
-                            <label class="clr-col-12 clr-col-md-4">Port</label>
45
-                            <input class="clr-col-12 clr-col-md-8" [(ngModel)]="data.apiPort" clrInput type="number" name="lastName" required />
46
-                            <clr-control-error>Valid range 1024 - 65536 
47
-                            </clr-control-error>
48
-                        </clr-input-container>
49
-                    </form>
50
-                </div>
51
-            </div>
52
-            <div class="card-footer">
53
-                <button *ngIf="!saving" class="btn btn-success-outline" (click)="save()">
54
-                <span>Save</span>
55
-                </button>
56
-
57
-                <button *ngIf="saving" class="btn btn-disabled" (click)="save()" disabled>
58
-                <span class="spinner spinner-inline"></span>
59
-                </button>
60
-                <button *ngIf="!advanced" class="btn btn-sm btn-link" (click)="setAdvanced()">Advanced</button>
61
-            </div>
62
-        </div>
63
-    </div>
64
-  `
65
-})
66
-export class ApiclientFormComponent implements OnInit {
67
-    testnet: boolean = true
68
-    saving: boolean = false
69
-    advanced: boolean = false
70
-    data: FrontblockApiConf = {
71
-        apiHost: "api.testnet.frontblock.me",
72
-        apiPort: 10001,
73
-        tls: false,
74
-        apiKey: ""
75
-    }
76
-
77
-    constructor() { }
78
-
79
-    ngOnInit() { }
80
-
81
-    setAdvanced() { this.advanced = true }
82
-
83
-    checkData(): boolean {
84
-        return (
85
-            typeof this.data.apiPort === "number" &&
86
-            typeof this.data.apiHost === "string" &&
87
-            typeof this.data.tls === "boolean" &&
88
-            typeof this.data.apiKey === "string"
89
-        )
90
-    }
91
-
92
-    updateTestnet() {
93
-        if (this.testnet) {
94
-            this.data.apiHost = "api.testnet.frontblock.me"
95
-            this.data.apiPort = 10001
96
-        } else {
97
-            this.data.apiHost = "api.frontblock.me"
98
-            this.data.apiPort = 10000
99
-        }
100
-    }
101
-
102
-    updatePort(obj) {
103
-        switch (this.data.apiHost) {
104
-            case "api.testnet.frontblock.me":
105
-                this.data.apiPort = 10001
106
-                break;
107
-            case "api.frontblock.me":
108
-                this.data.apiPort = 10000
109
-                break;
110
-
111
-            default:
112
-                console.warn("A non-standard api host was chosen: " + this.data.apiPort)
113
-                break;
114
-        }
115
-        console.log(this.data)
116
-    }
117
-
118
-    async save() {
119
-        this.saving = true;
120
-        if (typeof this.data.apiPort === "string")
121
-            this.data.apiPort = parseInt(this.data.apiPort)
122
-
123
-        if (this.checkData()) {
124
-            const conf = await fb.ApiClient.setConfig(this.data)
125
-            console.log(conf)
126
-        } else {
127
-            //show error in gui
128
-            console.error("bad data :(")
129
-        }
130
-        this.saving = false
131
-    }
132
-}

+ 0
- 103
src/app/ApiClient/apiclient-subscriptions.component.ts View File

@@ -1,103 +0,0 @@
1
-import { Component, OnInit, isDevMode } from '@angular/core';
2
-import { SubscriptionResponse, SuccessResponse, parseResponse, Coin } from 'frontblock-generic/Types.js';
3
-import { default as uuid } from 'uuid/v4'
4
-declare const fb
5
-
6
-@Component({
7
-    selector: 'subscriptions',
8
-    template: `
9
-    <div class="clr-row">
10
-        <div class="card clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-12 clr-col-xl-12">
11
-            <div class="card-header">
12
-            Subscriptions
13
-            </div>
14
-            <clr-alert *ngFor="let entry of alerts" [clrAlertType]="entry.severity">
15
-                <clr-alert-item>
16
-                    <span class="alert-text">
17
-                        {{entry.message}}
18
-                    </span>
19
-                </clr-alert-item>
20
-            </clr-alert>
21
-        
22
-            <div *ngIf="loading" class="card-block">
23
-            <span class="spinner spinner-inline"></span>
24
-            </div>
25
-            <div *ngIf="entries.length !== 0 && !loading" class="card-block">
26
-                <div class="card-text">
27
-                    <clr-datagrid>
28
-                        <clr-dg-column>UUID</clr-dg-column>
29
-                    <!--
30
-                        <clr-dg-column>Currency</clr-dg-column>
31
-                        <clr-dg-column>Address</clr-dg-column>
32
-                        <clr-dg-column>Memo</clr-dg-column>
33
-                        <clr-dg-column>Expiry</clr-dg-column>
34
-                        <clr-dg-column>Creation</clr-dg-column>
35
-                    -->
36
-        
37
-                        <clr-dg-row *clrDgItems="let line of entries">
38
-                            <clr-dg-cell>{{line.uid}}</clr-dg-cell>
39
-                        <!-- 
40
-                            <clr-dg-cell>{{line.currency}}</clr-dg-cell> 
41
-                            <clr-dg-cell>{{line.address}}</clr-dg-cell> 
42
-                            <clr-dg-cell>{{line.memo}}</clr-dg-cell> 
43
-                            <clr-dg-cell>{{line.expiry | date}}</clr-dg-cell> 
44
-                            <clr-dg-cell>{{line.created | date}}</clr-dg-cell> 
45
-                        -->
46
-                            
47
-                            <clr-dg-row-detail *clrIfExpanded>
48
-                                <button class="btn btn-icon btn-danger-outline" (click)="quit(line.uid)"><clr-icon shape="times"></clr-icon> Unsubscribe</button>
49
-                            </clr-dg-row-detail>
50
-                        </clr-dg-row>
51
-                        <clr-dg-footer>
52
-                            <clr-dg-pagination #pagination [clrDgPageSize]="10">
53
-                                <clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Users per page</clr-dg-page-size>
54
-                                {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
55
-                                of {{pagination.totalItems}} users
56
-                            </clr-dg-pagination>
57
-                        </clr-dg-footer>
58
-                    </clr-datagrid>
59
-                </div>
60
-            </div>
61
-            <div class="card-footer">
62
-                <button *ngIf="!loading" class="btn btn-sm btn-link" (click)="load()">{{actionName}}</button>
63
-        
64
-            </div>
65
-        </div>
66
-    </div>
67
-`
68
-})
69
-export class ApiclientSubscriptionComponent implements OnInit {
70
-    loading: boolean = false
71
-    actionName: string = "load"
72
-    entries: (SubscriptionResponse )[] = []
73
-    alerts: {
74
-        severity: "danger" | "warning" | "success"
75
-        message: string
76
-    }[] = []
77
-
78
-    constructor() { }
79
-
80
-    ngOnInit() { }
81
-
82
-    async load() {
83
-        this.loading = true
84
-        this.entries = await fb.ApiClient.getSubscriptions()
85
-        if (this.entries.length === 0) {
86
-            this.alerts.push({ severity: "warning", message: "0 results were returned" })
87
-        }
88
-        this.loading = false
89
-        this.actionName = "refresh"
90
-    }
91
-
92
-    async quit(uid: string) {
93
-        const r = await fb.ApiClient.unsubscribe(uid)
94
-        const res = parseResponse(r)
95
-        if (res instanceof SuccessResponse) {
96
-            this.alerts.push({ severity: "success", message: "Stopped subscription " + uid })
97
-            this.load()
98
-        } else {
99
-            this.alerts.push({ severity: "danger", message: "Error " + res.message })
100
-        }
101
-    }
102
-
103
-}

+ 0
- 51
src/app/ApiClient/module.ts View File

@@ -1,51 +0,0 @@
1
-import { NgModule } from '@angular/core';
2
-import { CommonModule } from '@angular/common';
3
-import { RouterModule } from '@angular/router';
4
-
5
-import { ApiclientFormComponent } from './apiclient-settings-form.component';
6
-import { ApiclientConsumptionComponent } from './apiclient-consumptions.component';
7
-import { ApiclientSubscriptionComponent } from './apiclient-subscriptions.component';
8
-
9
-import { FrontendPlugin, SidebarEntry, SidebarEntries } from 'frontblock-generic/Plugin';
10
-import { ClarityModule } from '@clr/angular';
11
-import { FormsModule } from '@angular/forms';
12
-
13
-
14
-@NgModule({
15
-  imports: [
16
-    FormsModule,
17
-    ClarityModule,
18
-
19
-    CommonModule, 
20
-    RouterModule.forChild([
21
-      {path: "settings", component: ApiclientFormComponent},
22
-      {path: "subscriptions", component: ApiclientSubscriptionComponent},
23
-      {path: "consumers", component: ApiclientConsumptionComponent},
24
-    ]),
25
-  ],
26
-  exports: [RouterModule],
27
-  declarations: [
28
-    ApiclientFormComponent,
29
-    ApiclientConsumptionComponent,
30
-    ApiclientSubscriptionComponent
31
-  ]
32
-})
33
-export class PluginModule implements FrontendPlugin{
34
-  getSidebarEntry(): SidebarEntries {
35
-    return {
36
-      icon: "key",
37
-      parentRoute: "apiclient",
38
-      text: "Api client",
39
-      links: [{
40
-        route: "settings",
41
-        text: "Settings"
42
-      },{
43
-        route: "consumers",
44
-        text: "Consumers"
45
-      },{
46
-        route: "subscriptions",
47
-        text: "Subscriptions"
48
-      },]
49
-    }
50
-  }
51
-}

+ 0
- 47
src/app/PluginManager/debug.component.ts View File

@@ -1,47 +0,0 @@
1
-import { Component, OnInit } from '@angular/core';
2
-import { SidebarEntry } from 'frontblock-generic/Plugin';
3
-declare const fb
4
-@Component({
5
-  selector: 'debug', //!!!!
6
-  template: `
7
-  <div class="clr-row">
8
-    <div class="clr-col">
9
-        <div class="card">
10
-            <div class="card-header">
11
-                DEBUG
12
-            </div>
13
-            <div class="card-block">
14
-                <div class="card-title">
15
-                    SETUP
16
-                </div>
17
-                <div class="card-text">
18
-                  <p>
19
-                    Press this button to install all plugins.
20
-                    <br>
21
-                    Once the installation is done the page will refresh automatically
22
-                  </p>
23
-                </div>
24
-            </div>
25
-            <div class="card-footer">
26
-              <button class="btn btn-warning-outline" onclick="setup()">SETUP</button>
27
-            </div>
28
-        </div>
29
-    </div>
30
-  </div>
31
-  `
32
-})
33
-export class PluginmanagerDEBUG implements OnInit {
34
-
35
-  constructor() { }
36
-
37
-  ngOnInit() { }
38
-
39
-}
40
-
41
-export const sidebarEntry: SidebarEntry = {
42
-  icon: "wrench",
43
-  route: "dev/pluginmanager",
44
-  text: "DEV Plugin manager",
45
-}
46
-
47
-

+ 0
- 45
src/app/PluginManager/module.ts View File

@@ -1,45 +0,0 @@
1
-import { NgModule } from '@angular/core';
2
-import { CommonModule } from '@angular/common';
3
-import { RouterModule } from '@angular/router';
4
-
5
-import { PluginmanagerDEBUG } from './debug.component';
6
-import { PluginsComponent } from './plugins.component';
7
-
8
-import { FrontendPlugin, SidebarEntries } from 'frontblock-generic/Plugin';
9
-import { ClarityModule } from '@clr/angular';
10
-import { FormsModule } from '@angular/forms';
11
-
12
-
13
-@NgModule({
14
-  imports: [
15
-    FormsModule,
16
-    ClarityModule,
17
-
18
-    CommonModule, 
19
-    RouterModule.forChild([
20
-      {path: "debug", component: PluginmanagerDEBUG},
21
-      {path: "plugins", component: PluginsComponent}
22
-    ]),
23
-  ],
24
-  exports: [RouterModule],
25
-  declarations: [
26
-    PluginmanagerDEBUG,
27
-    PluginsComponent
28
-  ]
29
-})
30
-export class PluginModule implements FrontendPlugin{
31
-  getSidebarEntry(): SidebarEntries {
32
-    return {
33
-      icon: "plugin",
34
-      text: "Plugin manager",
35
-      parentRoute: "pluginmanager",
36
-      links: [{
37
-        route: "debug",
38
-        text: "DEBUG"    
39
-      },{
40
-        route: "plugins",
41
-        text: "Plugins"    
42
-      }]
43
-    }
44
-  }
45
-}

+ 0
- 156
src/app/PluginManager/plugins.component.ts View File

@@ -1,156 +0,0 @@
1
-import { Component, OnInit, isDevMode } from '@angular/core';
2
-declare const fb
3
-@Component({
4
-    selector: 'plugins', //!!!!
5
-    template: `
6
-  <clr-modal [(clrModalOpen)]="updatepending">
7
-    <h3 class="modal-title">Confirm installation</h3>
8
-    <div class="modal-body">
9
-        <p>{{updateCandidate}} But not much to say...</p>
10
-    </div>
11
-    <div class="modal-footer">
12
-        <button class="btn btn-icon btn-success" (click)="download(updateCandidate)"><clr-icon shape="check"></clr-icon></button>
13
-        <button class="btn btn-icon btn-danger" (click)="cancelModal()"><clr-icon shape="times"></clr-icon></button>
14
-    </div>
15
-  </clr-modal>
16
-
17
-  <div class="clr-row">
18
-    <div class="card clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-12 clr-col-xl-12">
19
-        <div class="card-header">
20
-            Plugins
21
-        </div>
22
-        <clr-alert *ngFor="let entry of alerts" [clrAlertType]="line.severity">
23
-            <clr-alert-item>
24
-                <span class="alert-text">
25
-                    {{line.message}}
26
-                </span>
27
-            </clr-alert-item>
28
-        </clr-alert>
29
-    
30
-        <div *ngIf="loading" class="card-block">
31
-        <span class="spinner spinner-inline"></span>
32
-        </div>
33
-        <div *ngIf="plugins.length !== 0 && !loading" class="card-block">
34
-            <div class="card-text">
35
-                <clr-datagrid>
36
-                    <clr-dg-column>Name</clr-dg-column>
37
-                    <clr-dg-column>Available</clr-dg-column>
38
-                    <clr-dg-column>Installed</clr-dg-column>
39
-                    <clr-dg-column>Status</clr-dg-column>
40
-    
41
-                    <clr-dg-row *clrDgItems="let line of plugins">
42
-                        <clr-dg-cell>{{line.name}}</clr-dg-cell>
43
-                        <clr-dg-cell>
44
-                            <span *ngIf="line.installed != line.available" class="label info">{{line.available}}</span>
45
-                            <span *ngIf="line.installed == line.available">{{line.available}}</span>
46
-                        </clr-dg-cell>
47
-                        <clr-dg-cell>{{line.installed}}</clr-dg-cell>
48
-                        <clr-dg-cell>{{line.status}}</clr-dg-cell>
49
-                        
50
-                        <clr-dg-row-detail *clrIfExpanded>
51
-                            <button *ngIf="line.status === 'Stopped'" class="btn btn-icon btn-success-outline" (click)="start(line.name)"><clr-icon shape="play"></clr-icon></button>
52
-                            <button *ngIf="line.status === 'Running'" class="btn btn-icon btn-warning-outline" (click)="stop(line.name)"><clr-icon shape="pause"></clr-icon></button>
53
-                            <button *ngIf="line.status === 'Stopped'" class="btn btn-icon btn-danger-outline" (click)="delete(line.name)"><clr-icon shape="trash"></clr-icon></button>
54
-                            <button *ngIf="line.status === 'Available'" class="btn btn-icon btn-info-outline" (click)="showConfirmation(line.name)"><clr-icon shape="download"></clr-icon></button>
55
-                            <button *ngIf="line.available !== line.installed && line.status === 'Stopped'" class="btn btn-icon btn-outline " (click)="showConfirmation(line.name)">
56
-                                <clr-icon shape="sync"></clr-icon>
57
-                            </button>                        
58
-                        </clr-dg-row-detail>
59
-                    </clr-dg-row>
60
-                    <clr-dg-footer>
61
-                        <clr-dg-pagination #pagination [clrDgPageSize]="10">
62
-                            <clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">per page</clr-dg-page-size>
63
-                            {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
64
-                            of {{pagination.totalItems}}
65
-                        </clr-dg-pagination>
66
-                    </clr-dg-footer>
67
-                </clr-datagrid>
68
-            </div>
69
-        </div>
70
-        <div class="card-footer">
71
-            <button *ngIf="!reloading" class="btn btn-sm btn-link" (click)="reload()">Check</button>
72
-    
73
-        </div>
74
-    </div>
75
-    </div>
76
-  `
77
-})
78
-export class PluginsComponent implements OnInit {
79
-    plugins = [{
80
-        name: "test",
81
-        available: "0.0.1",
82
-        installed: "0.0.1",
83
-        status: "Running"
84
-    }, {
85
-        name: "test II: Return of test",
86
-        available: "0.0.1",
87
-        installed: "0.0.1",
88
-        status: "Stopped"
89
-    }, {
90
-        name: "test 3",
91
-        available: "0.0.2",
92
-        installed: "",
93
-        status: "Available"
94
-    }, {
95
-        name: "test IV: minor bump",
96
-        available: "0.9.27",
97
-        installed: "0.0.11",
98
-        status: "Stopped"
99
-    },]
100
-
101
-    reloading = false
102
-    updatepending = false
103
-    updateCandidate = ""
104
-
105
-    constructor() { }
106
-
107
-    start(name) {
108
-        this.plugins.find((el) => el.name === name).status = "Running"
109
-    }
110
-
111
-    stop(name) {
112
-        this.plugins.find((el) => el.name === name).status = "Stopped"
113
-    }
114
-
115
-    delete(name) {
116
-        let plugin = this.plugins.find((el) => el.name === name)
117
-        plugin.status = "Available"
118
-        plugin.installed = ""
119
-    }
120
-
121
-    showConfirmation(name) {
122
-        this.updateCandidate = name
123
-        this.updatepending = !this.updatepending
124
-    }
125
-
126
-    download(name) {
127
-        let plugin = this.plugins.find((el) => el.name === name)
128
-        plugin.status = "Stopped"
129
-        plugin.installed = plugin.available
130
-        this.updatepending = !this.updatepending
131
-    }
132
-
133
-    cancelModal() {
134
-        this.updateCandidate = ""
135
-        this.updatepending = !this.updatepending
136
-    }
137
-
138
-    async reload(){
139
-        this.reloading = true
140
-        if(isDevMode()){
141
-            await new Promise((resolve, reject) => {
142
-                setTimeout(resolve, 1000)
143
-            })
144
-            this.plugins = this.plugins.map(plugin => {
145
-                const parts = plugin.available.split('.')
146
-                plugin.available = parts[0]+"."+parts[1]+"."+(parseInt(parts[2])+1)
147
-                return plugin
148
-            })
149
-            this.reloading = false
150
-        }
151
-    }
152
-
153
-    ngOnInit() { }
154
-
155
-}
156
-

+ 0
- 174
src/app/Wallet/btc/address-viewer.component.ts View File

@@ -1,174 +0,0 @@
1
-
2
-
3
-import { Component, OnInit, isDevMode } from '@angular/core';
4
-import { PluginsComponent } from './btc.component';
5
-import { ClrDatagridStringFilterInterface, ClrDatagridNumericFilterInterface, ClrDropdownModule } from '@clr/angular';
6
-declare const fb
7
-@Component({
8
-    selector: 'address-viewer', //!!!!
9
-    template: `
10
-    <div class="clr-row">
11
-        <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">
12
-        <div class="card">    
13
-            <div class="card-header">
14
-                Addresses
15
-            </div>
16
-            <clr-alert *ngFor="let entry of alerts" [clrAlertType]="line.severity">
17
-                <clr-alert-item>
18
-                    <span class="alert-text">
19
-                        {{line.message}}
20
-                    </span>
21
-                </clr-alert-item>
22
-            </clr-alert>
23
-
24
-            <clr-datagrid class="datagrid-compact ">
25
-                <clr-dg-column>Address</clr-dg-column>
26
-                <clr-dg-column>
27
-                    Balance
28
-                </clr-dg-column>
29
-                <clr-dg-column>
30
-                    Pending
31
-                </clr-dg-column>
32
-                <clr-dg-column>
33
-                    Estimate total
34
-                    <clr-dg-numeric-filter [clrDgNumericFilter]="otherBalanceFilter" [clrFilterValue]="[0, null]"></clr-dg-numeric-filter>                
35
-                </clr-dg-column>
36
-
37
-                <clr-dg-row *clrDgItems="let line of regularAddresses">
38
-                    <clr-dg-cell class="monospace" style="word-break: break-all">{{line.address}}</clr-dg-cell>
39
-                    <clr-dg-cell class="monospace">{{line.confirmed.balance | number: '1.8-18'}}</clr-dg-cell>
40
-                    <clr-dg-cell class="monospace">
41
-                        <span *ngIf="line.unconfirmed.balance != 0">
42
-                            {{line.unconfirmed.balance | number: '1.8-18'}} 
43
-                        </span>
44
-                    </clr-dg-cell>
45
-                    <clr-dg-cell class="monospace">{{line.total.balance | number: '1.8-18'}}</clr-dg-cell>
46
-
47
-                    <clr-dg-row-detail *clrIfExpanded >
48
-                        <div class="clr-row">
49
-                            <div class="clr-col-3">
50
-                                <button class="btn btn-info-outline"  (click)="parent.addrExplorer(line.address)">Explorer</button>
51
-                            </div>
52
-
53
-                            <div *ngIf="parent.keys[line.address] != null" class="clr-col-9" style="word-break:break-all">
54
-                                <h6  style="margin-top: 0">Derivation </h6>
55
-                                {{parent.keys[line.address].derivation}}                                
56
-                                <h6> Public key </h6>
57
-                                {{parent.keys[line.address].publicExtendedKey}}
58
-                                <h6> Private key </h6>
59
-                                {{parent.keys[line.address].privateExtendedKey}}
60
-                            </div>
61
-                        </div>
62
-                    </clr-dg-row-detail>
63
-                </clr-dg-row>
64
-
65
-                <clr-dg-footer>
66
-                    <clr-dg-pagination #pagination2 [clrDgPageSize]="10">
67
-                        <clr-dg-page-size [clrPageSizeOptions]="[5,10,20,50,100]">per page</clr-dg-page-size>
68
-                        {{pagination2.firstItem + 1}} - {{pagination2.lastItem + 1}}
69
-                        of {{pagination2.totalItems}}
70
-                    </clr-dg-pagination>
71
-                </clr-dg-footer>
72
-            </clr-datagrid>
73
-        </div>
74
-        </div>
75
-
76
-        <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">
77
-        <div class="card">    
78
-            <div class="card-header">
79
-                Change Addresses
80
-            </div>
81
-            <clr-alert *ngFor="let entry of alerts" [clrAlertType]="line.severity">
82
-                <clr-alert-item>
83
-                    <span class="alert-text">
84
-                        {{line.message}}
85
-                    </span>
86
-                </clr-alert-item>
87
-            </clr-alert>
88
-
89
-            <clr-datagrid class="datagrid-compact">
90
-                <clr-dg-column>Address</clr-dg-column>
91
-                <clr-dg-column>
92
-                    Balance
93
-                </clr-dg-column>
94
-                <clr-dg-column>
95
-                    Pending
96
-                </clr-dg-column>
97
-                <clr-dg-column>
98
-                    Estimate total
99
-                    <clr-dg-numeric-filter [clrDgNumericFilter]="balanceFilter" [clrFilterValue]="[0.00000001, null]"></clr-dg-numeric-filter>
100
-                </clr-dg-column>
101
-
102
-                <clr-dg-row *clrDgItems="let line of changeAddresses">
103
-                    <clr-dg-cell class="monospace" style="word-break: break-all">{{line.address}}</clr-dg-cell>
104
-                    <clr-dg-cell class="monospace">{{line.confirmed.balance | number: '1.8-18'}}</clr-dg-cell>
105
-                    <clr-dg-cell class="monospace">
106
-                        <span *ngIf="line.unconfirmed.balance != 0">
107
-                          {{line.unconfirmed.balance | number: '1.8-18'}} 
108
-                        </span>
109
-                    </clr-dg-cell>
110
-                    <clr-dg-cell class="monospace">{{line.total.balance | number: '1.8-18'}}</clr-dg-cell>
111
-
112
-                    <clr-dg-row-detail *clrIfExpanded >
113
-                        <div class="clr-row">
114
-                            <div class="clr-col-3">
115
-                                <button class="btn btn-info-outline" (click)="parent.addrExplorer(line.address)">Explorer</button>
116
-                                <p>
117
-                            </div>
118
-
119
-                            <div *ngIf="parent.keys[line.address] != null" class="clr-col-9" style="word-break:break-all">
120
-                                <h6  style="margin-top: 0">Derivation </h6>
121
-                                {{parent.keys[line.address].derivation}}
122
-                                <h6> Public key </h6>
123
-                                {{parent.keys[line.address].publicExtendedKey}}
124
-                                <h6> Private key </h6>
125
-                                {{parent.keys[line.address].privateExtendedKey}}
126
-                            </div>
127
-                        </div>
128
-                    </clr-dg-row-detail>
129
-                </clr-dg-row>
130
-
131
-                <clr-dg-footer>
132
-                    <clr-dg-pagination #pagination [clrDgPageSize]="10">
133
-                        <clr-dg-page-size [clrPageSizeOptions]="[5,10,20,50,100]">per page</clr-dg-page-size>
134
-                        {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
135
-                        of {{pagination.totalItems}}
136
-                    </clr-dg-pagination>
137
-                </clr-dg-footer>
138
-            </clr-datagrid>
139
-        </div>
140
-        </div>
141
-    </div>
142
-  `
143
-})
144
-export class AddressViewerComponent implements OnInit{    
145
-    balanceFilter = new BalanceFilter()
146
-    otherBalanceFilter = new BalanceFilter()
147
-    regularAddresses = []
148
-    changeAddresses = []
149
-    keys = {}
150
-    parent:PluginsComponent
151
-    ngOnInit() { }
152
-
153
-    setParent(parent:PluginsComponent){
154
-        this.parent = parent
155
-    }
156
-
157
-    setRegularAddresses(addresses){
158
-        this.regularAddresses = addresses
159
-    }
160
-
161
-    setChangeAddresses(addresses){
162
-        this.changeAddresses = addresses
163
-    }    
164
-}
165
-
166
-class BalanceFilter implements ClrDatagridNumericFilterInterface<any>{
167
-    accepts(item: any, low: number, high: number): boolean {
168
-        high = parseFloat(""+high)
169
-        low = parseFloat(""+low)
170
-        const balance = (parseFloat(item.unconfirmed.balance) + parseFloat(item.confirmed.balance))
171
-        return (Number.isNaN(low)  || balance >= low) 
172
-            && (Number.isNaN(high) || balance <= high)
173
-    }
174
-}

+ 0
- 566
src/app/Wallet/btc/btc.component.ts View File

@@ -1,566 +0,0 @@
1
-import { Component, OnInit, isDevMode, ViewChild, AfterViewInit } from '@angular/core';
2
-import { WalletGeneratorComponent } from './wallet-generator.component';
3
-import { WalletPickerComponent } from './wallet-picker.component';
4
-import { HDKey } from "btc-hdkey"
5
-import { AddressViewerComponent } from './address-viewer.component';
6
-const fetch = require("node-fetch")
7
-const coinselect = require('coinselect/accumulative')
8
-import { TransactionBuilder, Signer } from 'bitcoinjs-lib'
9
-import { networks } from 'bitcoinjs-lib'
10
-let feeRate = 55 // satoshis per byte
11
-
12
-const hdkey = new HDKey()
13
-declare const fb
14
-@Component({
15
-    selector: 'plugins', //!!!!
16
-    template: `
17
-
18
-<wallet-generator></wallet-generator>
19
-
20
-<!-- loading -->
21
-<clr-modal  [clrModalSize]="'md'" [(clrModalOpen)]="loading">
22
-        
23
-    <div class="modal-body ">
24
-        <span class="spinner spinner-inverse spinner-md">
25
-            Loading...
26
-        </span> 
27
-        <h3>Checking addresses</h3> <br>
28
-        Checking the first {{loadingN*115}} addresses. <br>
29
-        Found addresses containing balance: {{regaddresses.length + changeaddresses.length}}
30
-    </div>
31
-</clr-modal>
32
-<!-- / loading -->
33
-
34
-<!-- row 0 -->
35
-<div *ngIf="mode.net == 'testnet'" class="clr-all-12">
36
-    <div class="card">
37
-                            
38
-        <div class="card-header">
39
-            Faucet
40
-        </div>
41
-        <div class="card-block" >
42
-            <button class="btn btn-icon btn-info-outline" onclick="window.open('https://testnet-faucet.mempool.co/', '_blank')"><clr-icon shape="fuel"></clr-icon></button>            
43
-            <button class="btn btn-icon btn-info-outline" onclick="window.open('https://bitcoinfaucet.uo1.net/', '_blank')"><clr-icon shape="fuel"></clr-icon></button>            
44
-            <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>            
45
-            <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>            
46
-        </div>
47
-        <div class="card-footer" >
48
-            Get free test-BTC
49
-        </div>
50
-        
51
-        
52
-    </div>
53
-</div>
54
-
55
-<!-- row 1 -->
56
-<div class="clr-all-12">
57
-
58
-    <!-- wallet picker + send box + balance box -->
59
-    <div class="clr-row">
60
-        
61
-        <!-- left column -->
62
-        <div class="clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-5 clr-col-xl-5">
63
-
64
-            <!-- Wallet picker -->
65
-            <div class="clr-row">
66
-                <walletpicker class="clr-all-12"></walletpicker>
67
-            </div>
68
-            <!-- /Wallet picker -->
69
-
70
-            <!-- Send box -->
71
-            <div *ngIf="mode.type=='private'" class="clr-row">
72
-
73
-                <div class="clr-all-12">
74
-                    <div class="card">
75
-                        
76
-                        <div class="card-header">
77
-                            Send
78
-                        </div>
79
-                        <clr-alert *ngFor="let error of errors"  [clrAlertType]="'danger'">
80
-                            <clr-alert-item>
81
-                                <span class="alert-text">
82
-                                    {{error}}
83
-                                </span>
84
-                            </clr-alert-item>
85
-                        </clr-alert>
86
-                        <clr-alert *ngFor="let success of successes"  [clrAlertType]="'success'">
87
-                            <clr-alert-item>
88
-                                <span class="alert-text">
89
-                                    {{success}}
90
-                                </span>
91
-                            </clr-alert-item>
92
-                        </clr-alert>
93
-                        <div class="card-block" >
94
-                            
95
-                            <div class="clr-row" style="padding-left:12px; padding-right:12px">
96
-                                <input [(ngModel)]="sendTo" type="text" placeholder="To address" class="clr-input clr-col-12" />
97
-                                <input [(ngModel)]="sendAmount" type="text" min="0" placeholder="Amount" class="clr-input clr-col-12" style="margin-top:12px; margin-borrom:12px" />
98
-                            </div>
99
-                        </div>
100
-                        <div class="card-footer" >
101
-                            <button class="btn btn-success-outline" (click)="createAndSendTx(sendTo, sendAmount)">send</button>
102
-                        </div>
103
-
104
-                    </div>
105
-                </div>
106
-
107
-            </div>
108
-            <!-- /Send Box -->
109
-
110
-        </div>
111
-        <!-- /left column -->
112
-        
113
-        <!-- right column -->
114
-        <div class="clr-col-12 clr-col-sm-12 clr-col-md-12 clr-col-lg-7 clr-col-xl-7" >
115
-            
116
-            <!-- Balance box -->
117
-            <div *ngIf="rootkey.publicExtendedKey != ''" class="card">
118
-                <div class="card-header" style="word-break: break-all">
119
-                    <span *ngIf="mode.net=='testnet'" class="label label-danger">Testnet</span>{{rootkey.publicExtendedKey}} 
120
-                </div>
121
-                <clr-alert *ngFor="let entry of alerts" [clrAlertType]="line.severity">
122
-                    <clr-alert-item>
123
-                        <span class="alert-text">
124
-                            {{line.message}}
125
-                        </span>
126
-                    </clr-alert-item>
127
-                </clr-alert>
128
-            
129
-                <div class="card-block">
130
-                    <h3 style="margin-top:12px">{{balanceDisplay.total | number: '1.8-18'}} BTC </h3>
131
-                    <p class="monospace">
132
-                        <span *ngIf="balanceDisplay.unconfirmed < 0">&nbsp;</span>{{balanceDisplay.confirmed | number: '1.18'}} BTC confirmed<br />
133
-                        {{balanceDisplay.unconfirmed | number: '1.18'}} BTC pending
134
-                    </p>
135
-                    <p *ngIf="mode.type=='private'">
136
-                        <clr-icon shape="key"></clr-icon> Private key available
137
-                    </p>
138
-                </div>
139
-
140
-                <div class="card-footer" >
141
-                    <button class="btn btn-icon" (click)="reload()"> <clr-icon shape="refresh"></clr-icon> Reload </button>
142
-                </div>
143
-            </div>
144
-            <!-- Balance box-->
145
-        
146
-        </div>
147
-        <!-- right column -->
148
-
149
-    </div>
150
-    <!-- /row wallet picker + send box + balance box -->
151
-
152
-        <div class="clr-all-12" style="padding-left:0px; padding-right: 0px">
153
-            <address-viewer></address-viewer>
154
-        </div>
155
-</div>
156
-<!-- /row 1 -->
157
-  `
158
-})
159
-export class PluginsComponent implements AfterViewInit {
160
-    errors:string[] = []
161
-    successes:string[] = []
162
-    wallets:WalletStore = {}
163
-    txToSend:any
164
-    rootkey:bip32Keypair = {publicExtendedKey: "",privateExtendedKey: ""}
165
-    keys:KeyStore = {}
166
-    regaddresses:AddressLine[] = []
167
-    changeaddresses:AddressLine[] = []
168
-    balanceDisplay = {
169
-        confirmed: 0,
170
-        total: 0,
171
-        unconfirmed: 0
172
-    }
173
-    mode : {
174
-        type:keyType,
175
-        net:networkType
176
-    } = {
177
-        net: "testnet",
178
-        type: "public"
179
-    }
180
-    sendTo:string
181
-    sendAmount:number
182
-    loading = false
183
-    loadingN = 1
184
-
185
-    @ViewChild(AddressViewerComponent, {static: false})
186
-    AddressViewerComponent:AddressViewerComponent
187
-  
188
-    @ViewChild(WalletGeneratorComponent, {static: false})
189
-    WalletGeneratorComponent:WalletGeneratorComponent
190
-
191
-    @ViewChild(WalletPickerComponent, {static: false})
192
-    WalletPickerComponent:WalletPickerComponent
193
-
194
-    ngAfterViewInit(): void {
195
-        this.WalletGeneratorComponent.setParent(this)
196
-        this.WalletPickerComponent.setParent(this)
197
-        this.AddressViewerComponent.setParent(this)
198
-
199
-        window['btc'] = this
200
-
201
-        this.loadKey("tprv8cXm1S7PGS2fHuLjZajuDZZsvxerzv4zZJJAhkLAWZzwz5rE7efHm31xsqpzfoGMHBNC8bkRcsjiMdmkSuNn5C1qNqk7rrk1pCuhk4HfVak")
202
-    }
203
-
204
-    addWallet(wallet){
205
-        /* store somewhere */
206
-
207
-        this.wallets[wallet.name] = wallet
208
-        this.WalletPickerComponent.setWallets(this.wallets)
209
-        
210
-    }
211
-
212
-    showWizard(){
213
-        this.WalletGeneratorComponent.open()
214
-    }
215
-
216
-    loadKey(key:string){
217
-        this.wallets = {}
218
-        this.txToSend = null
219
-        this.sendTo = ""
220
-        this.regaddresses = []
221
-
222
-        const t = hdkey.checkHDKey(key)
223
-        if(t){
224
-            console.log(t)
225
-            this.mode = t
226
-        }
227
-
228
-        this.rootkey = hdkey.HDKeyFromExtendedKey(key)
229
-        this.reload()
230
-    }
231
-
232
-    async reload():Promise<void>{
233
-        this.loading = true
234
-        this.loadingN = 1
235
-        this.keys = {}
236
-        this.balanceDisplay.total = 0
237
-        this.balanceDisplay.unconfirmed = 0
238
-        this.balanceDisplay.confirmed = 0
239
-        await this.refresh()
240
-        this.loading = false
241
-    }
242
-
243
-    async refresh():Promise<void>{
244
-        let p1 = this.updateChange()
245
-        let p2 = this.updateBalance()
246
-
247
-        let balances:GrandTotal[] = await Promise.all([p1,p2])
248
-        balances.forEach(balance => {
249
-            this.balanceDisplay.confirmed += balance.confirmed
250
-            this.balanceDisplay.total += balance.total
251
-            this.balanceDisplay.unconfirmed += balance.unconfirmed
252
-        })
253
-
254
-        this.AddressViewerComponent.setChangeAddresses(this.changeaddresses)
255
-        this.AddressViewerComponent.setRegularAddresses(this.regaddresses)
256
-    }
257
-
258
-    getAddresses(rootAddr: string, n = 10, skip = 0, changeAddresses = false): string[] | null{
259
-        let addresses: string[] = []
260
-        for(let i = skip; i < skip+n; i++){
261
-            let addr
262
-            if(changeAddresses){
263
-                addr = hdkey.deriveAddress(rootAddr, i, 'm/1/')
264
-            }else{
265
-                addr = hdkey.deriveAddress(rootAddr, i)
266
-            }
267
-            if(!addr){
268
-                return
269
-            }
270
-            addresses.push(addr)
271
-        }
272
-        return addresses
273
-    }
274
-
275
-    async fetchAddresses(addresses:string[], network:networkType): Promise<{success:boolean, address?:any, addresses?:any}>{
276
-        let lookupstr = addresses.join(',')
277
-        try{
278
-            let r = await fetch(api[network]+'/address/'+lookupstr, {
279
-                'method':'GET',
280
-                'mode':'cors',
281
-                'data': {limit: 200}
282
-            })
283
-            if(r.status !== 200){
284
-                return {success: false}
285
-            }
286
-
287
-            let json = (await r).json()
288
-            return json
289
-        }catch(e){
290
-            return {success: false}
291
-        }
292
-    }
293
-
294
-    async getAddressInfos(rootAddr: string, n = 10, skip = 0, changeAddresses = false): Promise<any>{
295
-        const t = hdkey.checkHDKey(rootAddr)
296
-        if(!t){
297
-            return false
298
-        }
299
-        const addresses = this.getAddresses(rootAddr, n, skip, changeAddresses)
300
-        return await this.fetchAddresses(addresses, t.net)
301
-        
302
-    }
303
-
304
-    async getTxs(address: string, type:networkType){
305
-        try{
306
-            let r = await fetch(api[type]+'/address/'+address, {
307
-                'method':'GET',
308
-                'mode':'cors'
309
-            })
310
-            if(r.status !== 200){
311
-                return {success: false}
312
-            }
313
-
314
-            return (await r).json()
315
-        }catch(e){
316
-            console.warn ("getTxs", e)
317
-        }
318
-    }
319
-
320
-    async getUnspentTxs(addresses:string[], type:networkType):Promise<any>{
321
-        let lookupstr = addresses.join(',')
322
-        
323
-        try{
324
-            let r = await fetch(api[type]+'/address/'+lookupstr+'/unspent', {
325
-                'method':'GET',
326
-                'mode':'cors'
327
-            })
328
-            if(r.status !== 200){
329
-                return {success: false}
330
-            }
331
-
332
-            return (await r).json()
333
-        }catch(e){
334
-            console.warn ("getUnspentTxs", e)
335
-            return {success: false}
336
-        }
337
-    }
338
-
339
-
340
-    getKeyForAddress(keyName){
341
-        return this.keys[keyName]
342
-    }
343
-
344
-    calculateTotal(addresses:AddressLine[]):GrandTotal{
345
-        const resMap: any = addresses.reduce((o1, o2)=>{o1[o2.address] = o2; return o1}, {})
346
-        const total: any = Object.values(resMap).reduce((accum:GrandTotal, obj:AddressLine) => {
347
-            accum.confirmed += parseFloat(<any>obj.confirmed.balance)
348
-            accum.unconfirmed += parseFloat(<any>obj.unconfirmed.balance)
349
-            accum.total += parseFloat(<any>obj.confirmed.balance) + parseFloat(<any>obj.unconfirmed.balance)
350
-            return accum
351
-        },{
352
-            confirmed: 0,
353
-            unconfirmed: 0,
354
-            total: 0
355
-        })
356
-        
357
-        return total
358
-    }
359
-
360
-    async updateBalance():Promise<GrandTotal>{
361
-        let n = 1
362
-        let res: { success: boolean; addresses: any; address: any; }
363
-        this.regaddresses = []
364
-        while(true){
365
-            this.loadingN = n
366
-            try{
367
-                res = await this.getAddressInfos(this.rootkey.publicExtendedKey, 115*n, 115*(n-1))
368
-            }catch(e){
369
-                break
370
-            }
371
-            if(res.success === true){
372
-                if('addresses' in res){ // multiple
373
-                    this.regaddresses = [...this.regaddresses, ...res.addresses]
374
-                }
375
-                if('address' in res){
376
-                    this.regaddresses.push(res.address)
377
-                }
378
-                n++
379
-            }else{
380
-                console.warn(`This error is a result of a failed fetch request. 
381
-These are always shown by the browser and cannot be hidden (a design decision)
382
-They are completely safe and mean no more addresses were found`)
383
-                console.log('No more balance found after attempting ', 115*n, 'addresses')
384
-                if(this.mode.type == "private"){
385
-                    for(let i = 0; i < 115*n+1; i++){
386
-                        const keyN = hdkey.deriveKey(this.rootkey.privateExtendedKey, i)
387
-                        const addrN = hdkey.addressFromHDKey(keyN._publicKey, this.mode.net)
388
-                        keyN.derivation = i
389
-                        this.keys[addrN] = keyN
390
-                    }
391
-                }
392
-                break
393
-            }
394
-        }
395
-
396
-        //add an extra empty address at the end
397
-        const extraAddr = hdkey.deriveAddress(this.rootkey.publicExtendedKey, this.regaddresses.length)
398
-        this.regaddresses.push({
399
-            address: <string>extraAddr,
400
-            confirmed: {balance: 0},
401
-            unconfirmed: {balance: 0},
402
-            total: {balance: 0},
403
-        })
404
-        
405
-        return this.calculateTotal(this.regaddresses)        
406
-    }
407
-
408
-    async updateChange():Promise<GrandTotal>{
409
-        let n = 1
410
-        this.changeaddresses = []
411
-        while(true){
412
-            let res
413
-            try{
414
-                res = await this.getAddressInfos(this.rootkey.publicExtendedKey, 115*n, 115*(n-1), true)
415
-            }catch(e){
416
-                break
417
-            }
418
-            if(res.success === true){
419
-                if('addresses' in res){ // multiple
420
-                    this.changeaddresses = [...this.changeaddresses, ...res.addresses]
421
-                }
422
-                if('address' in res){
423
-                    this.changeaddresses.push(res.address)
424
-                }
425
-                n++
426
-            }else{
427
-                console.warn(`This error is a result of a failed fetch request. 
428
-These are always shown by the browser and cannot be hidden (a design decision)
429
-They are completely safe and mean no more addresses were found`)
430
-                console.log('No more change balance found after attempting ', 115*n, 'addresses')
431
-                if(this.mode.type == "private"){
432
-                    //make keypairs for addresses
433
-                    for(let i = 0; i < 115*n; i++){
434
-                        const keyN = hdkey.deriveKey(this.rootkey.privateExtendedKey, i, 'm/1/')
435
-                        const addrN = hdkey.addressFromHDKey(keyN._publicKey, this.mode.net)
436
-                        keyN.derivation = i
437
-                        this.keys[addrN] = keyN
438
-                    }
439
-                }
440
-                break
441
-            }
442
-        }
443
-
444
-        return this.calculateTotal(this.changeaddresses)        
445
-    }
446
-
447
-    async createAndSendTx(target:string, value:number){
448
-
449
-        if(target == null || typeof target !== 'string' ||  target === '' || value == null || value <= 0 ){
450
-            this.errors.push('Bad inputs. Expected bitcoin address and number')
451
-            return
452
-        }
453
-
454
-        if(value > this.balanceDisplay.confirmed){
455
-            this.errors.push('Insufficient funds')
456
-            return
457
-        }
458
-
459
-        let addresses: string[] = [...this.regaddresses.map(a => a.address), ...this.changeaddresses.map(a => a.address)]
460
-        const txs = await this.getUnspentTxs(addresses, this.mode.net)
461
-
462
-        if(txs == null || txs.success !== true || txs.unspent.length === 0){
463
-            this.errors.push('No UTXOs found')
464
-            return
465
-        }
466
-
467
-        const utxos = txs.unspent.map(t => {
468
-            return {
469
-                address: t.addresses[0],
470
-                txId: t.txid,
471
-                vout: t.n,
472
-                value: t.value * 100000000
473
-            }
474
-        })
475
-
476
-        let { inputs, outputs, fee } = coinselect(utxos, [{address: target, value: value*100000000}], feeRate)
477
-
478
-        // .inputs and .outputs will be undefined if no solution was found
479
-        if (!inputs || !outputs){
480
-            this.errors.push('Could not build a valid transaction')
481
-            return
482
-        }
483
-
484
-        const txb = new TransactionBuilder(networks[this.mode.net])
485
-
486
-
487
-        txb.setVersion(1)
488
-        inputs.forEach((input) => {
489
-            txb.addInput(input.txId, input.vout)
490
-        })
491
-        outputs.forEach((output) => {
492
-            if (!output.address) {
493
-                output.address =  hdkey.deriveAddress(this.rootkey.publicExtendedKey, this.changeaddresses.length, 'm/1/')
494
-            }
495
-            txb.addOutput(output.address, output.value)
496
-        })
497
-        inputs.forEach((input, i) => {
498
-            txb.sign(i, <Signer>this.keys[input.address])            
499
-        })
500
-
501
-        this.txToSend = txb.build()
502
-
503
-        this.sendTx()
504
-    }
505
-
506
-    private async sendTx(){
507
-        if(this.txToSend == null){
508
-            this.errors.push('No transaction to send!')
509
-            return
510
-        }
511
-
512
-        let url = api[this.mode.net]+"/pushtx"
513
-        let r
514
-        try{
515
-            r = await fetch(url, {
516
-                'method':'POST',
517
-                'body': JSON.stringify({'hex': this.txToSend.toHex()})
518
-            })
519
-        }catch(e){
520
-           console.warn("sendTx", e) 
521
-           return
522
-        }
523
-        this.txToSend = null
524
-        if(r.status === 200){
525
-            this.errors = []
526
-            this.successes.push("Sent "+this.sendAmount+" to "+this.sendTo)
527
-            this.reload()
528
-        }else{
529
-            this.errors.push('The API '+url+' returned a non-200 error code '+r.status+' '+r.statusText)
530
-        }
531
-    }
532
-
533
-    addrExplorer(address){
534
-        const url = this.mode.net === 'testnet'?'https://live.blockcypher.com/btc-testnet/address/':'https://live.blockcypher.com/btc/address/'
535
-        window.open(url+address, '_blank')
536
-    }
537
-}
538
-
539
-export type KeyStore = {[keyname in string]: bip32Keypair & Signer}
540
-
541
-export type AddressLine = {
542
-    address: string,
543
-    confirmed: {balance: number},
544
-    unconfirmed: {balance: number},
545
-    total: {balance: number},
546
-}
547
-
548
-type networkType = 'testnet' | 'mainnet'
549
-type keyType = 'public' | 'private'
550
-type WalletStore = {
551
-    [address in string]:{
552
-        key:string
553
-        name:string
554
-    } 
555
-}
556
-type GrandTotal = {
557
-    confirmed: number,
558
-    unconfirmed: number,
559
-    total: number
560
-}
561
-type bip32Keypair = { publicExtendedKey: string, privateExtendedKey: string }
562
-
563
-const api = {
564
-    testnet: 'https://testnet-api.smartbit.com.au/v1/blockchain',
565
-    mainnet: 'https://api.smartbit.com.au/v1/blockchain'
566
-}

+ 0
- 266
src/app/Wallet/btc/wallet-generator.component.ts View File

@@ -1,266 +0,0 @@
1
-import { Component, OnInit, isDevMode, ViewChild } from '@angular/core';
2
-import { ClrWizard } from '@clr/angular';
3
-import { HDKey } from "btc-hdkey"
4
-import { PluginsComponent } from './btc.component';
5
-
6
-declare const fb
7
-@Component({
8
-    selector: 'wallet-generator', //!!!!
9
-    template: `
10
-    <clr-wizard #wizard [(clrWizardOpen)]="mdOpen" [clrWizardForceForwardNavigation]="true" clrWizardSize="lg">
11
-        <clr-wizard-title>Bitcoin wallet generator and importer</clr-wizard-title>
12
-
13
-        <clr-wizard-button [type]="'cancel'">Cancel</clr-wizard-button>
14
-        <clr-wizard-button [type]="'previous'">Back</clr-wizard-button>
15
-        <clr-wizard-button [type]="'next'">Next</clr-wizard-button>
16
-        <clr-wizard-button [type]="'finish'">Finish</clr-wizard-button>
17
-
18
-        <clr-wizard-page (clrWizardPageCustomButton)="doCustomClick($event)">
19
-            <ng-template clrPageTitle>Menemonic/BIP39 (optional)</ng-template>
20
-            <ng-template clrPageNavTitle>
21
-                Menemonic/BIP39
22
-            </ng-template>
23
-            <p>
24
-            A menemonic is a collection of words that is supposed to be easier to remember than a complex seed. It may be used to reconstruct the private key.
25
-            </p>
26
-            <p>
27
-            Enter your menemonic below or generate a new one. 
28
-            </p>
29
-            <textarea [(ngModel)]="menemonic" class="clr-textarea" style="margin-top: 24px; width: 100%; height: 200px">{{menemonic}}</textarea>
30
-            <div class="clr-row">
31
-                <clr-checkbox-wrapper class="clr-col">
32
-                    <input type="checkbox" clrCheckbox value="testnet" name="testnet1" [(ngModel)]="testnet" />
33
-                    <label>testnet</label>
34
-                </clr-checkbox-wrapper>
35
-                <button class="btn btn-outline-success clr-col" (click)="generateMenemonic()">{{"Generate"}}</button>
36
-            </div>
37
-            <ng-template clrPageButtons>
38
-                <clr-wizard-button [type]="'cancel'">Cancel</clr-wizard-button>
39
-                <clr-wizard-button [type]="'menemonic-next'">{{menemonic.length==0?"Skip":"Next"}}</clr-wizard-button>
40
-            </ng-template>
41
-        </clr-wizard-page>
42
-
43
-        <clr-wizard-page (clrWizardPageCustomButton)="doCustomClick($event)">
44
-            <ng-template clrPageTitle>Seed phrase (optional)</ng-template>
45
-            <ng-template clrPageNavTitle>
46
-                Seed phrase
47
-            </ng-template>
48
-            <p>
49
-            If you entered a menemonic in the previous step, a seed was generated from it.
50
-            </p>
51
-            <p>
52
-            If you would like to use your own seed enter it below. Use something sufficiently hard to guess.
53
-            </p>
54
-            <textarea class="clr-textarea" (ngModelChange)="updateSeed()" [(ngModel)]="seed" style="margin-top: 24px; width: 100%; height: 200px">{{seed}}</textarea>
55
-            <clr-checkbox-wrapper>
56
-                <input type="checkbox" clrCheckbox value="testnet" name="testnet2" [(ngModel)]="testnet" />
57
-                <label>testnet</label>
58
-            </clr-checkbox-wrapper>
59
-            <ng-template clrPageButtons>
60
-                <clr-wizard-button [type]="'cancel'">Cancel</clr-wizard-button>
61
-                <clr-wizard-button [type]="'back'">Back</clr-wizard-button>
62
-                <clr-wizard-button [type]="'seed-next'">{{seed.length==0?"Skip":"Next"}}</clr-wizard-button>
63
-            </ng-template>
64
-        </clr-wizard-page>
65
-
66
-        <clr-wizard-page [clrWizardPageNextDisabled]="keyInvalid" (clrWizardPageCustomButton)="doCustomClick($event)">
67
-            <ng-template clrPageTitle>Extended Key/BIP32</ng-template>
68
-            <p>
69
-            Accepts keys in the xpub and xprv (BIP32) format
70
-            </p>
71
-            <textarea [(ngModel)]="key" (ngModelChange)="updateKey()"class="clr-textarea" style="margin-top: 24px; width: 100%; height: 200px"></textarea>
72
-        </clr-wizard-page>
73
-
74
-        <clr-wizard-page class="break-word" (clrWizardPageCustomButton)="doCustomClick($event)">
75
-            <ng-template clrPageTitle>Confirm</ng-template>
76
-
77
-            <div class="alert alert-danger" role="alert">
78
-                <div class="alert-items">
79
-                    <div class="alert-item static">
80
-                        <div class="alert-icon-wrapper">
81
-                            <clr-icon class="alert-icon" shape="exclamation-circle"></clr-icon>
82
-                        </div>
83
-                        <span class="alert-text">
84
-                            Do not give any of this information to other people! Even your public key holds the power to correlate all your addresses back to you! 
85
-                        </span>
86
-                    </div>
87
-                </div>
88
-            </div>
89
-            <div *ngIf="keypair.privateExtendedKey != null && keypair.privateExtendedKey.length != 0" class="alert alert-warning" role="alert">
90
-                <div class="alert-items">
91
-                    <div class="alert-item static">
92
-                        <div class="alert-icon-wrapper">
93
-                            <clr-icon class="alert-icon" shape="exclamation-circle"></clr-icon>
94
-                        </div>
95
-                        <span class="alert-text">
96
-                            WARNING: A private key is not required for operating frontblock
97
-                        </span>
98
-                    </div>
99
-                </div>
100
-            </div>
101
-            <div *ngIf="keypair.privateExtendedKey != null && keypair.privateExtendedKey.length != 0" class="alert alert-info" role="alert">
102
-                <div class="alert-items">
103
-                    <div class="alert-item static">
104
-                        <div class="alert-icon-wrapper">
105
-                            <clr-icon class="alert-icon" shape="exclamation-circle"></clr-icon>
106
-                        </div>
107
-                        <span class="alert-text">
108
-                            HINT: You can exclusively store the public key by going back one step and importing the xpub you just created
109
-                        </span>
110
-                    </div>
111
-                </div>
112
-            </div>
113
-            <table class="table">
114
-                <thead>
115
-                    <tr>
116
-                        <th class="left">Type</th>
117
-                        <th class="left">Value</th>
118
-                    </tr>
119
-                </thead>
120
-                <tbody>
121
-                    <tr *ngIf="menemonic.length != 0">
122
-                        <td class="left"> menemonic</td>
123
-                        <td class="left">{{menemonic}}</td>
124
-                    </tr>
125
-                    <tr *ngIf="seed.length != 0">
126
-                        <td class="left"> seed</td>
127
-                        <textarea rows="3" class="clr-textarea left" [ngModel]="seed" style="width: 100%"></textarea>
128
-                    </tr>
129
-                    <tr>
130
-                        <td class="left"> xpub</td>
131
-                        <textarea rows="3" class="clr-textarea left" [ngModel]="keypair.publicExtendedKey" style="width: 100%"></textarea>
132
-                    </tr>
133
-                    <tr *ngIf="keypair.privateExtendedKey != null && keypair.privateExtendedKey.length != 0">
134
-                        <td class="left"> xprv</td>
135
-                        <textarea rows="3" class="clr-textarea left" [ngModel]="keypair.privateExtendedKey" style="width: 100%"></textarea>
136
-                    </tr>
137
-                </tbody>
138
-            </table>
139
-            <clr-checkbox-wrapper>
140
-                <input type="checkbox" clrCheckbox value="option1" name="options" />
141
-                <label>I understand this is important</label>
142
-            </clr-checkbox-wrapper>
143
-            <ng-template clrPageButtons>
144
-                <clr-wizard-button [type]="'cancel'">Cancel</clr-wizard-button>
145
-                <clr-wizard-button [type]="'back'">Back</clr-wizard-button>
146
-                <clr-wizard-button class="btn btn-success" [type]="'myfinish'">Finish</clr-wizard-button>
147
-            </ng-template>
148
-        </clr-wizard-page>
149
-    </clr-wizard>
150
- 
151
-  `
152
-})
153
-export class WalletGeneratorComponent implements OnInit {
154
-    @ViewChild("wizard", {static: false}) wizard: ClrWizard;
155
-    key:string = ""
156
-    keyInvalid = true
157
-    accept = false
158
-    seed:string = ""
159
-    mdOpen: boolean = false
160
-    checkKey: boolean = true
161
-    menemonic:string = ""
162
-    keypair: any = {}
163
-    testnet: boolean = false
164
-    profileName
165
-    private hdKey = new HDKey()
166
-    private parent:PluginsComponent
167
-
168
-    ngOnInit() { }
169
-
170
-    open(){
171
-        this.key = ""
172
-        this.keyInvalid = true
173
-        this.seed = ""
174
-        this.checkKey = true
175
-        this.menemonic = ""
176
-        this.keypair = {}
177
-        this.testnet = false
178
-        this.wizard.reset()
179
-        this.mdOpen = true
180
-    }
181
-
182
-    setParent(parent:PluginsComponent){
183
-        this.parent = parent
184
-    }
185
-
186
-    async generateMenemonic(){
187
-        this.menemonic = this.hdKey.randomMenemonic()
188
-    }
189
-
190
-    async seedFromMenemonic(){
191
-        try{
192
-            this.seed = this.hdKey.seedFromMenemonic(this.menemonic)
193
-        }catch(e){
194
-            /* invalid menemonic */
195
-            console.log(e)
196
-        }
197
-    }
198
-
199
-    async accountFromSeed(){
200
-        this.keypair = this.hdKey.deriveAccount(this.seed, this.testnet?"testnet":"mainnet", 0)
201
-        console.log(this.keypair)
202
-        this.key = this.keypair.privateExtendedKey != null?this.keypair.privateExtendedKey:this.keypair.publicExtendedKey
203
-        this.keyInvalid = false
204
-    }
205
-
206
-    async importKey(){
207
-        this.hdKey.HDKeyFromExtendedKey(this.key)
208
-    }
209
-
210
-    checkBip32(){
211
-        return this.hdKey.checkHDKey(this.keypair.privateExtendedKey != null?this.keypair.privateExtendedKey:this.keypair.publicExtendedKey)
212
-    }
213
-
214
-    finish(){
215
-        this.parent.addWallet({
216
-            name: this.key.substr(4,15),
217
-            key: this.key
218
-        })
219
-    }
220
-
221
-    public doCustomClick(buttonType: string): void {
222
-        if ("menemonic-next" === buttonType) {
223
-            if(this.menemonic.length != 0){
224
-                this.seedFromMenemonic()
225
-            }
226
-            this.wizard.next();
227
-        }
228
-
229
-        if ("myfinish" === buttonType) {
230
-            this.finish()
231
-            this.wizard.close()
232
-        }
233
-
234
-        if ("seed-next" === buttonType) {
235
-            if(this.seed.length != 0){
236
-                this.accountFromSeed()
237
-            }
238
-            this.wizard.next();
239
-        }
240
-
241
-        if ("back" === buttonType) {
242
-            this.wizard.previous();
243
-        }
244
-    }
245
-
246
-    updateSeed(){
247
-        this.menemonic = ""
248
-    }
249
-
250
-    updateKey(){
251
-        this.keyInvalid = true
252
-        this.menemonic = ""
253
-        this.seed = ""
254
-        let key
255
-        try{
256
-            key = this.hdKey.HDKeyFromExtendedKey(this.key)
257
-        }catch(e){
258
-            /* invalid key */
259
-            console.log("bad key")
260
-        }
261
-        if(key){
262
-            this.keypair = key
263
-            this.keyInvalid = false
264
-        }
265
-    }
266
-}

+ 0
- 50
src/app/Wallet/btc/wallet-picker.component.ts View File

@@ -1,50 +0,0 @@
1
-
2
-
3
-import { Component, OnInit, isDevMode } from '@angular/core';
4
-import { PluginsComponent } from './btc.component';
5
-declare const fb
6
-@Component({
7
-    selector: 'walletpicker', //!!!!
8
-
9
-    template: `
10
-    <div class="card" style="overflow:hidden; padding-bottom:12px">
11
-        <div class="card-header">
12
-            Wallets
13
-        </div>
14
-        <clr-alert *ngFor="let entry of alerts" [clrAlertType]="line.severity">
15
-            <clr-alert-item>
16
-                <span class="alert-text">
17
-                    {{line.message}}
18
-                </span>
19
-            </clr-alert-item>
20
-        </clr-alert>
21
-
22
-        <clr-tree-node style="margin-top:12px; margin-bottom:12px">
23
-            <a style="cursor:pointer" (click)="parent.showWizard()"><clr-icon shape="download" class="is-solid"></clr-icon> New / Import</a>
24
-        </clr-tree-node>
25
-        <clr-tree-node *ngFor="let line of wallets">
26
-            <a style="cursor:pointer" (click)="parent.loadKey(line.key)">
27
-                <clr-icon *ngIf="line.key.startsWith('xpub') || line.key.startsWith('tpub')" shape="lock" class="is-solid"></clr-icon>
28
-                <clr-icon *ngIf="line.key.startsWith('xprv') || line.key.startsWith('tprv')" shape="key" class="is-solid"></clr-icon>
29
-                {{line.name}}
30
-            </a>
31
-        </clr-tree-node>        
32
-    </div> 
33
-  `
34
-})
35
-export class WalletPickerComponent implements OnInit {
36
-    private parent:PluginsComponent
37
-    wallets = []
38
-
39
-    setWallets(wallets){
40
-        this.wallets = Object.values(wallets)
41
-    }
42
-
43
-    setParent(parent:PluginsComponent){
44
-        this.parent = parent
45
-    }
46
-
47
-    ngOnInit() { }
48
-
49
-}
50
-

+ 0
- 60
src/app/Wallet/module.ts View File

@@ -1,60 +0,0 @@
1
-import { NgModule } from '@angular/core';
2
-import { CommonModule } from '@angular/common';
3
-import { RouterModule } from '@angular/router';
4
-
5
-import { PluginsComponent } from './btc/btc.component';
6
-import { WalletPickerComponent } from './btc/wallet-picker.component';
7
-import { AddressViewerComponent } from './btc/address-viewer.component';
8
-
9
-import { FrontendPlugin, SidebarEntries } from 'frontblock-generic/Plugin';
10
-import { ClarityModule } from '@clr/angular';
11
-import { FormsModule } from '@angular/forms';
12
-import { WalletGeneratorComponent } from './btc/wallet-generator.component';
13
-
14
-
15
-@NgModule({
16
-  imports: [
17
-    FormsModule,
18
-    ClarityModule,
19
-
20
-    CommonModule, 
21
-    RouterModule.forChild([
22
-      {path: "btc", component: PluginsComponent},
23
-    ]),
24
-  ],
25
-  exports: [RouterModule],
26
-  declarations: [
27
-    PluginsComponent,
28
-    WalletPickerComponent,
29
-    AddressViewerComponent,
30
-    WalletGeneratorComponent
31
-  ]
32
-})
33
-export class PluginModule implements FrontendPlugin{
34
-  getSidebarEntry(): SidebarEntries {
35
-    return {
36
-      icon: "wallet",
37
-      text: "Wallets",
38
-      parentRoute: "wallet",
39
-      links: [{
40
-        route: "btc",
41
-        text: "BTC Wallet"    
42
-      },{
43
-        route: "ltc",
44
-        text: "LTC Wallet"    
45
-      },{
46
-        route: "eth",
47
-        text: "ETH Wallet"    
48
-      },{
49
-        route: "xrp",
50
-        text: "XRP Wallet"    
51
-      },{
52
-        route: "xlm",
53
-        text: "XLM Wallet"    
54
-      },{
55
-        route: "settings",
56
-        text: "Settings"    
57
-      }]
58
-    }
59
-  }
60
-}

Loading…
Cancel
Save