Skip to content

Commit

Permalink
Merge 166627b into b462720
Browse files Browse the repository at this point in the history
  • Loading branch information
pciavald committed Jan 18, 2018
2 parents b462720 + 166627b commit f04064c
Show file tree
Hide file tree
Showing 15 changed files with 572 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/app/core/rpc/rpc-state/rpc-state.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class RpcStateClass {
// set state for coldstaking
response => this._rpc.state.set('ui:coldstaking',
response.changeaddress === 'default'
? false
? undefined
: !!response.changeaddress.coldstakingaddress
),
error => this.log.er('walletsettings changeaddress', error)
Expand Down
39 changes: 37 additions & 2 deletions src/app/wallet/overview/widgets/coldstake/coldstake.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,25 @@
</mat-progress-bar>
<p class="widget-help" *ngIf="coldStakingEnabled || stakingTowardsCold">
{{coldstakeProgress}}% of your balance is now safely staking on your staking node.
Please keep this wallet online until the cold staking activation process is complete.
The activation process will continue only when your wallet is online and unlocked for staking.
You can close your wallet if you need to, but it is adviced to keep it online until it reaches 100%.
</p>
<!-- TODO: component ? -->
<p class="buttons">
<button mat-button class="small" color="primary"
matTooltip="Fast-forward to 100%"
(click)="zap()"
*ngIf="hotstaking.txs.length > 0">
Zap
<!-- <span class="tag zap">{{ hotstaking.txs.length }}</span> -->
</button>
<button mat-button class="small" color="warn"
matTooltip="Disable Cold Staking"
(click)="revert()"
*ngIf="coldstaking.txs.length > 0">
Disable
<!-- <span class="tag cancel">{{ coldstaking.txs.length }}</span> -->
</button>
</p>
</mat-card>

Expand All @@ -74,6 +92,23 @@
Whilst paused, {{coldstakeProgress}}% of your balance that has already converted
will continue to stake on your staking node.
</p>
<!-- TODO: component ? -->
<p class="buttons">
<button mat-button class="small" color="primary"
matTooltip="Fast-forward to 100%"
(click)="zap()"
*ngIf="hotstaking.txs.length > 0">
Zap
<!-- <span class="tag zap">{{ hotstaking.txs.length }}</span> -->
</button>
<button mat-button class="small" color="warn"
matTooltip="Disable Cold Staking"
(click)="revert()"
*ngIf="coldstaking.txs.length > 0">
Disable
<!-- <span class="tag cancel">{{ coldstaking.txs.length }}</span> -->
</button>
</p>
</mat-card>


Expand All @@ -91,4 +126,4 @@
</p-->


</div><!-- .cold-staking -->
</div><!-- .cold-staking -->
28 changes: 28 additions & 0 deletions src/app/wallet/overview/widgets/coldstake/coldstake.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
&.warning .subtitle {
color: $color-alert;
}

.title {
display: inline-block;
text-transform: uppercase;
Expand All @@ -36,6 +37,32 @@
.progress-bar {
margin: 5px 0 15px;
}
.buttons { // Zap/revert buttons
margin: -12px 0;
button {
margin: 0;
.tag {
background: $text-muted;
color: white;
display: inline-block;
padding: 1px 6px;
border-radius: 4px;
line-height: 1.3;
font-size: 85%;
font-weight: 800;
margin-left: 3px;
position: relative;
top: -1px;
&.zap {
background: $color;
}
&.cancel {
background: $color-alert;
}
}
}
}

button {
font-size: 12px;
text-transform: uppercase;
Expand All @@ -53,5 +80,6 @@
width: 24px;
}
}

}
}
130 changes: 116 additions & 14 deletions src/app/wallet/overview/widgets/coldstake/coldstake.component.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { MatDialog } from '@angular/material';
import { Log } from 'ng2-logger';

import { RpcService } from '../../../../core/rpc/rpc.module';
import { ModalsService } from '../../../../modals/modals.service';
import { ModalsService } from 'app/modals/modals.service';
import { RpcService } from 'app/core/rpc/rpc.module';

import { Amount } from '../../../shared/util/utils';
import { ZapColdstakingComponent } from './zap-coldstaking/zap-coldstaking.component';
import {RevertColdstakingComponent} from './revert-coldstaking/revert-coldstaking.component';

