From 92666ba0c08bcd6061ad8a3b839cc7c5fae8465c Mon Sep 17 00:00:00 2001 From: peter Date: Fri, 16 Aug 2019 20:46:06 +0200 Subject: [PATCH] better wallet --- src/frontend/dashboard/package-lock.json | 13 + src/frontend/dashboard/package.json | 1 + .../app/PluginManager/plugins.component.ts | 2 +- .../Wallet/btc/address-viewer.component.ts | 223 +++++---- .../src/app/Wallet/btc/btc.component.ts | 436 ++++++++++-------- .../Wallet/btc/wallet-generator.component.ts | 1 + .../app/Wallet/btc/wallet-picker.component.ts | 2 +- .../dashboard/src/app/app.component.html | 2 +- .../dashboard/src/app/app.component.scss | 10 - .../src/app/content-area/main.component.html | 4 +- src/frontend/dashboard/src/styles.scss | 51 ++ 11 files changed, 459 insertions(+), 286 deletions(-) diff --git a/src/frontend/dashboard/package-lock.json b/src/frontend/dashboard/package-lock.json index 5c4df88..cb10b6e 100644 --- a/src/frontend/dashboard/package-lock.json +++ b/src/frontend/dashboard/package-lock.json @@ -3724,6 +3724,11 @@ "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": { "version": "7.0.3", "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", "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": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", diff --git a/src/frontend/dashboard/package.json b/src/frontend/dashboard/package.json index 6a197f8..7479bcc 100644 --- a/src/frontend/dashboard/package.json +++ b/src/frontend/dashboard/package.json @@ -31,6 +31,7 @@ "key-file-storage": "^2.2.4", "node-fetch": "^2.6.0", "rxjs": "~6.5.2", + "stream": "0.0.2", "systemjs": "^0.21.3", "tslib": "^1.9.0", "uuid": "^3.3.2", diff --git a/src/frontend/dashboard/src/app/PluginManager/plugins.component.ts b/src/frontend/dashboard/src/app/PluginManager/plugins.component.ts index 85b5822..6347fc8 100644 --- a/src/frontend/dashboard/src/app/PluginManager/plugins.component.ts +++ b/src/frontend/dashboard/src/app/PluginManager/plugins.component.ts @@ -41,7 +41,7 @@ declare const fb {{line.name}} - {{line.available}} + {{line.available}} {{line.available}} {{line.installed}} diff --git a/src/frontend/dashboard/src/app/Wallet/btc/address-viewer.component.ts b/src/frontend/dashboard/src/app/Wallet/btc/address-viewer.component.ts index de724f0..cd96b87 100644 --- a/src/frontend/dashboard/src/app/Wallet/btc/address-viewer.component.ts +++ b/src/frontend/dashboard/src/app/Wallet/btc/address-viewer.component.ts @@ -2,98 +2,148 @@ import { Component, OnInit, isDevMode } from '@angular/core'; import { PluginsComponent } from './btc.component'; +import { ClrDatagridStringFilterInterface, ClrDatagridNumericFilterInterface, ClrDropdownModule } from '@clr/angular'; declare const fb @Component({ selector: 'address-viewer', //!!!! template: ` -
-
- Addresses +
+
+
+
+ Addresses +
+ + + + {{line.message}} + + + + + + Address + + Balance + + + Pending + + + Estimate total + + + + + {{line.address}} + {{line.confirmed.balance | number: '1.8-18'}} + + + {{line.unconfirmed.balance | number: '1.8-18'}} + + + {{line.total.balance | number: '1.8-18'}} + + +
+
+ +
+ +
+
Derivation
+ {{parent.keys[line.address].derivation}} +
Public key
+ {{parent.keys[line.address].publicExtendedKey}} +
Private key
+ {{parent.keys[line.address].privateExtendedKey}} +
+
+
+
+ + + + per page + {{pagination2.firstItem + 1}} - {{pagination2.lastItem + 1}} + of {{pagination2.totalItems}} + + +
+
- - - - {{line.message}} - - - - - Address - Balance - Pending - Estimate total +
+
+
+ Change Addresses +
+ + + + {{line.message}} + + + - - {{line.address}} - {{line.confirmed.balance}} - {{line.unconfirmed.balance}} - {{line.total.balance}} - -
-
- + + Address + + Balance + + + Pending + + + Estimate total + + + + + {{line.address}} + {{line.confirmed.balance | number: '1.8-18'}} + + + {{line.unconfirmed.balance | number: '1.8-18'}} + + + {{line.total.balance | number: '1.8-18'}} + + +
+
+ +

+

+ +
+
Derivation
+ {{parent.keys[line.address].derivation}} +
Public key
+ {{parent.keys[line.address].publicExtendedKey}} +
Private key
+ {{parent.keys[line.address].privateExtendedKey}} +
+
+
-
-
Public key
- {{parent.keys[line.address].publicExtendedKey}} -
Private key
- {{parent.keys[line.address].privateExtendedKey}} -
-
- - - - - - per page - {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} - of {{pagination.totalItems}} - - - - - - Address - Balance - Pending - Estimate total - - - {{line.address}} - {{line.confirmed.balance}} - {{line.unconfirmed.balance}} - {{line.total.balance}} - -
-
- -
- -
-
Public key
- {{parent.keys[line.address].publicExtendedKey}} -
Private key
- {{parent.keys[line.address].privateExtendedKey}} -
-
-
-
- - - - per page - {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} - of {{pagination.totalItems}} - - -
-
+ + + per page + {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} + of {{pagination.totalItems}} + + + +
+
+
` }) -export class AddressViewerComponent implements OnInit { - +export class AddressViewerComponent implements OnInit{ + balanceFilter = new BalanceFilter() + otherBalanceFilter = new BalanceFilter() regularAddresses = [] changeAddresses = [] keys = {} @@ -110,6 +160,15 @@ export class AddressViewerComponent implements OnInit { setChangeAddresses(addresses){ this.changeAddresses = addresses - } + } } +class BalanceFilter implements ClrDatagridNumericFilterInterface{ + 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) + } +} \ No newline at end of file diff --git a/src/frontend/dashboard/src/app/Wallet/btc/btc.component.ts b/src/frontend/dashboard/src/app/Wallet/btc/btc.component.ts index 9be6a21..dd89fcb 100644 --- a/src/frontend/dashboard/src/app/Wallet/btc/btc.component.ts +++ b/src/frontend/dashboard/src/app/Wallet/btc/btc.component.ts @@ -5,7 +5,7 @@ import { HDKey } from "btc-hdkey" import { AddressViewerComponent } from './address-viewer.component'; const fetch = require("node-fetch") const coinselect = require('coinselect/accumulative') -import { TransactionBuilder } from 'bitcoinjs-lib' +import { TransactionBuilder, Signer } from 'bitcoinjs-lib' import { networks } from 'bitcoinjs-lib' let feeRate = 55 // satoshis per byte @@ -17,8 +17,43 @@ declare const fb + + + + + + + + +
+
+ +
+ Faucet +
+
+ + + + +
+ + + +
+
+ -
+
@@ -28,26 +63,42 @@ declare const fb
- +
-
+
-
+
+
Send
- + + + + {{error}} + + + + + + + {{success}} + + +
- - - + +
+ + +
@@ -63,9 +114,9 @@ declare const fb
-
+
- {{rootkey.publicExtendedKey}} + Testnet{{rootkey.publicExtendedKey}}
@@ -75,12 +126,19 @@ declare const fb -
-

Balance: {{balance.confirmed}}

-

- Unconfirmed: {{balance.unconfirmed}}
- Estimated total: {{balance.total}} +

+

{{balanceDisplay.total | number: '1.8-18'}} BTC

+

+  {{balanceDisplay.confirmed | number: '1.18'}} BTC confirmed
+ {{balanceDisplay.unconfirmed | number: '1.18'}} BTC pending

+

+ Private key available +

+
+ +
@@ -91,50 +149,39 @@ declare const fb
-
+
- - - - - ` }) export class PluginsComponent implements AfterViewInit { - - wallets:{ - [someLabel in string]:{ - key:string - name:string - } - } = {} + errors:string[] = [] + successes:string[] = [] + wallets:WalletStore = {} txToSend:any - rootkey = { - publicExtendedKey: "", - privateExtendedKey: "" - } - keys = {} - regaddresses = [] - changeaddresses = [] - balance = { + rootkey:bip32Keypair = {publicExtendedKey: "",privateExtendedKey: ""} + keys:KeyStore = {} + regaddresses:AddressLine[] = [] + changeaddresses:AddressLine[] = [] + balanceDisplay = { confirmed: 0, total: 0, unconfirmed: 0 } mode : { - net:network + type:keyType, + net:networkType } = { - net: "testnet" + net: "testnet", + type: "public" } - sendto:string - amount:number + sendTo:string + sendAmount:number + loading = false + loadingN = 1 - constructor(){ - window["btc"] = () => this - } @ViewChild(AddressViewerComponent, {static: false}) AddressViewerComponent:AddressViewerComponent @@ -149,8 +196,8 @@ export class PluginsComponent implements AfterViewInit { this.WalletPickerComponent.setParent(this) this.AddressViewerComponent.setParent(this) - //tprv8cXm1S7PGS2fHuLjZajuDZZsvxerzv4zZJJAhkLAWZzwz5rE7efHm31xsqpzfoGMHBNC8bkRcsjiMdmkSuNn5C1qNqk7rrk1pCuhk4HfVak - //tpubD9Do9r9dQoiLBNNXTEQVcyDzVzAoAFFu8btwzGNTvqoLpa6zk3UswXdq3zeArrakUu8huCtG1L5pTqNYNftanuutf57fn1C74rBzFybH1xe + window['btc'] = this + this.loadKey("tprv8cXm1S7PGS2fHuLjZajuDZZsvxerzv4zZJJAhkLAWZzwz5rE7efHm31xsqpzfoGMHBNC8bkRcsjiMdmkSuNn5C1qNqk7rrk1pCuhk4HfVak") } @@ -169,50 +216,46 @@ export class PluginsComponent implements AfterViewInit { loadKey(key:string){ this.wallets = {} this.txToSend = null - this.sendto = "" + this.sendTo = "" this.regaddresses = [] const t = hdkey.checkHDKey(key) if(t){ + console.log(t) this.mode = t } this.rootkey = hdkey.HDKeyFromExtendedKey(key) - this.refresh() + this.reload() } - async refresh(){ + async reload():Promise{ + this.loading = true + this.loadingN = 1 this.keys = {} - this.changeaddresses = [] - this.regaddresses = [] - this.AddressViewerComponent.setChangeAddresses([]) - this.AddressViewerComponent.setRegularAddresses([]) - this.balance.total = 0 - this.balance.unconfirmed = 0 - this.balance.confirmed = 0 + this.balanceDisplay.total = 0 + this.balanceDisplay.unconfirmed = 0 + this.balanceDisplay.confirmed = 0 + await this.refresh() + this.loading = false + } + async refresh():Promise{ 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 => { - this.balance.confirmed += balance.confirmed - this.balance.total += balance.total - this.balance.unconfirmed += balance.unconfirmed + this.balanceDisplay.confirmed += balance.confirmed + this.balanceDisplay.total += balance.total + this.balanceDisplay.unconfirmed += balance.unconfirmed }) - console.log(this.changeaddresses) - this.AddressViewerComponent.setChangeAddresses(this.changeaddresses) this.AddressViewerComponent.setRegularAddresses(this.regaddresses) } - - async getInfo(rootAddr: string, n = 10, skip = 0, changeAddresses = false): Promise{ - const t = hdkey.checkHDKey(rootAddr) - if(!t){ - return false - } + getAddresses(rootAddr: string, n = 10, skip = 0, changeAddresses = false): string[] | null{ let addresses: string[] = [] for(let i = skip; i < skip+n; i++){ let addr @@ -222,13 +265,17 @@ export class PluginsComponent implements AfterViewInit { addr = hdkey.deriveAddress(rootAddr, i) } if(!addr){ - return false + return } addresses.push(addr) } + return addresses + } + + async fetchAddresses(addresses:string[], network:networkType): Promise<{success:boolean, address?:any, addresses?:any}>{ let lookupstr = addresses.join(',') try{ - let r = await fetch(api[t.net]+'/address/'+lookupstr, { + let r = await fetch(api[network]+'/address/'+lookupstr, { 'method':'GET', 'mode':'cors', 'data': {limit: 200} @@ -244,20 +291,35 @@ export class PluginsComponent implements AfterViewInit { } } - async getTxs(address: string, type:network){ - let r = await fetch(api[type]+'/address/'+address, { - 'method':'GET', - 'mode':'cors' - }) - if(r.status !== 200){ - return {success: false} + async getAddressInfos(rootAddr: string, n = 10, skip = 0, changeAddresses = false): Promise{ + const t = hdkey.checkHDKey(rootAddr) + if(!t){ + return false } - - return (await r).json() + const addresses = this.getAddresses(rootAddr, n, skip, changeAddresses) + return await this.fetchAddresses(addresses, t.net) + } - async getUnspentTxs(addresses:string[], type:network):Promise{ + async getTxs(address: string, type:networkType){ + try{ + let r = await fetch(api[type]+'/address/'+address, { + 'method':'GET', + 'mode':'cors' + }) + if(r.status !== 200){ + return {success: false} + } + + return (await r).json() + }catch(e){ + console.warn ("getTxs", e) + } + } + + async getUnspentTxs(addresses:string[], type:networkType):Promise{ let lookupstr = addresses.join(',') + try{ let r = await fetch(api[type]+'/address/'+lookupstr+'/unspent', { 'method':'GET', @@ -269,6 +331,7 @@ export class PluginsComponent implements AfterViewInit { return (await r).json() }catch(e){ + console.warn ("getUnspentTxs", e) return {success: false} } } @@ -278,30 +341,51 @@ export class PluginsComponent implements AfterViewInit { return this.keys[keyName] } - async update(){ - let n = 1 - let regAddresses + calculateTotal(addresses:AddressLine[]):GrandTotal{ + const resMap: any = addresses.reduce((o1, o2)=>{o1[o2.address] = o2; return o1}, {}) + const total: any = Object.values(resMap).reduce((accum:GrandTotal, obj:AddressLine) => { + accum.confirmed += parseFloat(obj.confirmed.balance) + accum.unconfirmed += parseFloat(obj.unconfirmed.balance) + accum.total += parseFloat(obj.confirmed.balance) + parseFloat(obj.unconfirmed.balance) + return accum + },{ + confirmed: 0, + unconfirmed: 0, + total: 0 + }) + + return total + } + async updateBalance():Promise{ + let n = 1 + let res: { success: boolean; addresses: any; address: any; } + this.regaddresses = [] while(true){ + this.loadingN = n 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){ break } - if(regAddresses.success === true){ - if('addresses' in regAddresses){ // multiple - this.regaddresses = [...this.regaddresses, ...regAddresses.addresses] + if(res.success === true){ + if('addresses' in res){ // multiple + this.regaddresses = [...this.regaddresses, ...res.addresses] } - if('address' in regAddresses){ - this.regaddresses.push(regAddresses.address) + if('address' in res){ + this.regaddresses.push(res.address) } n++ }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') - if(this.rootkey.privateExtendedKey != null){ - for(let i = 0; i < 115*n; i++){ + if(this.mode.type == "private"){ + for(let i = 0; i < 115*n+1; i++){ const keyN = hdkey.deriveKey(this.rootkey.privateExtendedKey, i) const addrN = hdkey.addressFromHDKey(keyN._publicKey, this.mode.net) + keyN.derivation = i this.keys[addrN] = keyN } } @@ -309,46 +393,25 @@ export class PluginsComponent implements AfterViewInit { } } - if(this.regaddresses.length === 0){ - const addr = hdkey.deriveAddress(this.rootkey.publicExtendedKey, 0) - this.regaddresses.push({ - address: addr, - confirmed: {balance: 0}, - unconfirmed: {balance: 0}, - total: {balance: 0}, - }) - return { - total: 0, - unconfirmed: 0, - confirmed: 0 - } - } - const resMap: any = {} - this.regaddresses.forEach(a => { - resMap[a.address] = a + //add an extra empty address at the end + const extraAddr = hdkey.deriveAddress(this.rootkey.publicExtendedKey, this.regaddresses.length) + this.regaddresses.push({ + address: extraAddr, + confirmed: {balance: 0}, + unconfirmed: {balance: 0}, + total: {balance: 0}, }) - - const confirmed = Object.values(resMap).reduce((accum:any, obj:any) => { - return accum + parseFloat(obj.confirmed.balance) - }, 0) - const unconfirmed = Object.values(resMap).reduce((accum:any, obj:any) => { - return accum + parseFloat(obj.unconfirmed.balance) - }, 0) - - return { - total: confirmed+unconfirmed, - unconfirmed: unconfirmed, - confirmed: confirmed - } + + return this.calculateTotal(this.regaddresses) } - async updateChange(){ + async updateChange():Promise{ let n = 1 - let res - + this.changeaddresses = [] while(true){ + let res 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){ break } @@ -361,11 +424,16 @@ export class PluginsComponent implements AfterViewInit { } n++ }else{ - console.log('No more balance found after attempting ', 115*n, 'addresses') - if(this.rootkey.privateExtendedKey != null){ + 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 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++){ const keyN = hdkey.deriveKey(this.rootkey.privateExtendedKey, i, 'm/1/') const addrN = hdkey.addressFromHDKey(keyN._publicKey, this.mode.net) + keyN.derivation = i this.keys[addrN] = keyN } } @@ -373,60 +441,26 @@ export class PluginsComponent implements AfterViewInit { } } - if(this.changeaddresses.length === 0){ - 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 = {} - this.changeaddresses.forEach(a => { - resMap[a.address] = a - }) - - const confirmed = Object.values(resMap).reduce((accum:any, obj:any) => { - return accum + parseFloat(obj.confirmed.balance) - }, 0) - const unconfirmed = Object.values(resMap).reduce((accum:any, obj:any) => { - return accum + parseFloat(obj.unconfirmed.balance) - }, 0) - - return { - confirmed: confirmed, - unconfirmed: unconfirmed, - total: unconfirmed + confirmed - } + return this.calculateTotal(this.changeaddresses) } - async createTx(target:string, value:number){ - - console.log(target, value) + async createAndSendTx(target:string, value:number){ 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 } - if(value > this.balance.confirmed){ - //this.error = 'Insufficient funds' + if(value > this.balanceDisplay.confirmed){ + this.errors.push('Insufficient funds') return } - let addresses: string[] = this.regaddresses.map(a => a.address) - addresses = [...addresses, ...this.changeaddresses.map(a => a.address)] + let addresses: string[] = [...this.regaddresses.map(a => a.address), ...this.changeaddresses.map(a => a.address)] const txs = await this.getUnspentTxs(addresses, this.mode.net) if(txs == null || txs.success !== true || txs.unspent.length === 0){ - //this.error = 'No UTXOs found' + this.errors.push('No UTXOs found') return } @@ -443,7 +477,7 @@ export class PluginsComponent implements AfterViewInit { // .inputs and .outputs will be undefined if no solution was found if (!inputs || !outputs){ - //this.error = 'Could not build a valid transaction' + this.errors.push('Could not build a valid transaction') return } @@ -461,7 +495,7 @@ export class PluginsComponent implements AfterViewInit { txb.addOutput(output.address, output.value) }) inputs.forEach((input, i) => { - txb.sign(i, this.keys[input.address]) + txb.sign(i, this.keys[input.address]) }) this.txToSend = txb.build() @@ -469,37 +503,61 @@ export class PluginsComponent implements AfterViewInit { this.sendTx() } - async sendTx(){ + private async sendTx(){ if(this.txToSend == null){ - //this.error = 'No transaction to send!' + this.errors.push('No transaction to send!') return } - let url - if(this.mode.net === 'mainnet'){ - url = 'https://api.smartbit.com.au/v1/blockchain/pushtx' - }else{ - url = 'https://testnet-api.smartbit.com.au/v1/blockchain/pushtx' + let url = api[this.mode.net]+"/pushtx" + let r + try{ + r = await fetch(url, { + 'method':'POST', + 'body': JSON.stringify({'hex': this.txToSend.toHex()}) + }) + }catch(e){ + console.warn("sendTx", e) + return } - let r = await fetch(url, { - 'method':'POST', - 'body': JSON.stringify({'hex': this.txToSend.toHex()}) - }) this.txToSend = null if(r.status === 200){ - console.log(r) - this.refresh() + this.errors = [] + this.successes.push("Sent "+this.sendAmount+" to "+this.sendTo) + this.reload() }else{ - //this.error = 'The API '+url+' returned a non-200 error code '+r.status+' '+r.statusText - console.log(r) + this.errors.push('The API '+url+' returned a non-200 error code '+r.status+' '+r.statusText) } } + + 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') + } } +export type KeyStore = {[keyname in string]: bip32Keypair & Signer} -type network = 'testnet' | 'mainnet' +export type AddressLine = { + address: string, + confirmed: {balance: number}, + unconfirmed: {balance: number}, + total: {balance: number}, +} + +type networkType = 'testnet' | 'mainnet' 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 } const api = { diff --git a/src/frontend/dashboard/src/app/Wallet/btc/wallet-generator.component.ts b/src/frontend/dashboard/src/app/Wallet/btc/wallet-generator.component.ts index 8efc1fe..dec2d36 100644 --- a/src/frontend/dashboard/src/app/Wallet/btc/wallet-generator.component.ts +++ b/src/frontend/dashboard/src/app/Wallet/btc/wallet-generator.component.ts @@ -142,6 +142,7 @@ declare const fb Cancel + Back Finish diff --git a/src/frontend/dashboard/src/app/Wallet/btc/wallet-picker.component.ts b/src/frontend/dashboard/src/app/Wallet/btc/wallet-picker.component.ts index a4a1a2d..802b3ab 100644 --- a/src/frontend/dashboard/src/app/Wallet/btc/wallet-picker.component.ts +++ b/src/frontend/dashboard/src/app/Wallet/btc/wallet-picker.component.ts @@ -7,7 +7,7 @@ declare const fb selector: 'walletpicker', //!!!! template: ` -
+
Wallets
diff --git a/src/frontend/dashboard/src/app/app.component.html b/src/frontend/dashboard/src/app/app.component.html index a9c930a..b0b5cb2 100644 --- a/src/frontend/dashboard/src/app/app.component.html +++ b/src/frontend/dashboard/src/app/app.component.html @@ -1,4 +1,4 @@ - + diff --git a/src/frontend/dashboard/src/app/app.component.scss b/src/frontend/dashboard/src/app/app.component.scss index b09567c..e69de29 100644 --- a/src/frontend/dashboard/src/app/app.component.scss +++ b/src/frontend/dashboard/src/app/app.component.scss @@ -1,10 +0,0 @@ -.heightmax{ - height: 100% -} -.break-word { - word-wrap: break-word; - } -.monospace { - font-family: monospace; - font-size: 90% -} \ No newline at end of file diff --git a/src/frontend/dashboard/src/app/content-area/main.component.html b/src/frontend/dashboard/src/app/content-area/main.component.html index 3548d48..abf62eb 100644 --- a/src/frontend/dashboard/src/app/content-area/main.component.html +++ b/src/frontend/dashboard/src/app/content-area/main.component.html @@ -1,3 +1,3 @@ -
- +
+
diff --git a/src/frontend/dashboard/src/styles.scss b/src/frontend/dashboard/src/styles.scss index 90d4ee0..567921e 100644 --- a/src/frontend/dashboard/src/styles.scss +++ b/src/frontend/dashboard/src/styles.scss @@ -1 +1,52 @@ /* 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 +} \ No newline at end of file