Add block-sync to application.
This commit is contained in:
parent
cec92d25b9
commit
ca9ca61ae1
2262
package-lock.json
generated
2262
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -24,8 +24,11 @@
|
|||||||
"datatables.net": "^1.10.22",
|
"datatables.net": "^1.10.22",
|
||||||
"datatables.net-dt": "^1.10.22",
|
"datatables.net-dt": "^1.10.22",
|
||||||
"jquery": "^3.5.1",
|
"jquery": "^3.5.1",
|
||||||
|
"mocha": "^8.2.1",
|
||||||
|
"moolb": "^0.1.0",
|
||||||
"rxjs": "~6.6.0",
|
"rxjs": "~6.6.0",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.0.0",
|
||||||
|
"web3": "^1.3.0",
|
||||||
"zone.js": "~0.10.2"
|
"zone.js": "~0.10.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export * from './transaction';
|
export * from './transaction';
|
||||||
|
export * from './settings';
|
||||||
|
18
src/app/_models/settings.ts
Normal file
18
src/app/_models/settings.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export class Settings {
|
||||||
|
w3: W3 = {
|
||||||
|
engine: undefined,
|
||||||
|
provider: undefined,
|
||||||
|
};
|
||||||
|
scanFilter: any;
|
||||||
|
registry: any;
|
||||||
|
txHelper: any;
|
||||||
|
|
||||||
|
constructor(scanFilter: any) {
|
||||||
|
this.scanFilter = scanFilter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class W3 {
|
||||||
|
engine: any;
|
||||||
|
provider: any;
|
||||||
|
}
|
@ -3,11 +3,14 @@ import {HttpClient} from '@angular/common/http';
|
|||||||
import {map} from 'rxjs/operators';
|
import {map} from 'rxjs/operators';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
import {environment} from '../../environments/environment';
|
import {environment} from '../../environments/environment';
|
||||||
|
import {Conversion, Transaction} from '../_models';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class TransactionService {
|
export class TransactionService {
|
||||||
|
transactions: Transaction[] = [];
|
||||||
|
conversions: Conversion[] = [];
|
||||||
|
|
||||||
constructor(private http: HttpClient) { }
|
constructor(private http: HttpClient) { }
|
||||||
|
|
||||||
@ -24,4 +27,12 @@ export class TransactionService {
|
|||||||
return response;
|
return response;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTransaction(transaction): void {
|
||||||
|
this.transactions.push(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
setConversion(conversion): void {
|
||||||
|
this.conversions.push(conversion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,106 @@
|
|||||||
import { Component } from '@angular/core';
|
import {Component, HostListener, OnInit} from '@angular/core';
|
||||||
|
import {TransactionService} from './_services/transaction.service';
|
||||||
|
import {fetcher} from './../assets/js/plugin';
|
||||||
|
import {Registry, TransactionHelper} from './../assets/js/bancor/registry';
|
||||||
|
import Web3 from 'web3';
|
||||||
|
import { Settings } from './_models';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrls: ['./app.component.scss']
|
styleUrls: ['./app.component.scss']
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent implements OnInit {
|
||||||
title = 'cic-staff-client';
|
title = 'cic-staff-client';
|
||||||
|
registryAddress: string = '0xb708175e3f6Cd850643aAF7B32212AFad50e2549';
|
||||||
|
readyStateTarget: number = 3;
|
||||||
|
readyState: number = 0;
|
||||||
|
|
||||||
|
constructor(private transactionService: TransactionService) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const settings = new Settings(this.scan);
|
||||||
|
const provider = 'ws://localhost:8545';
|
||||||
|
const readyStateElements = {
|
||||||
|
token: 1,
|
||||||
|
network: 2,
|
||||||
|
};
|
||||||
|
settings.w3.provider = provider;
|
||||||
|
settings.w3.engine = new Web3(provider);
|
||||||
|
settings.registry = new Registry(settings.w3.engine, this.registryAddress);
|
||||||
|
settings.txHelper = new TransactionHelper(settings.w3.engine, settings.registry);
|
||||||
|
|
||||||
|
settings.txHelper.ontransfer = async (transaction: any): Promise<void> => {
|
||||||
|
window.dispatchEvent(this.newTransferEvent(transaction));
|
||||||
|
};
|
||||||
|
settings.txHelper.onconversion = async (transaction: any): Promise<any> => {
|
||||||
|
window.dispatchEvent(this.newConversionEvent(transaction));
|
||||||
|
};
|
||||||
|
settings.registry.ontokenload = (tokenCount: number): void => {
|
||||||
|
console.debug('loaded tokens', tokenCount);
|
||||||
|
this.readyStateProcessor(settings, readyStateElements.token);
|
||||||
|
};
|
||||||
|
settings.registry.onregistryload = (tokenCount: number): void => {
|
||||||
|
console.debug('loaded network contracts', tokenCount);
|
||||||
|
this.readyStateProcessor(settings, readyStateElements.network);
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.registry.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
readyStateProcessor(settings, bit): void {
|
||||||
|
this.readyState |= bit;
|
||||||
|
if (this.readyStateTarget === this.readyState && this.readyStateTarget) {
|
||||||
|
console.log('reached readyState target', this.readyStateTarget);
|
||||||
|
fetcher(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newTransferEvent(tx): any {
|
||||||
|
return new CustomEvent('cic_transfer', {
|
||||||
|
detail: {
|
||||||
|
tx,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
newConversionEvent(tx): any {
|
||||||
|
return new CustomEvent('cic_convert', {
|
||||||
|
detail: {
|
||||||
|
tx,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async scan(settings, lo, hi, bloomBlockBytes, bloomBlocktxBytes, bloomRounds): Promise<void> {
|
||||||
|
const w = new Worker('./../assets/js/worker.js');
|
||||||
|
w.onmessage = (m) => {
|
||||||
|
settings.txHelper.processReceipt(m.data);
|
||||||
|
};
|
||||||
|
w.postMessage({
|
||||||
|
w3_provider: settings.w3.provider,
|
||||||
|
lo,
|
||||||
|
hi,
|
||||||
|
filters: [
|
||||||
|
bloomBlockBytes,
|
||||||
|
bloomBlocktxBytes,
|
||||||
|
],
|
||||||
|
filter_rounds: bloomRounds,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('window:cic_transfer', ['$event'])
|
||||||
|
cicTransfer(event: CustomEvent): void {
|
||||||
|
console.log('have tx ', event.detail.tx);
|
||||||
|
const transaction = event.detail.tx;
|
||||||
|
this.transactionService.setTransaction(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('window:cic_convert', ['$event'])
|
||||||
|
cicConvert(event: CustomEvent): void {
|
||||||
|
console.log('have convert ', event.detail.tx);
|
||||||
|
const conversion = event.detail.tx;
|
||||||
|
this.transactionService.setConversion(conversion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
<div *ngIf="conversion" class="mb-5">
|
||||||
|
<div class="card text-center">
|
||||||
|
<div class="card-header bg-dark text-white">
|
||||||
|
<strong>CONVERSION DETAILS</strong>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h4>Exchange: </h4>
|
||||||
|
<h6>Trader Address: {{conversion.trader}}</h6><br>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h4>Source Token: </h4>
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>Address: {{conversion.sourceToken.address}}</p>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>Name: {{conversion.sourceToken.name}}</p>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>Symbol: {{conversion.sourceToken.symbol}}</p>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>Amount: {{conversion.fromValue | currency: conversion.sourceToken.name + ' ' }}</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h4>Destination Token: </h4>
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>Address: {{conversion.destinationToken.address}}</p>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>Name: {{conversion.destinationToken.name}}</p>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>Symbol: {{conversion.destinationToken.symbol}}</p>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p>Amount: {{conversion.toValue | currency: conversion.destinationToken.name + ' ' }}</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,25 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ConversionDetailsComponent } from './conversion-details.component';
|
||||||
|
|
||||||
|
describe('ConversionDetailsComponent', () => {
|
||||||
|
let component: ConversionDetailsComponent;
|
||||||
|
let fixture: ComponentFixture<ConversionDetailsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ ConversionDetailsComponent ]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ConversionDetailsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,17 @@
|
|||||||
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
|
import {Conversion} from '../../../_models';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-conversion-details',
|
||||||
|
templateUrl: './conversion-details.component.html',
|
||||||
|
styleUrls: ['./conversion-details.component.scss']
|
||||||
|
})
|
||||||
|
export class ConversionDetailsComponent implements OnInit {
|
||||||
|
@Input() conversion: Conversion;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
<div *ngIf="transaction" class="mb-5">
|
<div *ngIf="transaction" class="mb-5">
|
||||||
<div class="card">
|
<div class="card text-center">
|
||||||
<div class="card-header text-center bg-dark text-white">
|
<div class="card-header bg-dark text-white">
|
||||||
<strong>TRANSACTIONS DETAILS</strong>
|
<strong>TRANSACTION DETAILS</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let transaction of data">
|
<tr *ngFor="let transaction of transactions">
|
||||||
<td>{{transaction.from}}</td>
|
<td>{{transaction.from}}</td>
|
||||||
<td>{{transaction.to}}</td>
|
<td>{{transaction.to}}</td>
|
||||||
<td>{{transaction.value | currency: transaction.token.name + ' '}}</td>
|
<td>{{transaction.value | currency: transaction.token.name + ' '}}</td>
|
||||||
@ -47,6 +47,49 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
Conversions
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<app-conversion-details [conversion]="conversion"></app-conversion-details>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-bordered table-hover table-sm row-border hover" datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Initial Token</th>
|
||||||
|
<th scope="col">Initial Value</th>
|
||||||
|
<th scope="col">Final Token</th>
|
||||||
|
<th scope="col">Final Value</th>
|
||||||
|
<th scope="col">Trader</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let conversion of conversions">
|
||||||
|
<td>{{conversion.sourceToken.symbol}}</td>
|
||||||
|
<td>{{conversion.fromValue | currency: conversion.sourceToken.name + ' '}}</td>
|
||||||
|
<td>{{conversion.destinationToken.symbol}}</td>
|
||||||
|
<td>{{conversion.toValue | currency: conversion.destinationToken.name + ' '}}</td>
|
||||||
|
<td>{{conversion.trader}}</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-outline-primary" (click)="viewConversion(conversion)"><i class="fa fa-eye"> VIEW </i></button></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Initial Token</th>
|
||||||
|
<th scope="col">Initial Value</th>
|
||||||
|
<th scope="col">Final Token</th>
|
||||||
|
<th scope="col">Final Value</th>
|
||||||
|
<th scope="col">Trader</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<app-footer appMenuSelection></app-footer>
|
<app-footer appMenuSelection></app-footer>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {TransactionService} from '../../_services/transaction.service';
|
import {TransactionService} from '../../_services/transaction.service';
|
||||||
import {Transaction} from '../../_models';
|
import {Conversion, Transaction} from '../../_models';
|
||||||
import {Subject} from 'rxjs';
|
import {Subject} from 'rxjs';
|
||||||
import {first} from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-transactions',
|
selector: 'app-transactions',
|
||||||
@ -10,22 +9,12 @@ import {first} from 'rxjs/operators';
|
|||||||
styleUrls: ['./transactions.component.scss']
|
styleUrls: ['./transactions.component.scss']
|
||||||
})
|
})
|
||||||
export class TransactionsComponent implements OnInit, OnDestroy {
|
export class TransactionsComponent implements OnInit, OnDestroy {
|
||||||
public data: Transaction[] = [
|
|
||||||
{from: '0x36Bd1f197E2b3D2b8213d4A1Dc20a6d949B8C273', to: '0xc14958CD9A605AB0d9A36850362AaD2b9D42DF97', token: {address: '0x36Bd1f197E2b3D2b8213d4A1Dc20a6d949B8C273', name: 'RSV', symbol: 'Reserve Token'}, value: 100000, tx: {block: 20, txIndex: 0, txHash: '0x88a498042610113f1348fdaab03eabd6d67e1d182fb23cb2b580a3db342a5aa5', timestamp: 1603360297, success: true}},
|
|
||||||
{from: '0xc14958CD9A605AB0d9A36850362AaD2b9D42DF97', to: '0xbF0b5cD8Ae50b3bfA304D1f989916038E6d2Fa2e', token: {address: '0x36Bd1f197E2b3D2b8213d4A1Dc20a6d949B8C273', name: 'RSV', symbol: 'Reserve Token'}, value: 100000, tx: {block: 26, txIndex: 0, txHash: '0x165b4a37ccf7f8bf1fac057d509939d890ada47d040d1f8e180aed538c72af6c', timestamp: 1603360298, success: true}},
|
|
||||||
{from: '0x36Bd1f197E2b3D2b8213d4A1Dc20a6d949B8C273', to: '0xe3C4db5947409Aff0FF8D643047EA41515cA4B8e', token: {address: '0x36Bd1f197E2b3D2b8213d4A1Dc20a6d949B8C273', name: 'RSV', symbol: 'Reserve Token'}, value: 50000, tx: {block: 21, txIndex: 0, txHash: '0x552948b95f0bf2768e0ed2251627295d9c60d9d3509f397aa1c585be496dea39', timestamp: 1603360298, success: true}},
|
|
||||||
{from: '0xe3C4db5947409Aff0FF8D643047EA41515cA4B8e', to: '0xee617C30f026536d420358CF00fE60b993975A6f', token: {address: '0x36Bd1f197E2b3D2b8213d4A1Dc20a6d949B8C273', name: 'RSV', symbol: 'Reserve Token'}, value: 50000, tx: {block: 29, txIndex: 0, txHash: '0x2aa5cfb84eb1d36fe9f9554c4633914eb8e5813a47ef07d02b621b96c9d86ffa', timestamp: 1603360298, success: true}},
|
|
||||||
{from: '0x0000000000000000000000000000000000000000', to: '0xc14958CD9A605AB0d9A36850362AaD2b9D42DF97', token: {address: '0x528c3E8B3e6dC646530440D88F83da0e45DaC25b', name: 'BRT', symbol: 'Bert Token'}, value: 400000, tx: {block: 26, txIndex: 0, txHash: '0x165b4a37ccf7f8bf1fac057d509939d890ada47d040d1f8e180aed538c72af6c', timestamp: 1603360298, success: true}},
|
|
||||||
{from: '0x0000000000000000000000000000000000000000', to: '0xe3C4db5947409Aff0FF8D643047EA41515cA4B8e', token: {address: '0x720B26ebd87476b39a47DE50020376d099d7e1A0', name: 'RNI', symbol: 'Ernie Token'}, value: 200000, tx: {block: 29, txIndex: 0, txHash: '0x2aa5cfb84eb1d36fe9f9554c4633914eb8e5813a47ef07d02b621b96c9d86ffa', timestamp: 1603360298, success: true}},
|
|
||||||
{from: '0xc14958CD9A605AB0d9A36850362AaD2b9D42DF97', to: '0x528c3E8B3e6dC646530440D88F83da0e45DaC25b', token: {address: '0x528c3E8B3e6dC646530440D88F83da0e45DaC25b', name: 'BRT', symbol: 'Bert Token'}, value: 100, tx: {block: 33, txIndex: 0, txHash: '0xfbe21fcf7677a760b8792e5499e4cf7d5b9d16b0e343e81502882962467bba3b', timestamp: 1603645828, success: true}},
|
|
||||||
];
|
|
||||||
dtOptions: DataTables.Settings = {};
|
dtOptions: DataTables.Settings = {};
|
||||||
dtTrigger: Subject<any> = new Subject();
|
dtTrigger: Subject<any> = new Subject();
|
||||||
defaultLimit = 100;
|
transactions: Transaction[] = [];
|
||||||
defaultOffset = 0;
|
conversions: Conversion[] = [];
|
||||||
transactions: any[] = [];
|
|
||||||
transaction: Transaction;
|
transaction: Transaction;
|
||||||
error: any;
|
conversion: Conversion;
|
||||||
|
|
||||||
constructor(private transactionService: TransactionService) { }
|
constructor(private transactionService: TransactionService) { }
|
||||||
|
|
||||||
@ -37,15 +26,9 @@ export class TransactionsComponent implements OnInit, OnDestroy {
|
|||||||
processing: true
|
processing: true
|
||||||
};
|
};
|
||||||
|
|
||||||
this.transactionService.getAllTransactions(this.defaultOffset, this.defaultLimit)
|
this.transactions = this.transactionService.transactions;
|
||||||
.pipe(first()).subscribe(response => {
|
this.conversions = this.transactionService.conversions;
|
||||||
this.transactions = response;
|
|
||||||
this.dtTrigger.next();
|
this.dtTrigger.next();
|
||||||
console.log(response);
|
|
||||||
}, error => {
|
|
||||||
this.error = error;
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
@ -55,4 +38,8 @@ export class TransactionsComponent implements OnInit, OnDestroy {
|
|||||||
viewTransaction(transaction): void {
|
viewTransaction(transaction): void {
|
||||||
this.transaction = transaction;
|
this.transaction = transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewConversion(conversion): void {
|
||||||
|
this.conversion = conversion;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,11 @@ import { TransactionsComponent } from './transactions.component';
|
|||||||
import { TransactionDetailsComponent } from './transaction-details/transaction-details.component';
|
import { TransactionDetailsComponent } from './transaction-details/transaction-details.component';
|
||||||
import {DataTablesModule} from 'angular-datatables';
|
import {DataTablesModule} from 'angular-datatables';
|
||||||
import {SharedModule} from '../../shared/shared.module';
|
import {SharedModule} from '../../shared/shared.module';
|
||||||
|
import { ConversionDetailsComponent } from './conversion-details/conversion-details.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [TransactionsComponent, TransactionDetailsComponent],
|
declarations: [TransactionsComponent, TransactionDetailsComponent, ConversionDetailsComponent],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
TransactionsRoutingModule,
|
TransactionsRoutingModule,
|
||||||
|
319
src/assets/js/bancor/registry.js
Normal file
319
src/assets/js/bancor/registry.js
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
import Web3 from "web3";
|
||||||
|
|
||||||
|
if (Web3 === undefined) {
|
||||||
|
Web3 = require('web3');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Load these from json external source
|
||||||
|
const abis = {
|
||||||
|
bancor: {
|
||||||
|
'network':[
|
||||||
|
],
|
||||||
|
'contract_registry': [
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bytes32",
|
||||||
|
"name": "_contractName",
|
||||||
|
"type": "bytes32"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "getAddress",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function",
|
||||||
|
"constant": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'converter_registry': [
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "getConvertibleTokens",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address[]",
|
||||||
|
"name": "",
|
||||||
|
"type": "address[]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function",
|
||||||
|
"constant": true
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
common: {
|
||||||
|
'erc20': [
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "balanceOf",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function",
|
||||||
|
"constant": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "decimals",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint8",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function",
|
||||||
|
"constant": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "name",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "string",
|
||||||
|
"name": "",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function",
|
||||||
|
"constant": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "symbol",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "string",
|
||||||
|
"name": "",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function",
|
||||||
|
"constant": true
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const topics = {
|
||||||
|
erc20: {
|
||||||
|
'transfer': '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
|
||||||
|
'convert': '0x7154b38b5dd31bb3122436a96d4e09aba5b323ae1fd580025fab55074334c095'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function Token(address, name, symbol) {
|
||||||
|
let self = this;
|
||||||
|
self.address = address;
|
||||||
|
self.name = name;
|
||||||
|
self.symbol = symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token.prototype.toString = function() {
|
||||||
|
let self = this;
|
||||||
|
return 'Token: ' + self.name + ' (' + self.symbol + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Registry(w3, address) {
|
||||||
|
let self = this;
|
||||||
|
self.w3 = w3;
|
||||||
|
self.contracts = {
|
||||||
|
'bancor_contract_registry': new self.w3.eth.Contract(abis.bancor['contract_registry'], address),
|
||||||
|
};
|
||||||
|
self.contracts_r = {};
|
||||||
|
self.contracts_r[address] = self.contracts['bancor_contract_registry'];
|
||||||
|
|
||||||
|
self.tokens = [];
|
||||||
|
self.tokens_s = {};
|
||||||
|
self.tokens_r = {};
|
||||||
|
|
||||||
|
self.init = {
|
||||||
|
network: [1, 3], // current index, target index
|
||||||
|
tokens: [0, -1], // current index, target index
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ontokensload= function(n) {
|
||||||
|
console.debug('tokens loaded', n);
|
||||||
|
}
|
||||||
|
self.onregistryload= function() {
|
||||||
|
console.debug('registry loaded');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Registry.prototype.load = async function() {
|
||||||
|
console.debug('loading registry');
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
const cr = self.contracts['bancor_contract_registry'];
|
||||||
|
let crid_hex = self.w3.utils.toHex('BancorConverterRegistry');
|
||||||
|
let shaid = self.w3.eth.abi.encodeParameter('bytes32', crid_hex)
|
||||||
|
cr.methods.getAddress(shaid).call().then((address) => {
|
||||||
|
self.contracts['bancor_converter_registry'] = new self.w3.eth.Contract(abis.bancor['converter_registry'], address);
|
||||||
|
self.contracts_r[address] = self.contracts['bancor_converter_registry'];
|
||||||
|
console.log('bancor converter registry', address);
|
||||||
|
self.load_tokens();
|
||||||
|
self.init.network[0]++;
|
||||||
|
if (self.init.network[0] == self.init.network[1]) {
|
||||||
|
self.onregistryload(self.init.network[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
crid_hex = self.w3.utils.toHex('BancorNetwork');
|
||||||
|
shaid = self.w3.eth.abi.encodeParameter('bytes32', crid_hex)
|
||||||
|
cr.methods.getAddress(shaid).call().then((address) => {
|
||||||
|
self.contracts['bancor_network'] = new self.w3.eth.Contract(abis.bancor['network'], address);
|
||||||
|
self.contracts_r[address] = self.contracts['bancor_network'];
|
||||||
|
console.log('bancor network', address);
|
||||||
|
self.init.network[0]++;
|
||||||
|
if (self.init.network[0] == self.init.network[1]) {
|
||||||
|
self.onregistryload(self.init.network[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Registry.prototype.load_tokens = async function() {
|
||||||
|
console.debug('loading tokens');
|
||||||
|
let self = this;
|
||||||
|
const cr = self.contracts['bancor_converter_registry'];
|
||||||
|
cr.methods.getConvertibleTokens().call().then(async (addresses) => {
|
||||||
|
self.init.tokens[1] = addresses.length;
|
||||||
|
for (const address of addresses) {
|
||||||
|
await self.add_token(address);
|
||||||
|
console.debug('l ', self.tokens.length, addresses.length);
|
||||||
|
if (self.tokens.length === addresses.length) {
|
||||||
|
// self.onload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Registry.prototype.add_token = async function(address) {
|
||||||
|
let self = this;
|
||||||
|
const ct = new self.w3.eth.Contract(abis.common['erc20'], address);
|
||||||
|
const symbol = await ct.methods.symbol().call();
|
||||||
|
const name = await ct.methods.name().call();
|
||||||
|
const t = new Token(address, symbol, name);
|
||||||
|
const ti = self.tokens.length;
|
||||||
|
self.tokens.push(t);
|
||||||
|
self.tokens[t.symbol] = self.tokens[ti];
|
||||||
|
self.tokens_r[address] = self.tokens[ti];
|
||||||
|
self.init.tokens[0]++;
|
||||||
|
console.log('added token', t.toString(), ti, address);
|
||||||
|
if (self.init.tokens[0] == self.init.tokens[1]) {
|
||||||
|
self.ontokenload(self.init.tokens[0]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function Tx(block, tx_index, tx_hash, timestamp, success) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
self.block = block;
|
||||||
|
self.txIndex = tx_index;
|
||||||
|
self.txHash = tx_hash;
|
||||||
|
self.timestamp = timestamp;
|
||||||
|
self.success = success;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Transfer(tx, token, from, to, value, timestamp, block, transaction) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
self.from = from;
|
||||||
|
self.to = to;
|
||||||
|
self.token = token;
|
||||||
|
self.value = value;
|
||||||
|
self.tx = tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Conversion(tx, sourceToken, destinationToken, trader, fromValue, toValue) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
self.sourceToken = sourceToken;
|
||||||
|
self.destinationToken = destinationToken;
|
||||||
|
self.trader = trader;
|
||||||
|
self.fromValue = fromValue;
|
||||||
|
self.toValue = toValue;
|
||||||
|
self.tx = tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TransactionHelper(w3, registry) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
self.registry = registry;
|
||||||
|
self.w3 = w3;
|
||||||
|
self.ontransfer = (t) => {
|
||||||
|
console.debug('transfer ', t);
|
||||||
|
}
|
||||||
|
self.onconversion = (c) => {
|
||||||
|
console.debug('convert ', c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionHelper.prototype.processTokenTransactionLog = async function(success, t, log) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
if (log.topics[0] == topics.erc20['transfer']) {
|
||||||
|
const block = await self.w3.eth.getBlock(log.blockNumber);
|
||||||
|
const from = self.w3.utils.toChecksumAddress(log.topics[1].substring(26, 66));
|
||||||
|
const to = self.w3.utils.toChecksumAddress(log.topics[2].substring(26, 66));
|
||||||
|
const value = self.w3.utils.hexToNumber(log.data);
|
||||||
|
const tx = new Tx(log.blockNumber, log.transactionIndex, log.transactionHash, block.timestamp, success);
|
||||||
|
const transfer = new Transfer(tx, t, from, to, value);
|
||||||
|
self.ontransfer(transfer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionHelper.prototype.processConvertTransactionLog = async function(success, log) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
if (log.topics[0] == topics.erc20['convert']) {
|
||||||
|
const block = await self.w3.eth.getBlock(log.blockNumber);
|
||||||
|
const sourceToken_address = self.w3.utils.toChecksumAddress('0x' + log.topics[1].substring(26, 66));
|
||||||
|
const sourceToken = self.registry.tokens_r[sourceToken_address];
|
||||||
|
const destinationToken_address = self.w3.utils.toChecksumAddress('0x' + log.topics[2].substring(26, 66));
|
||||||
|
const destinationToken = self.registry.tokens_r[destinationToken_address];
|
||||||
|
const fromValue = self.w3.utils.hexToNumber(log.data.substring(0, 66));
|
||||||
|
const toValue = self.w3.utils.hexToNumber('0x' + log.data.substring(66, 130));
|
||||||
|
const trader = self.w3.utils.toChecksumAddress('0x' + log.data.substring(154));
|
||||||
|
const tx = new Tx(log.blockNumber, log.transactionIndex, log.transactionHash, block.timestamp, success);
|
||||||
|
const cv = new Conversion(tx, sourceToken, destinationToken, trader, fromValue, toValue);
|
||||||
|
self.onconversion(cv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionHelper.prototype.processReceipt = async function(r) {
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
const logs = r.logs;
|
||||||
|
for (let i = 0; i < logs.length; i++) {
|
||||||
|
const contract_address = logs[i].address;
|
||||||
|
const t = self.registry.tokens_r[contract_address];
|
||||||
|
if (t !== undefined) {
|
||||||
|
self.processTokenTransactionLog(r.status, t, logs[i]);
|
||||||
|
} else {
|
||||||
|
if (self.registry.contracts_r[contract_address] !== undefined) {
|
||||||
|
self.processConvertTransactionLog(r.status, logs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
168
src/assets/js/moolb.js
Normal file
168
src/assets/js/moolb.js
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
let crypto = undefined;
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
if (typeof module !== 'undefined' && typeof exports !== 'undefined') {
|
||||||
|
const nodeCrypto = require('crypto');
|
||||||
|
function hashWrapper(nodeCrypto, alg) {
|
||||||
|
this.alg = alg;
|
||||||
|
this.crypto = nodeCrypto.createHash(alg);
|
||||||
|
}
|
||||||
|
hashWrapper.prototype.update = function(d) {
|
||||||
|
this.crypto.update(d);
|
||||||
|
}
|
||||||
|
hashWrapper.prototype.digest = async function() {
|
||||||
|
const z = this.crypto.digest(this.data);
|
||||||
|
return new Uint8Array(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cryptoWrapper(nodeCrypto) {
|
||||||
|
this.crypto = nodeCrypto
|
||||||
|
}
|
||||||
|
cryptoWrapper.prototype.createHash = function(alg) {
|
||||||
|
return new hashWrapper(this.crypto, alg);
|
||||||
|
}
|
||||||
|
module.exports = {
|
||||||
|
Bloom: Bloom,
|
||||||
|
fromBytes: fromBytes,
|
||||||
|
};
|
||||||
|
crypto = new cryptoWrapper(nodeCrypto);
|
||||||
|
} else {
|
||||||
|
function hashWrapper(webCrypto, alg) {
|
||||||
|
this.alg = alg;
|
||||||
|
this.crypto = webCrypto;
|
||||||
|
this.data = undefined;
|
||||||
|
}
|
||||||
|
hashWrapper.prototype.update = function(d) {
|
||||||
|
if (this.data != undefined) {
|
||||||
|
throw "cannot append";
|
||||||
|
}
|
||||||
|
this.data = d;
|
||||||
|
}
|
||||||
|
hashWrapper.prototype.digest = async function() {
|
||||||
|
const z = await this.crypto.subtle.digest('SHA-256', this.data);
|
||||||
|
return new Uint8Array(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cryptoWrapper(webCrypto) {
|
||||||
|
this.crypto = webCrypto
|
||||||
|
}
|
||||||
|
cryptoWrapper.prototype.createHash = function(alg) {
|
||||||
|
return new hashWrapper(this.crypto, alg);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto = new cryptoWrapper(window.crypto);
|
||||||
|
window.Bloom = Bloom;
|
||||||
|
window.bloomFromBytes = fromBytes;
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
|
||||||
|
// block numbers 6000000
|
||||||
|
// false positive probability 2%
|
||||||
|
//
|
||||||
|
// m = ceil((n * log(p)) / log(1 / pow(2, log(2))));
|
||||||
|
// m = ceil((6000000 * log(0.1)) / log(1 / pow(2, log(2))))
|
||||||
|
// = 3917675
|
||||||
|
|
||||||
|
// Creates a new bloom object.
|
||||||
|
// \param size of filter in bits, aligned to byte boundary
|
||||||
|
// \param number of rounds to hash
|
||||||
|
// \param hasher function, which must take two Uint8Array parameters 'data' and 'salt'. If not sef, hashBloomDefault will be used.
|
||||||
|
function Bloom(bits, rounds, hasher) {
|
||||||
|
this.bits = bits;
|
||||||
|
this.bytes = parseInt(bits / 8, 10);
|
||||||
|
this.rounds = rounds;
|
||||||
|
if (this.hasher === undefined) {
|
||||||
|
this.hasher = hashBloomDefault;
|
||||||
|
}
|
||||||
|
if (this.bytes * 8 != this.bits) {
|
||||||
|
console.error('number of bits must be on byte boundary');
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
this.filter = new Uint8Array(this.bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add entry to bloom filter
|
||||||
|
// \param value to add
|
||||||
|
Bloom.prototype.add = async function(v) {
|
||||||
|
let a = new ArrayBuffer(v.byteLength + 4);
|
||||||
|
let iw = new DataView(a);
|
||||||
|
for (let i = 0; i < v.byteLength; i++) {
|
||||||
|
iw.setUint8(i, v[i]);
|
||||||
|
}
|
||||||
|
//console.debug(iw, v);
|
||||||
|
for (var i = 0; i < this.rounds; i++) {
|
||||||
|
iw.setInt32(v.byteLength, i);
|
||||||
|
let result = await this.hasher(iw);
|
||||||
|
let resultHex = Array.prototype.map.call(new Uint8Array(result), x => ('00' + x.toString(16)).slice(-2)).join('');
|
||||||
|
let resultInt = parseInt(BigInt('0x'+resultHex) % BigInt(this.bits), 10);
|
||||||
|
let bytepos = parseInt(resultInt / 8, 10);
|
||||||
|
let bitpos = parseInt(resultInt, 10) % 8;
|
||||||
|
this.filter[bytepos] |= 1 << bitpos;
|
||||||
|
//console.log("setpos ", bytepos, bitpos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// checks if the block number has been added to the bloom filter
|
||||||
|
// \param value to check for
|
||||||
|
// \return false if not found in filter
|
||||||
|
Bloom.prototype.check = async function(v) {
|
||||||
|
let a = new ArrayBuffer(v.byteLength + 4);
|
||||||
|
let iw = new DataView(a);
|
||||||
|
for (let i = 0; i < v.byteLength; i++) {
|
||||||
|
iw.setUint8(i, v[i]);
|
||||||
|
}
|
||||||
|
for (let j = 0; j < this.filter.byteLength; j++) {
|
||||||
|
if (v[3] == 20 && this.filter[j] > 0) {
|
||||||
|
console.log('filter ', j, this.filter[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.rounds; i++) {
|
||||||
|
iw.setInt32(v.byteLength, i);
|
||||||
|
let result = await this.hasher(iw);
|
||||||
|
//console.log('result', result);
|
||||||
|
let resultHex = Array.prototype.map.call(new Uint8Array(result), x => ('00' + x.toString(16)).slice(-2)).join('');
|
||||||
|
let resultInt = parseInt(BigInt('0x'+resultHex) % BigInt(this.bits), 10);
|
||||||
|
let bytepos = parseInt(resultInt / 8, 10);
|
||||||
|
//console.log("setpos ", v, bytepos, resultInt % 8);
|
||||||
|
if (this.filter[bytepos] === undefined) {
|
||||||
|
console.error('byte pos ' + bytepos + ' is undefined (filter length ' + this.filter.byteLength + ')');
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
let test = 1 << (0xff & (resultInt % 8));
|
||||||
|
if (v[3] == 20) {
|
||||||
|
console.log('test', test, bytepos, resultInt % 8);
|
||||||
|
}
|
||||||
|
if ((this.filter[bytepos] & test) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// return the verbatim filter
|
||||||
|
// \return Uint8Array filter
|
||||||
|
Bloom.prototype.bytes = function() {
|
||||||
|
return this.filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Default hashing function used in Bloom.add() - sha256
|
||||||
|
// \param data to insert in filter
|
||||||
|
// \param salt, typically a sequence number
|
||||||
|
// \return Uint8Array digest
|
||||||
|
async function hashBloomDefault(data, salt) {
|
||||||
|
const h = crypto.createHash('sha256');
|
||||||
|
h.update(data);
|
||||||
|
const z = await h.digest();
|
||||||
|
return Uint8Array.from(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromBytes(bytes, rounds, hasher) {
|
||||||
|
const bits = bytes.byteLength * 8;
|
||||||
|
let b = new Bloom(bits, rounds, hasher);
|
||||||
|
b.filter = bytes;
|
||||||
|
return b;
|
||||||
|
}
|
31
src/assets/js/plugin.js
Normal file
31
src/assets/js/plugin.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
export function fetcher(settings) {
|
||||||
|
let xhr = new XMLHttpRequest();
|
||||||
|
xhr.responseType = 'json';
|
||||||
|
xhr.open('GET', 'http://localhost:5555/tx/0/100');
|
||||||
|
xhr.addEventListener('load', async (e) => {
|
||||||
|
const d = xhr.response;
|
||||||
|
|
||||||
|
//const digest = await crypto.subtle.digest('SHA-256', ArrayBuffer.from(d.block_filter))
|
||||||
|
//console.log('block filter digest', digest)
|
||||||
|
|
||||||
|
const block_filter_binstr = window.atob(d.block_filter);
|
||||||
|
let b_one = new Uint8Array(block_filter_binstr.length);
|
||||||
|
b_one.map(function(e, i, v) {
|
||||||
|
v[i] = block_filter_binstr.charCodeAt([i]);
|
||||||
|
});
|
||||||
|
|
||||||
|
const blocktx_filter_binstr = window.atob(d.blocktx_filter);
|
||||||
|
let b_two = new Uint8Array(blocktx_filter_binstr.length);
|
||||||
|
b_two.map(function(e, i, v) {
|
||||||
|
v[i] = blocktx_filter_binstr.charCodeAt([i]);
|
||||||
|
});
|
||||||
|
for (let i = 0; i < block_filter_binstr.length; i++) {
|
||||||
|
if (b_one[i] > 0 ) {
|
||||||
|
console.debug('blocktx value on', i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.scanFilter(settings, d.low, d.high, b_one, b_two, d.filter_rounds)
|
||||||
|
});
|
||||||
|
xhr.send();
|
||||||
|
}
|
30
src/assets/js/sync.js
Normal file
30
src/assets/js/sync.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
function sync_by_filter_block(block, count, buf, bloom_blocktx, result_callback) {
|
||||||
|
for (let j = 0; j < count; j++) {
|
||||||
|
let w = new DataView(buf);
|
||||||
|
w.setInt32(4, j);
|
||||||
|
const r = new Uint8Array(buf);
|
||||||
|
bloom_blocktx.check(r).then(function(ok) {
|
||||||
|
if (ok) {
|
||||||
|
console.debug('match in block' + block + ' tx ' + j);
|
||||||
|
result_callback(block, j);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sync_by_filter(caller, lo, hi, bloom_block, bloom_blocktx, tx_count_getter, result_callback) {
|
||||||
|
for (let i = lo; i <= hi; i++) {
|
||||||
|
let a = new ArrayBuffer(8);
|
||||||
|
let w = new DataView(a);
|
||||||
|
w.setInt32(0, i);
|
||||||
|
const r = new Uint8Array(a.slice(0, 4));
|
||||||
|
bloom_block.check(r).then(function(ok) {
|
||||||
|
if (ok) {
|
||||||
|
console.debug('match in block ' + i);
|
||||||
|
tx_count_getter(i).then(function(n) {
|
||||||
|
sync_by_filter_block(i, n, a, bloom_blocktx, result_callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
1
src/assets/js/web3.min.js
vendored
Normal file
1
src/assets/js/web3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
63
src/assets/js/worker.js
Normal file
63
src/assets/js/worker.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
let window = self;
|
||||||
|
|
||||||
|
importScripts('./moolb.js');
|
||||||
|
importScripts('./sync.js');
|
||||||
|
importScripts('./web3.min.js');
|
||||||
|
|
||||||
|
let s = undefined;
|
||||||
|
|
||||||
|
// TODO: as worker has its own scope we don't need the object
|
||||||
|
function Driver(messager, provider, lo, filters, syncer) {
|
||||||
|
this.w3 = new Web3(provider);
|
||||||
|
this.lo = lo;
|
||||||
|
this.hi = lo;
|
||||||
|
this.filters = filters;
|
||||||
|
this.syncer = syncer;
|
||||||
|
this.messager = messager;
|
||||||
|
}
|
||||||
|
|
||||||
|
Driver.prototype.start = function(hi) {
|
||||||
|
let self = this;
|
||||||
|
if (hi !== undefined) {
|
||||||
|
self.sync(hi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s.w3.eth.getBlockNumber().then(function(n) {
|
||||||
|
self.sync(n);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Driver.prototype.sync = function(n) {
|
||||||
|
this.hi = n;
|
||||||
|
this.syncer(this, this.lo, this.hi, this.filters[0], this.filters[1], this.getCount, this.process);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Driver.prototype.process = function(b, t) {
|
||||||
|
s.w3.eth.getTransactionFromBlock(b, t).then((t) => {
|
||||||
|
s.w3.eth.getTransactionReceipt(t.hash).then((r) => {
|
||||||
|
this.postMessage(r);
|
||||||
|
});
|
||||||
|
}).catch(function(e) {
|
||||||
|
//this.postMessage(['failed getTransactionFromBlock(' + b + ', ' + t + ')']);
|
||||||
|
console.error('failed getTransactionFromBlock(' + b + ', ' + t + ')');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Driver.prototype.getCount = async function (b) {
|
||||||
|
const n = s.w3.eth.getBlockTransactionCount(b);
|
||||||
|
return n;
|
||||||
|
};
|
||||||
|
|
||||||
|
onmessage = function(o) {
|
||||||
|
const filters = [
|
||||||
|
bloomFromBytes(o.data.filters[0], o.data.filter_rounds),
|
||||||
|
bloomFromBytes(o.data.filters[1], o.data.filter_rounds),
|
||||||
|
];
|
||||||
|
s = new Driver(postMessage, o.data.w3_provider, o.data.lo, filters, sync_by_filter);
|
||||||
|
let hi = undefined;
|
||||||
|
if (o.data.hi > 0) {
|
||||||
|
hi = o.data.hi;
|
||||||
|
}
|
||||||
|
s.start(hi);
|
||||||
|
};
|
@ -1,3 +1,4 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: true
|
production: true,
|
||||||
|
cicCacheUrl: 'http://localhost:5555'
|
||||||
};
|
};
|
||||||
|
@ -16,5 +16,8 @@
|
|||||||
<script async src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
|
<script async src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
|
||||||
<script async src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
|
<script async src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
|
||||||
<script async src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
|
<script async src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
|
||||||
|
<script async src='assets/js/web3.min.js'></script>
|
||||||
|
<script async src='assets/js/plugin.js'></script>
|
||||||
|
<script async src='assets/js/bancor/registry.js'></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user