@Component({
selector: 'app-coldstake',
templateUrl: './coldstake.component.html',
styleUrls: ['./coldstake.component.scss']
})
export class ColdstakeComponent implements OnInit {
export class ColdstakeComponent {

/* General */
private log: any = Log.create('coldstake.component');

coldStakingEnabled: boolean = undefined;
stakingTowardsCold: boolean = undefined;
activation: string = 'Activation in progress';
public encryptionStatus: string = 'Locked';
private progress: Amount = new Amount(0, 2);
get coldstakeProgress(): number { return this.progress.getAmount() }

hotstaking: any = {
txs: [],
amount: 0
};

coldstaking: any = {
txs: [],
amount: 0
};

constructor(
private dialog: MatDialog,
private _modals: ModalsService,
private _rpc: RpcService
) {
Expand All @@ -36,32 +50,120 @@ export class ColdstakeComponent implements OnInit {
this._rpc.state.observe('ui:coldstaking:stake')
.subscribe(status => this.stakingTowardsCold = status);

// TODO: move to coldstaking service
this.rpc_progressLoop();
}

ngOnInit() {
}

/** calls getcoldstakinginfo, then calculate progress. */
private rpc_progressLoop(): void {

this._rpc.call('getcoldstakinginfo').subscribe((coldstakinginfo: any) => {
this.log.d(coldstakinginfo['percent_in_coldstakeable_script']);
this.progress = new Amount(coldstakinginfo['percent_in_coldstakeable_script'], 2);
}, error => this.log.er('couldn\'t get cold staking info', error));
// TODO: not necessary when cold staking disabled

this._rpc.call('getcoldstakinginfo').subscribe(coldstakinginfo => {
this.progress = new Amount(coldstakinginfo['percent_in_coldstakeable_script'], 2);
}, error => this.log.er('couldn\'t get cold staking info', error));
this.stakingStatus();

setTimeout(this.rpc_progressLoop.bind(this), 1000);
if (this.coldstakeProgress === 100) {
this.activation = 'Activated';
}
}

private stakingStatus() {

this._rpc.call('listunspent').subscribe(unspent => {

this.log.d('listunspent', unspent);

this.hotstaking = {
txs: [],
amount: 0
};

this.coldstaking = {
txs: []
};

unspent.map(utxo => {

if (utxo.coldstaking_address) { /* found a cold staking utxo */

let txAlreadyRecorded = false;

this.coldstaking.txs.map(tx => {
if (tx.address === utxo.address) {
txAlreadyRecorded = true;
tx.amount += utxo.amount;
tx.inputs.push({ tx: utxo.txid, n: utxo.vout });
}
});

if (!txAlreadyRecorded) {
this.coldstaking.txs.push({
address: utxo.address,
amount: utxo.amount,
inputs: [{ tx: utxo.txid, n: utxo.vout }]
});
}

} else { /* found a hot staking utxo */
this.hotstaking.amount += utxo.amount;
this.hotstaking.txs.push({ tx: utxo.txid, n: utxo.vout });
}

});

this.hotstaking.amount = this.hotstaking.amount.toFixed(8);
this.coldstaking.txs = this.coldstaking.txs.map(tx => {
tx.amount = tx.amount.toFixed(8);
return tx;
});

this.log.d('hotstaking', this.hotstaking);
this.log.d('coldstaking', this.coldstaking);

}, error => this.log.er('couldn\'t list unspent outputs', error));

}

zap() {
if (this._rpc.state.get('locked')) {
this._modals.open('unlock', {
forceOpen: true,
callback: this.openZapColdstakingModal.bind(this)
});
} else {
this.openZapColdstakingModal();
}
}

openRevertColdstakingModal() {
const dialogRef = this.dialog.open(RevertColdstakingComponent);
dialogRef.componentInstance.utxos = this.coldstaking;
}

revert() {
if (this._rpc.state.get('locked')) {
this._modals.open('unlock', {
forceOpen: true,
callback: this.openRevertColdstakingModal.bind(this)
});
} else {
this.openRevertColdstakingModal();
}
}

openZapColdstakingModal(): void {
const dialogRef = this.dialog.open(ZapColdstakingComponent);
dialogRef.componentInstance.utxos = this.hotstaking;
}

openUnlockWalletModal(): void {
this._modals.open('unlock', {forceOpen: true, showStakeOnly: false, stakeOnly: true});
}

openColdStakeModal(): void {
this._modals.open('coldStake', {forceOpen: true, type: 'cold'});
this._modals.open('coldStake', { forceOpen: true, type: 'cold' });
}

checkStatus(): boolean {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<h2 mat-dialog-title>Disable Cold Staking</h2>

<mat-dialog-content>
<p>
Disable Cold Staking and move your funds back to your wallet from your staking device.
Note that you don't need to disable Cold Staking to spend your coins.
</p>
<!--p>
Alternatively, you can just disable Cold Staking activation. That will stop sending staked coins to your staking device. Coins already there will stay there.
</p-->
<p class="warning">
<mat-icon fontSet="partIcon" fontIcon="part-alert"></mat-icon>
Disabling Cold Staking will create {{ utxos.txs.length }} transaction(s) and will consume <strong>{{ fee }} PART</strong> in fees.
</p>
</mat-dialog-content>

<mat-dialog-actions fxLayoutAlign="end center">
<button mat-button mat-dialog-close>
<mat-icon fontSet="partIcon" fontIcon="part-cross"></mat-icon>
Cancel
</button>
<!--button mat-button color="warn" (click)="disableColdstaking()">
<mat-icon fontSet="partIcon" fontIcon="part-error"></mat-icon>
Disable Cold Staking
</button-->
<button mat-raised-button color="warn" (click)="revert()" [disabled]="!fee">
<mat-icon fontSet="partIcon" fontIcon="part-refresh"></mat-icon>
Disable Cold Staking
</button>
</mat-dialog-actions>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@import "./src/assets/_config"; // import shared colors etc.

@import "./src/app/modals/shared/_modal-layout.scss"; // shared layout for modals (dialog titles etc.)
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialogRef } from '@angular/material';

import { RpcModule } from '../../../../../core/rpc/rpc.module';
import { SharedModule } from '../../../../shared/shared.module';
import { CoreModule } from '../../../../../core/core.module'

import { CoreUiModule } from '../../../../../core-ui/core-ui.module';
import { ModalsService } from '../../../../../modals/modals.service';

import { RevertColdstakingComponent } from './revert-coldstaking.component';

describe('RevertColdstakingComponent', () => {
let component: RevertColdstakingComponent;
let fixture: ComponentFixture<RevertColdstakingComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RpcModule.forRoot(),
SharedModule,
CoreModule.forRoot(),
CoreUiModule.forRoot()
],
declarations: [ RevertColdstakingComponent ],
providers: [{ provide: MatDialogRef}, ModalsService],
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(RevertColdstakingComponent);
component = fixture.componentInstance;
component.utxos = {
txs: [],
amount: 0
};
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Loading

0 comments on commit f04064c

Please sign in to comment.