Skip to content

Commit 4dc2615

Browse files
committed
Add contract address ui
1 parent 3457e0e commit 4dc2615

6 files changed

Lines changed: 284 additions & 3 deletions

File tree

src/Blockcore.Explorer/ClientApp/src/app/app.module.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { InsightComponent } from './insight/insight.component';
3131
import { RichlistComponent } from './insight/richlist/richlist.component';
3232
import { TippyDirective } from './shared/tippy.directive';
3333
import { ContractTransactionComponent } from './explorer/contracttransaction/contracttransaction.component';
34+
import { ContractAddressComponent } from './explorer/contractaddress/contractaddress.component';
3435

3536
const routes: Routes = [
3637
{
@@ -97,7 +98,12 @@ const routes: Routes = [
9798
path: ':chain/explorer/contracttransaction/:transaction', component: ContractTransactionComponent, resolve: {
9899
chain: LoadingResolverService
99100
}
100-
}
101+
},
102+
{
103+
path: ':chain/explorer/contractaddress/:address', component: ContractAddressComponent, resolve: {
104+
chain: LoadingResolverService
105+
}
106+
}
101107
];
102108

103109
@NgModule({
@@ -128,7 +134,8 @@ const routes: Routes = [
128134
InsightComponent,
129135
RichlistComponent,
130136
TippyDirective,
131-
ContractTransactionComponent
137+
ContractTransactionComponent,
138+
ContractAddressComponent
132139
],
133140
imports: [
134141
BrowserModule,
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<app-search></app-search>
2+
3+
<div class="box">
4+
<div *ngIf="transaction">
5+
<div class="grid-hash">
6+
<div>
7+
<span class="grid-hash-left"><i class="fas fa-hashtag"></i></span>
8+
<span class="grid-hash-middle breakable">{{transaction.transactionId}}</span>
9+
<span class="grid-hash-middle breakable"><a [routerLink]="['../../','contracttransaction', transaction.transactionId]">Contract Transaction</a></span>
10+
<span class="grid-hash-right">
11+
<div class="grid-double">
12+
</div>
13+
</span>
14+
</div>
15+
</div>
16+
</div>
17+
</div>
18+
19+
<div class="box">
20+
21+
<!--<a class="link block-details-toggle" (click)="toggleDetails()"><span *ngIf="!detailsVisible">View</span><span
22+
*ngIf="detailsVisible">Hide</span>
23+
details</a>-->
24+
25+
<h3><i class="fas fa-receipt"></i>&nbsp;&nbsp;Smart Contract Details</h3>
26+
27+
<app-progress class="centered" *ngIf="!transaction"></app-progress>
28+
<app-error class="centered" [error]="error"></app-error>
29+
30+
<div class="grid-label-value" *ngIf="transaction">
31+
<div>
32+
<span>Is this a new contract</span>
33+
<span>{{transaction.contractOpcode == "create" | yes}}</span>
34+
</div>
35+
<div>
36+
<span>Contract Type</span>
37+
<span>{{transaction.contractCodeType}}</span>
38+
</div>
39+
<div>
40+
<span>Block</span>
41+
<span><a [routerLink]="['../../block', transaction.blockIndex]">{{transaction.blockIndex}}</a></span>
42+
</div>
43+
<div>
44+
<span>Execution Success</span>
45+
<span>{{transaction.success | yes}}</span>
46+
</div>
47+
<div>
48+
<span>Gas Used</span>
49+
<span>{{transaction.gasUsed }}</span>
50+
</div>
51+
<div>
52+
<span>From Address</span>
53+
<span>{{transaction.fromAddress}}</span>
54+
</div>
55+
56+
<div>
57+
<span>Contract Address</span>
58+
<span>{{transaction.contractAddress}}</span>
59+
</div>
60+
61+
<div *ngIf="transaction.error">
62+
<span>Error</span>
63+
<span>{{transaction.error}}</span>
64+
</div>
65+
66+
</div>
67+
</div>
68+
69+
<div class="box">
70+
<h3>Transactions ({{total}})</h3>
71+
72+
<app-progress class="centered" *ngIf="!transactions">Loading transactions...</app-progress>
73+
74+
<div *ngIf="errorTransactions">
75+
<span class="muted">Error: </span> <span class="negative">{{errorTransactions.title}}</span><br><br>
76+
{{errorTransactions.errors | json}}
77+
</div>
78+
79+
<div *ngIf="transactions">
80+
<!-- <div class="grid-list-transactions">
81+
<span></span>
82+
<span>Transaction ID</span>
83+
<span>Height</span>
84+
<span></span>
85+
<span>Amount</span>
86+
</div> -->
87+
88+
<div class="scrollable address-transactions-scrollable" appDetectScroll (onScroll)="onScroll($event)" [bottomOffset]="400" [topOffset]="400">
89+
<div class="grid-list-transactions" *ngFor="let item of transactions">
90+
91+
92+
<span class="left"><a class=" number" [routerLink]="['../../','contracttransaction', item.transactionId]">{{item.transactionId | slice:0:20}}</a></span>
93+
<span class="left">{{item.success}}</span>
94+
<span class="left">{{item.methodName}}</span>
95+
<span class="number left">{{item.gasUsed }} {{setup.Chain.Symbol}}</span>
96+
<span class="left"> <a class="number" [routerLink]="['../../block', item.blockIndex]">{{item.blockIndex}}</a></span>
97+
<span class="address left" tippy tippyType="address">{{item.fromAddress}}</span>
98+
</div>
99+
<br>
100+
<app-progress class="centered" *ngIf="loading">Loading more transactions...</app-progress>
101+
</div>
102+
</div>
103+
104+
</div>
105+
106+
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import { Component, HostBinding, OnInit, OnDestroy, HostListener } from '@angular/core';
2+
import { ActivatedRoute, Route, Router } from '@angular/router';
3+
import { ApiComponent } from 'src/app/api/api.component';
4+
import { ApiService, HttpError } from 'src/app/services/api.service';
5+
import { SetupService } from 'src/app/services/setup.service';
6+
import { ScrollEvent } from 'src/app/shared/scroll.directive';
7+
8+
@Component({
9+
selector: 'app-contractaddress-component',
10+
templateUrl: './contractaddress.component.html'
11+
})
12+
export class ContractAddressComponent implements OnInit, OnDestroy {
13+
@HostBinding('class.content-centered-top') hostClass = true;
14+
15+
info: any;
16+
node: any;
17+
blockchain: any;
18+
network: any;
19+
configuration: any;
20+
consensus: any;
21+
peers: any;
22+
blocks: any;
23+
transactions: any;
24+
transaction: any;
25+
26+
timerInfo: any;
27+
timerBlocks: any;
28+
timerTransactions: any;
29+
address: any;
30+
balance: any;
31+
detailsVisible = false;
32+
lastBlockHeight: number;
33+
subscription: any;
34+
limit = 10;
35+
loading = false;
36+
count = 0;
37+
total: any;
38+
link: string;
39+
error: any;
40+
errorTransactions: any;
41+
42+
constructor(
43+
private api: ApiService,
44+
private router: Router,
45+
public setup: SetupService,
46+
private activatedRoute: ActivatedRoute) {
47+
48+
this.activatedRoute.paramMap.subscribe(async params => {
49+
const id: any = params.get('address');
50+
console.log('Address:', id);
51+
52+
this.transactions = null;
53+
this.address = id;
54+
55+
try {
56+
this.transaction = await this.api.getContractAddress(id);
57+
} catch (err) {
58+
if (err.message[0] === '{') {
59+
this.error = JSON.parse(err.message);
60+
} else {
61+
this.error = err;
62+
}
63+
}
64+
65+
try {
66+
await this.updateTransactions('/api/query/cirrus/contract/' + id + '/transactions?limit=' + this.limit);
67+
} catch (err) {
68+
if (err.message[0] === '{') {
69+
this.errorTransactions = JSON.parse(err.message);
70+
} else {
71+
this.errorTransactions = err;
72+
}
73+
}
74+
});
75+
}
76+
77+
amount(outputs: any[]) {
78+
const filteredOutputs = outputs.filter(o => o.address === this.address);
79+
const amount = filteredOutputs.reduce((acc, item) => acc + item.balance, 0);
80+
81+
return amount;
82+
}
83+
84+
async ngOnInit() {
85+
86+
}
87+
88+
toggleDetails() {
89+
this.detailsVisible = !this.detailsVisible;
90+
}
91+
92+
ngOnDestroy(): void {
93+
94+
}
95+
96+
async updateTransactions(url) {
97+
// If no URL, then likely reached the end.
98+
if (!url) {
99+
return;
100+
}
101+
102+
const baseUrl = this.api.baseUrl.replace('/api', '');
103+
// For the block scrolling (using link http header), we must manually set full URL.
104+
const response = await this.api.request(baseUrl + url);
105+
106+
// When the offset is not set (0), we should reverse the order of items.
107+
const list = await response.json();
108+
109+
if (response.status !== 200) {
110+
if (list && list.status) {
111+
throw new HttpError(list.status, url, JSON.stringify(list));
112+
} else {
113+
throw new HttpError(response.status, url, response.statusText);
114+
}
115+
}
116+
117+
this.total = response.headers.get('Pagination-Total');
118+
const linkHeader = response.headers.get('Link');
119+
const links = this.api.parseLinkHeader(linkHeader);
120+
121+
// This will be set to undefined/null when no more next links is available.
122+
this.link = links['previous'];
123+
124+
125+
126+
if (!this.transactions) {
127+
this.transactions = [];
128+
}
129+
130+
this.transactions = [...this.transactions, ...list];
131+
this.count++;
132+
}
133+
134+
async onScroll(event: ScrollEvent) {
135+
console.log('scroll occurred', event);
136+
137+
if (event.isReachingBottom) {
138+
console.log(`the user is reaching the bottom`);
139+
140+
this.loading = true;
141+
142+
setTimeout(async () => {
143+
await this.updateTransactions(this.link);
144+
this.loading = false;
145+
});
146+
147+
}
148+
if (event.isReachingTop) {
149+
console.log(`the user is reaching the top`);
150+
}
151+
if (event.isWindowEvent) {
152+
console.log(`This event is fired on Window not on an element.`);
153+
}
154+
}
155+
}
156+

src/Blockcore.Explorer/ClientApp/src/app/explorer/contracttransaction/contracttransaction.component.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
<div>
77
<span class="grid-hash-left"><i class="fas fa-hashtag"></i></span>
88
<span class="grid-hash-middle breakable">{{transaction.transactionId}}</span>
9+
<span class="grid-hash-middle breakable"><a [routerLink]="['../../','transaction', transaction.transactionId]">View Transaction</a></span>
10+
11+
912
<span class="grid-hash-right">
1013
<div class="grid-double">
1114
</div>
@@ -67,6 +70,11 @@ <h3><i class="fas fa-receipt"></i>&nbsp;&nbsp;Smart Contract Transaction Details
6770
<span>New Contract Address</span>
6871
<span><a [routerLink]="['../../contractaddress', transaction.newContractAddress]">{{transaction.newContractAddress}}</a></span>
6972
</div>
73+
<div *ngIf="transaction.error">
74+
<span>Error</span>
75+
<span>{{transaction.error}}</span>
76+
</div>
77+
7078

7179

7280
</div>

src/Blockcore.Explorer/ClientApp/src/app/explorer/transaction/transaction.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<span class="grid-hash-left"><i class="fas fa-hashtag"></i></span>
88
<span class="grid-hash-middle breakable">{{transaction.transactionId}}</span>
99
<div *ngIf="transaction.hasContract">
10-
<span class="grid-hash-middle breakable"><a [routerLink]="['../../','contracttransaction', transaction.transactionId]">View Contract Data</a></span>
10+
<span class="grid-hash-middle breakable"><a [routerLink]="['../../','contracttransaction', transaction.transactionId]">Contract Transaction</a></span>
1111
</div>
1212
<span class="grid-hash-right">
1313
<div class="grid-double">

src/Blockcore.Explorer/ClientApp/src/app/services/api.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ export class ApiService {
150150
return this.downloadRelative('/query/cirrus/contract/transaction/' + hash);
151151
}
152152

153+
async getContractAddress(address: string) {
154+
return this.downloadRelative('/query/cirrus/contract/' + address);
155+
}
156+
153157

154158
parseLinkHeader(linkHeader: string) {
155159
const sections = linkHeader.split(', ');

0 commit comments

Comments
 (0)