Skip to content

Commit

Permalink
WEB v2: Fee recipient UI (#229)
Browse files Browse the repository at this point in the history
* enabling list fee recipient method

* adding new component for updating fee recipient

* adding refresh on fee recipient update

* removing temp balance

* fixing unit test and adjusting table based on real testing

* fixing linting issue
  • Loading branch information
james-prysm authored Jun 30, 2022
1 parent b39aa7f commit a6427e4
Show file tree
Hide file tree
Showing 22 changed files with 425 additions and 84 deletions.
11 changes: 11 additions & 0 deletions src/app/modules/core/interceptors/mock.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { EnvironmenterService } from '../services/environmenter.service';

export const VALIDATOR_API_PREFIX = '/v2/validator';
export const KEYMANAGER_API_PREFIX = '/eth/v1/keystores';
export const KEYMANAGER_API_VALIDATOR_PREFIX = '/eth/v1/validator';

@Injectable()
export class MockInterceptor implements HttpInterceptor {
Expand All @@ -29,6 +30,16 @@ export class MockInterceptor implements HttpInterceptor {
body: mock[request.method as keyof RestObject],
}));
}
if (this.contains(request.url, KEYMANAGER_API_VALIDATOR_PREFIX )) {
if(this.contains(request.url,'feerecipient')){
let mock = KeymanagerAPIMocks['/eth/v1/validator/{pubkey}/feerecipient'];
return of(new HttpResponse({
status: 200,
body: mock[request.method as keyof RestObject],
}));
}

}
if (this.contains(request.url, VALIDATOR_API_PREFIX)) {
endpoint = this.extractEndpoint(request.url, VALIDATOR_API_PREFIX);
}
Expand Down
14 changes: 12 additions & 2 deletions src/app/modules/core/mocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ValidatorParticipation } from 'src/app/proto/eth/v1alpha1/validator';
import {
Account, BackupAccountsResponse, BeaconStatusResponse, GenerateMnemonicResponse, ImportKeystoresResponse, InitializeAuthResponse, ListAccountsResponse, WalletResponse
} from 'src/app/proto/validator/accounts/v2/web_api';
import { DeleteAccountsResponse } from 'src/app/proto/validator/accounts/v2/web_api_keymanager-api';
import { DeleteAccountsResponse, ListFeeRecipientResponse } from 'src/app/proto/validator/accounts/v2/web_api_keymanager-api';
import { GWEI_PER_ETHER } from '../constants';


Expand Down Expand Up @@ -583,7 +583,17 @@ export const KeymanagerAPIMocks = {
}],
slashing_protection: "{\"metadata\":{\"interchange_format_version\":\"5\",\"genesis_validators_root\":\"0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb\"},\"data\":[{\"pubkey\":\"0x8d65ffe7b65ee8e7c3e14a474a360f16722920ef8c0ef1da6f942fd6ddc3628c1edda7f57cf28d7ddc7fc9cb9745df60\",\"signed_blocks\":[],\"signed_attestations\":[{\"source_epoch\":\"71793\",\"target_epoch\":\"71794\",\"signing_root\":\"0xc996259c3456818eb1cc5102a88316ff505d940a9840a5205f54ba3334a60aa8\"},{\"source_epoch\":\"71794\",\"target_epoch\":\"71795\",\"signing_root\":\"0x0ea5c7312ebd4a0a009fd92780972a0ad7391eb12143218359b1019140da4e53\"},{\"source_epoch\":\"71795\",\"target_epoch\":\"71796\",\"signing_root\":\"0xe09c4e38834637c4588fde948827709959e9d177d93207f2d00951bb4ddc18ff\"},{\"source_epoch\":\"71796\",\"target_epoch\":\"71797\",\"signing_root\":\"0xf13f47d87685ffc6258cbd831dd1e375cf54cfa1702ef3ec92a8d230ca353c44\"},{\"source_epoch\":\"71797\",\"target_epoch\":\"71798\",\"signing_root\":\"0x57ab41e44ca77e9bb26a9a1a2950eda83ba1f900091a200bcab6bab4bc921c0c\"},{\"source_epoch\":\"71798\",\"target_epoch\":\"71799\",\"signing_root\":\"0x444eed11867e86d3ce6b97e08d7d8bb87f403583a9940f364eaba04c862e78f5\"},{\"source_epoch\":\"71799\",\"target_epoch\":\"71800\",\"signing_root\":\"0xa0fcc0fbf0b7f24d18fc3f4efbd474fc762fc4ed2ca3a0798d4b07aeee1b144b\"},{\"source_epoch\":\"71800\",\"target_epoch\":\"71801\",\"signing_root\":\"0xcdd9a1454f93632fb3f4da8f0654306c045af6b8490a8558780cc27b43d763a2\"},{\"source_epoch\":\"71801\",\"target_epoch\":\"71802\",\"signing_root\":\"0x4e473e9bcafd60f6c5c53eceb8cdcdfa0b2a165830fd82243e8b682e373b248e\"},{\"source_epoch\":\"71802\",\"target_epoch\":\"71803\",\"signing_root\":\"0xf98c0a28d46739bbdee389281b087635fbc7c58ddb27e9736d9376500b865674\"},{\"source_epoch\":\"71803\",\"target_epoch\":\"71804\",\"signing_root\":\"0x52ffb97763758fbe1a22783f98983b78f580815fb41fada3bb0cfc886e0838d1\"},{\"source_epoch\":\"71804\",\"target_epoch\":\"71805\",\"signing_root\":\"0x2388327613c16412baf6b3429603dbfc31fa84490877e57706d464b26a720241\"},{\"source_epoch\":\"71805\",\"target_epoch\":\"71806\",\"signing_root\":\"0xfc5b7a3bee9e71c76691ab392ed9e21730eba735f129eaf150c754eb9b0ebd56\"},{\"source_epoch\":\"71806\",\"target_epoch\":\"71807\",\"signing_root\":\"0xa4071f5852bbde14c2128027682dfa8e9c166d3affc42fd45b7b1120d16cb126\"},{\"source_epoch\":\"71807\",\"target_epoch\":\"71808\",\"signing_root\":\"0xb8ee3840e82dd2d8982d551b079dc77d64d74e93045207315ab67531c345db88\"},{\"source_epoch\":\"71808\",\"target_epoch\":\"71809\",\"signing_root\":\"0x700567d637657c615410e60e45ccc1f313173242480454cdc3ac1c239c54876e\"},{\"source_epoch\":\"71809\",\"target_epoch\":\"71810\",\"signing_root\":\"0xa6ad2005a5675a9b33cf08ac1f0fafb3b96afd0acb004e2daccee981e0bc6ca0\"},{\"source_epoch\":\"71810\",\"target_epoch\":\"71811\",\"signing_root\":\"0xf78c31f4158dce92c386261a48d77b47813deaaeefc8679790eb69decc6e2dcb\"},{\"source_epoch\":\"71811\",\"target_epoch\":\"71812\",\"signing_root\":\"0xfd21111aa0c2e2ddd7b599378b23095dd176d9fb6f86805e103ad9ea2b602a8a\"},{\"source_epoch\":\"71812\",\"target_epoch\":\"71813\",\"signing_root\":\"0xa50d236f1063b04b34a2b9d0e8f3fb56e495ebf26e992e8d8b89af66b7d28243\"},{\"source_epoch\":\"71813\",\"target_epoch\":\"71814\",\"signing_root\":\"0x0b9df665c3b717d5ffc7b14a6cad4b883edb9b3068c5ded219522d626f8b38ac\"},{\"source_epoch\":\"71814\",\"target_epoch\":\"71815\",\"signing_root\":\"0xfe9f887500d0797f5340d336495020795e896c95eed15a6d990c63bcffffca48\"},{\"source_epoch\":\"71815\",\"target_epoch\":\"71816\",\"signing_root\":\"0xfe5b638cade977c527bcb0cab500ad2bd1d992432c22641f08b376210f76322d\"},{\"source_epoch\":\"71816\",\"target_epoch\":\"71817\",\"signing_root\":\"0x0efb9c40d8771746a7bfeb8e50da9ee281c91b6e315f538b677251989592ccf4\"},{\"source_epoch\":\"71817\",\"target_epoch\":\"71818\",\"signing_root\":\"0x534238e82f5a637076166143acacccd45b629b5f271020d9917f2a307b5b3daf\"},{\"source_epoch\":\"71818\",\"target_epoch\":\"71819\",\"signing_root\":\"0x7bcb82fb0cb70e14e6d14981d8c372b096af2051048bb765644fee0b34e06af3\"},{\"source_epoch\":\"71819\",\"target_epoch\":\"71820\",\"signing_root\":\"0x79341fd23fac19f66b62729c675f0841269dd51b1796d982f726bb3697b945a3\"},{\"source_epoch\":\"71820\",\"target_epoch\":\"71821\",\"signing_root\":\"0x4cee1928b36d80d846ac4ad03798604415ce9df67f8aae2154a5143c467f7045\"},{\"source_epoch\":\"71821\",\"target_epoch\":\"71822\",\"signing_root\":\"0xd52fd16a994e5c0321acbe99f75050ab35f34a40f830bdf2c7e22639fde32bba\"},{\"source_epoch\":\"71822\",\"target_epoch\":\"71823\",\"signing_root\":\"0x72f7fabc617608017e405fb4b7d38a5cb32415d02f680aba4197399a4297e85c\"},{\"source_epoch\":\"71823\",\"target_epoch\":\"71824\",\"signing_root\":\"0x833d572c3175a3da0ff52daa77a1c43930f5cfb1bd76d949e709b7499f2ce976\"},{\"source_epoch\":\"71824\",\"target_epoch\":\"71825\",\"signing_root\":\"0xb41571cdf4b6bddac9de6fd9d8dd307db80f4bdaffd59f9a5453c9e369e63857\"},{\"source_epoch\":\"71825\",\"target_epoch\":\"71826\",\"signing_root\":\"0x6128c2914d23051a0dd850271ef82d5cee0ea060da153d9557b8d79ca4df0f96\"},{\"source_epoch\":\"71826\",\"target_epoch\":\"71827\",\"signing_root\":\"0xf360a01608e54d16da72133511b7d6a5e535bf2a6ec2f8e793424126808d50e5\"},{\"source_epoch\":\"71827\",\"target_epoch\":\"71828\",\"signing_root\":\"0xb54d8eaa2f26c61f3b63d4691f88970c6ee0d4180e704f7e1333a7de7381ebc7\"},{\"source_epoch\":\"71828\",\"target_epoch\":\"71829\",\"signing_root\":\"0x0b6dfce0ba24e05930e91ace94988785d3334d45f33356801895a07ba7a1c820\"},{\"source_epoch\":\"71829\",\"target_epoch\":\"71830\",\"signing_root\":\"0xb36a3059dac0dd3c76d7557b67c2134f7b01f40e636e37149a3656dd0b77bb63\"},{\"source_epoch\":\"71830\",\"target_epoch\":\"71831\",\"signing_root\":\"0xa82420dd16591544680bd55eb05491a69fe2ed37fab16d6f4b858c2f45dfbc90\"},{\"source_epoch\":\"71831\",\"target_epoch\":\"71832\",\"signing_root\":\"0x2a59b5be18b4223ccf1ccb895c9bd959808d96e252cb098485ef73816b818a4c\"},{\"source_epoch\":\"71832\",\"target_epoch\":\"71833\",\"signing_root\":\"0xbb031ce7ed980a545eccdf330a109c748003e816a9376a6ca51bf126037f1520\"},{\"source_epoch\":\"71833\",\"target_epoch\":\"71834\",\"signing_root\":\"0x9efcb9af1e9ed8b9b0c05726159d1bf9c8190a5b6b4630e4a0ba48ddb328e444\"},{\"source_epoch\":\"71834\",\"target_epoch\":\"71835\",\"signing_root\":\"0x1b48057c770f415b4c2a67197dcb7eebcf05a90f87ee818034291fa3e0f2cdbc\"},{\"source_epoch\":\"71835\",\"target_epoch\":\"71836\",\"signing_root\":\"0x33f7a8c54ef1e3e353537901a195a0be1ffbc0d9922f15fc18e836f7d9d49d13\"},{\"source_epoch\":\"71836\",\"target_epoch\":\"71837\",\"signing_root\":\"0x1289e1b831366e1dce42eacf93ce357ce4793c143251953d43d086f8ce738b93\"},{\"source_epoch\":\"71837\",\"target_epoch\":\"71838\",\"signing_root\":\"0x09abf84d9b8b528ce6fdfb4d6b456a380f6def97ac33600680c740a58c4824af\"},{\"source_epoch\":\"71838\",\"target_epoch\":\"71839\",\"signing_root\":\"0x8b5201fa5038f1aedd85258352a9380a70d423cd23300fd4cf27ae20957f65e0\"},{\"source_epoch\":\"71839\",\"target_epoch\":\"71840\",\"signing_root\":\"0x13ccfddfc270176a5379218974d7e62984b07cf23025cb4b579a4c6a209549cf\"},{\"source_epoch\":\"71840\",\"target_epoch\":\"71841\",\"signing_root\":\"0x9f2249c6bdfeec47b52609189c4befbb5b39debf5cafa25d7d280a65b08c6ccf\"},{\"source_epoch\":\"71841\",\"target_epoch\":\"71842\",\"signing_root\":\"0xe4a6f8bdd4d6cc255ad80c39618e8f3c2c64ace4d5bde8aedc90bcecad6713b8\"},{\"source_epoch\":\"71842\",\"target_epoch\":\"71843\",\"signing_root\":\"0xc495fe48309ebbccb7e888772a0174978a57e37f135f418d822081de62422bc9\"},{\"source_epoch\":\"72225\",\"target_epoch\":\"72226\",\"signing_root\":\"0x399d34a7be6120925668009f2fb6bc1cdcde7ffa9d96ef5bdf6f13db49bdef93\"},{\"source_epoch\":\"72226\",\"target_epoch\":\"72227\",\"signing_root\":\"0x0b81c94db5d4cf6a12c9198a407f811019464899126ae16b040bd25fa3f52a47\"}]}]}"
} as DeleteAccountsResponse,
} as RestObject
} as RestObject,
'/eth/v1/validator/{pubkey}/feerecipient':{
'GET':{
data:{
pubkey:"0xaadaf653799229200378369ee7d6d9fdbdcdc2788143ed44f1ad5f2367c735e83a37c5bb80d7fb917de73a61bbcf00c4",
ethaddress: "0xasdfsadfsfsfsdfsadfsdafsadfsadsdafasdf"
}
} as ListFeeRecipientResponse,
'POST':{},
'DELETE':{},
}as RestObject
}

export interface RestObject {
Expand Down
19 changes: 18 additions & 1 deletion src/app/modules/core/services/validator.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, zip } from 'rxjs';
import { Observable, Subject, zip } from 'rxjs';
import { map, share, switchMap } from 'rxjs/operators';
import {
ValidatorBalances, Validators, ValidatorSummaryResponse
} from 'src/app/proto/eth/v1alpha1/beacon_chain';
import { VersionResponse } from 'src/app/proto/validator/accounts/v2/web_api';
import { ListFeeRecipientResponse, SetFeeRecipientRequest } from 'src/app/proto/validator/accounts/v2/web_api_keymanager-api';
import { base64ToHex } from '../utils/hex-util';
import { EnvironmenterService } from './environmenter.service';
import { WalletService } from './wallet.service';

Expand All @@ -24,6 +26,9 @@ export class ValidatorService {
private environmenter: EnvironmenterService,
) { }
private apiUrl = this.environmenter.env.validatorEndpoint;
private keymanagerUrl = this.environmenter.env.keymanagerEndpoint;

refreshTableDataTrigger$ = new Subject<Boolean>();

version$: Observable<VersionResponse> = this.http.get<VersionResponse>(`${this.apiUrl}/health/version`).pipe(
share(),
Expand Down Expand Up @@ -57,6 +62,18 @@ export class ValidatorService {
return this.http.get<Validators>(`${this.apiUrl}/beacon/validators${params}`);
}

getFeeRecipient(publicKey:string): Observable< ListFeeRecipientResponse>{
return this.http.get<ListFeeRecipientResponse>(`${this.keymanagerUrl}/validator/${base64ToHex(publicKey)}/feerecipient`)
}

setFeeRecipient(publicKey:string,request: SetFeeRecipientRequest){
return this.http.post(`${this.keymanagerUrl}/validator/${publicKey}/feerecipient`,request)
}

deleteFeeRecipient(publicKey:string){
return this.http.delete(`${this.keymanagerUrl}/validator/${publicKey}/feerecipient`)
}

balances(
publicKeys: string[],
pageIndex: number,
Expand Down
2 changes: 1 addition & 1 deletion src/app/modules/core/services/wallet.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class WalletService {
) {}

private apiUrl = this.environmenter.env.validatorEndpoint;
private keymanagerApiUrl = this.environmenter.env.keymanagerEndpoint;
private keymanagerApiUrl = this.environmenter.env.keymanagerEndpoint+"/keystores";

// Observables.
walletConfig$: Observable<WalletResponse> = this.http
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@
{{element.publicKey | base64tohex}}
</td>
</ng-container>

<ng-container matColumnDef="correctlyVotedSource">
<ng-container matColumnDef="feeRecipient">
<th mat-header-cell *matHeaderCellDef>Fee Recipient</th>
<td mat-cell *matCellDef="let element" class="truncate">
{{element.feeRecipient }}
</td>
</ng-container>
<ng-container matColumnDef="correctlyVotedSource" >
<th mat-header-cell *matHeaderCellDef>Correctly voted source</th>
<td mat-cell *matCellDef="let element">
<div [className]="element.correctlyVotedSource ? 'check green' :
Expand All @@ -35,7 +40,7 @@
</td>
</ng-container>

<ng-container matColumnDef="correctlyVotedTarget">
<ng-container matColumnDef="correctlyVotedTarget" >
<th mat-header-cell *matHeaderCellDef>Voted target</th>
<td mat-cell *matCellDef="let element">
<div [className]="element.correctlyVotedTarget ? 'check green' :
Expand All @@ -44,11 +49,10 @@
</td>
</ng-container>

<ng-container matColumnDef="correctlyVotedHead">
<ng-container matColumnDef="correctlyVotedHead" class="max-w-sm">
<th mat-header-cell *matHeaderCellDef>Voted head</th>
<td mat-cell *matCellDef="let element">
<div

[className]="element.correctlyVotedHead ?
'check green' :
'cross red'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ import { MatTableDataSource } from '@angular/material/table';

import { BigNumber } from 'ethers';
import { ValidatorSummaryResponse } from 'src/app/proto/eth/v1alpha1/beacon_chain';
import { throwError } from 'rxjs';
import { catchError, map, take, tap, takeUntil, filter } from 'rxjs/operators';
import { EMPTY, forkJoin, Observable, throwError, zip } from 'rxjs';
import { catchError, map, take, tap, takeUntil, filter, switchMap, flatMap, concatMap, mergeMap } from 'rxjs/operators';
import { ValidatorService } from '../../../core/services/validator.service';
import { BaseComponent } from '../../../shared/components/base.component';
import { UserService } from '../../../shared/services/user.service';
import { ListFeeRecipientResponse } from 'src/app/proto/validator/accounts/v2/web_api_keymanager-api';
import { base64ToHex } from 'src/app/modules/core/utils/hex-util';

export interface ValidatorListItem {
publicKey: string;
feeRecipient: string;
currentEffectiveBalances: string;
correctlyVotedSource: boolean;
correctlyVotedTarget: boolean;
Expand All @@ -31,6 +34,7 @@ export class ValidatorPerformanceListComponent
implements OnInit {
displayedColumns: string[] = [
'publicKey',
'feeRecipient',
'correctlyVotedSource',
'correctlyVotedTarget',
'correctlyVotedHead',
Expand All @@ -56,6 +60,7 @@ export class ValidatorPerformanceListComponent
.pipe(
map((performance: ValidatorSummaryResponse) => {
const list: ValidatorListItem[] = [];

if (performance) {
for (let i = 0; i < performance.public_keys.length; i++) {
// converting snake_case to camelCase
Expand All @@ -78,12 +83,29 @@ export class ValidatorPerformanceListComponent
}
return list;
}),
tap((result) => {
this.dataSource = new MatTableDataSource(result);
switchMap((list:ValidatorListItem[]) => {
const arrayOfRequests: Observable<ListFeeRecipientResponse>[] = [];
list.forEach((item:ValidatorListItem)=>{
arrayOfRequests.push(this.validatorService.getFeeRecipient(item.publicKey));
});
return forkJoin(arrayOfRequests).pipe(
map((res:ListFeeRecipientResponse[]) => {
res.forEach((r)=>{
let item = list.find((obj)=>base64ToHex(obj.publicKey) === r.data.pubkey)
if(item){
item.feeRecipient = r.data.ethaddress
}
})
return list;
})
)
}),
tap((list:ValidatorListItem[])=>{
this.dataSource = new MatTableDataSource(list);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
this.loading = false;
this.noData = result.length === 0;
this.noData = list.length === 0;
}),
catchError((err) => {
this.loading = false;
Expand Down Expand Up @@ -119,3 +141,7 @@ export class ValidatorPerformanceListComponent
this.userService.changeGainsAndLosesPageSize(ev.pageSize);
}
}
function compactMap(arg0: (res: ListFeeRecipientResponse[]) => void): import("rxjs").OperatorFunction<ListFeeRecipientResponse[], unknown> {
throw new Error('Function not implemented.');
}

Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@
<th mat-header-cell *matHeaderCellDef mat-sort-header> Validator Index</th>
<td mat-cell *matCellDef="let row"> {{row.index}} </td>
</ng-container>

<ng-container matColumnDef="feeRecipient">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Fee Recipient</th>
<td mat-cell *matCellDef="let row"
matTooltipPosition="left"
matTooltip="Copy to Clipboard"
(click)="copyFeeRecipientToClipboard(row.feeRecipient)"
class="cursor-pointer"> {{row.feeRecipient | slice:0:8 }}... </td>
</ng-container>
<ng-container matColumnDef="balance">
<th mat-header-cell *matHeaderCellDef mat-sort-header>ETH Balance</th>
<td mat-cell *matCellDef="let row">
Expand Down Expand Up @@ -86,7 +93,7 @@
<div class="flex">
<app-icon-trigger-select
[menuItems]="menuItems"
[data]="row.publicKey"
[data]="row"
icon="more_horiz"></app-icon-trigger-select>
<a mat-icon-button
matTooltip="Exit validator"
Expand Down
Loading

0 comments on commit a6427e4

Please sign in to comment.