Add strong typing to variables and functions.

This commit is contained in:
Spencer Ofwiti 2021-04-29 20:10:39 +03:00
parent d0e0108274
commit 9921488a04
37 changed files with 315 additions and 282 deletions

View File

@ -1,10 +1,8 @@
// @ts-ignore
import * as accountIndex from '@src/assets/js/block-sync/data/AccountRegistry.json';
import {environment} from '@src/environments/environment'; import {environment} from '@src/environments/environment';
const Web3 = require('web3'); import Web3 from 'web3';
const web3 = new Web3(environment.web3Provider); const abi: Array<any> = require('@src/assets/js/block-sync/data/AccountRegistry.json');
const abi = accountIndex.default; const web3: Web3 = new Web3(environment.web3Provider);
export class AccountIndex { export class AccountIndex {
contractAddress: string; contractAddress: string;
@ -30,14 +28,14 @@ export class AccountIndex {
} }
public async last(numberOfAccounts: number): Promise<Array<string>> { public async last(numberOfAccounts: number): Promise<Array<string>> {
const count = await this.totalAccounts(); const count: number = await this.totalAccounts();
let lowest = count - numberOfAccounts - 1; let lowest: number = count - numberOfAccounts - 1;
if (lowest < 0) { if (lowest < 0) {
lowest = 0; lowest = 0;
} }
let accounts = []; const accounts: Array<string> = [];
for (let i = count - 1; i > lowest; i--) { for (let i = count - 1; i > lowest; i--) {
const account = await this.contract.methods.accounts(i).call(); const account: string = await this.contract.methods.accounts(i).call();
accounts.push(account); accounts.push(account);
} }
return accounts; return accounts;
@ -46,8 +44,7 @@ export class AccountIndex {
public async addToAccountRegistry(address: string): Promise<boolean> { public async addToAccountRegistry(address: string): Promise<boolean> {
if (!await this.haveAccount(address)) { if (!await this.haveAccount(address)) {
return await this.contract.methods.add(address).send({from: this.signerAddress}); return await this.contract.methods.add(address).send({from: this.signerAddress});
} else {
return await this.haveAccount(address);
} }
return true;
} }
} }

View File

@ -1,10 +1,8 @@
// @ts-ignore
import * as registryClient from '@src/assets/js/block-sync/data/TokenUniqueSymbolIndex.json';
import Web3 from 'web3'; import Web3 from 'web3';
import {environment} from '@src/environments/environment'; import {environment} from '@src/environments/environment';
const web3 = new Web3(environment.web3Provider); const abi: Array<any> = require('@src/assets/js/block-sync/data/TokenUniqueSymbolIndex.json');
const abi = registryClient.default; const web3: Web3 = new Web3(environment.web3Provider);
export class TokenRegistry { export class TokenRegistry {
contractAddress: string; contractAddress: string;
@ -30,7 +28,7 @@ export class TokenRegistry {
} }
public async addressOf(identifier: string): Promise<string> { public async addressOf(identifier: string): Promise<string> {
const id = '0x' + web3.utils.padRight(new Buffer(identifier).toString('hex'), 64); const id: string = web3.eth.abi.encodeParameter('bytes32', web3.utils.toHex(identifier));
return await this.contract.methods.addressOf(id).call(); return await this.contract.methods.addressOf(id).call();
} }
} }

View File

@ -1,5 +1,7 @@
export class ArraySum { function arraySum(arr: Array<number>): number {
static arraySum(arr: any[]): number { return arr.reduce((accumulator, current) => accumulator + current, 0);
return arr.reduce((accumulator, current) => accumulator + current, 0);
}
} }
export {
arraySum
};

View File

@ -1,6 +1,6 @@
function copyToClipboard(text: any): boolean { function copyToClipboard(text: any): boolean {
// create our hidden div element // create our hidden div element
const hiddenCopy = document.createElement('div'); const hiddenCopy: HTMLDivElement = document.createElement('div');
// set the innerHTML of the div // set the innerHTML of the div
hiddenCopy.innerHTML = text; hiddenCopy.innerHTML = text;
// set the position to be absolute and off the screen // set the position to be absolute and off the screen
@ -21,7 +21,7 @@ function copyToClipboard(text: any): boolean {
// append the div to the body // append the div to the body
document.body.appendChild(hiddenCopy); document.body.appendChild(hiddenCopy);
// create a selection range // create a selection range
const copyRange = document.createRange(); const copyRange: Range = document.createRange();
// set the copy range to be the hidden div // set the copy range to be the hidden div
copyRange.selectNode(hiddenCopy); copyRange.selectNode(hiddenCopy);
// add the copy range // add the copy range

View File

@ -3,7 +3,7 @@ import {FormControl, FormGroupDirective, NgForm} from '@angular/forms';
export class CustomErrorStateMatcher implements ErrorStateMatcher{ export class CustomErrorStateMatcher implements ErrorStateMatcher{
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted; const isSubmitted: boolean = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted)); return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
} }
} }

View File

@ -15,7 +15,7 @@ export class CustomValidator {
return null; return null;
} }
const valid = regex.test(control.value); const valid: boolean = regex.test(control.value);
return valid ? null : error; return valid ? null : error;
}; };
} }

View File

@ -1,12 +1,11 @@
function exportCsv(arrayData: any[], filename: string, delimiter = ','): void { function exportCsv(arrayData: Array<any>, filename: string, delimiter: string = ','): void {
if (arrayData === undefined || arrayData.length === 0) { if (arrayData === undefined || arrayData.length === 0) {
alert('No data to be exported!'); alert('No data to be exported!');
return; return;
} }
const header = Object.keys(arrayData[0]).join(delimiter) + '\n'; let csv: string = Object.keys(arrayData[0]).join(delimiter) + '\n';
let csv = header;
arrayData.forEach(obj => { arrayData.forEach(obj => {
let row = []; const row: Array<any> = [];
for (const key in obj) { for (const key in obj) {
if (obj.hasOwnProperty(key)) { if (obj.hasOwnProperty(key)) {
row.push(obj[key]); row.push(obj[key]);
@ -15,10 +14,10 @@ function exportCsv(arrayData: any[], filename: string, delimiter = ','): void {
csv += row.join(delimiter) + '\n'; csv += row.join(delimiter) + '\n';
}); });
const csvData = new Blob([csv], {type: 'text/csv'}); const csvData: Blob = new Blob([csv], {type: 'text/csv'});
const csvUrl = URL.createObjectURL(csvData); const csvUrl: string = URL.createObjectURL(csvData);
let downloadLink = document.createElement('a'); const downloadLink: HTMLAnchorElement = document.createElement('a');
downloadLink.href = csvUrl; downloadLink.href = csvUrl;
downloadLink.target = '_blank'; downloadLink.target = '_blank';
downloadLink.download = filename + '.csv'; downloadLink.download = filename + '.csv';

View File

@ -3,10 +3,10 @@ import {LoggingService} from '@app/_services/logging.service';
import {HttpErrorResponse} from '@angular/common/http'; import {HttpErrorResponse} from '@angular/common/http';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
// A generalized http repsonse error // A generalized http response error
export class HttpError extends Error { export class HttpError extends Error {
public status: number public status: number;
constructor(message, status) { constructor(message: string, status: number) {
super(message); super(message);
this.status = status; this.status = status;
this.name = 'HttpError'; this.name = 'HttpError';
@ -15,7 +15,7 @@ export class HttpError extends Error {
@Injectable() @Injectable()
export class GlobalErrorHandler extends ErrorHandler { export class GlobalErrorHandler extends ErrorHandler {
private sentencesForWarningLogging: string[] = []; private sentencesForWarningLogging: Array<string> = [];
constructor( constructor(
private loggingService: LoggingService, private loggingService: LoggingService,
@ -26,15 +26,15 @@ export class GlobalErrorHandler extends ErrorHandler {
handleError(error: Error): void { handleError(error: Error): void {
this.logError(error); this.logError(error);
const message = error.message ? error.message : error.toString(); const message: string = error.message ? error.message : error.toString();
// if (error.status) { // if (error.status) {
// error = new Error(message); // error = new Error(message);
// } // }
const errorTraceString = `Error message:\n${message}.\nStack trace: ${error.stack}`; const errorTraceString: string = `Error message:\n${message}.\nStack trace: ${error.stack}`;
const isWarning = this.isWarning(errorTraceString); const isWarning: boolean = this.isWarning(errorTraceString);
if (isWarning) { if (isWarning) {
this.loggingService.sendWarnLevelMessage(errorTraceString, {error}); this.loggingService.sendWarnLevelMessage(errorTraceString, {error});
} else { } else {
@ -45,7 +45,7 @@ export class GlobalErrorHandler extends ErrorHandler {
} }
logError(error: any): void { logError(error: any): void {
const route = this.router.url; const route: string = this.router.url;
if (error instanceof HttpErrorResponse) { if (error instanceof HttpErrorResponse) {
this.loggingService.sendErrorLevelMessage( this.loggingService.sendErrorLevelMessage(
`There was an HTTP error on route ${route}.\n${error.message}.\nStatus code: ${(error as HttpErrorResponse).status}`, `There was an HTTP error on route ${route}.\n${error.message}.\nStatus code: ${(error as HttpErrorResponse).status}`,
@ -60,12 +60,12 @@ export class GlobalErrorHandler extends ErrorHandler {
} }
private isWarning(errorTraceString: string): boolean { private isWarning(errorTraceString: string): boolean {
let isWarning = true; let isWarning: boolean = true;
if (errorTraceString.includes('/src/app/')) { if (errorTraceString.includes('/src/app/')) {
isWarning = false; isWarning = false;
} }
this.sentencesForWarningLogging.forEach((whiteListSentence) => { this.sentencesForWarningLogging.forEach((whiteListSentence: string) => {
if (errorTraceString.includes(whiteListSentence)) { if (errorTraceString.includes(whiteListSentence)) {
isWarning = true; isWarning = true;
} }

View File

@ -1,13 +1,13 @@
function HttpGetter(): void {} function HttpGetter(): void {}
HttpGetter.prototype.get = filename => new Promise((whohoo, doh) => { HttpGetter.prototype.get = filename => new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest(); const xhr: XMLHttpRequest = new XMLHttpRequest();
xhr.addEventListener('load', (e) => { xhr.addEventListener('load', (e) => {
if (xhr.status === 200) { if (xhr.status === 200) {
whohoo(xhr.responseText); resolve(xhr.responseText);
return; return;
} }
doh('failed with status ' + xhr.status + ': ' + xhr.statusText); reject('failed with status ' + xhr.status + ': ' + xhr.statusText);
}); });
xhr.open('GET', filename); xhr.open('GET', filename);
xhr.send(); xhr.send();

View File

@ -3,7 +3,41 @@ import {Injectable} from '@angular/core';
import {Observable, of, throwError} from 'rxjs'; import {Observable, of, throwError} from 'rxjs';
import {delay, dematerialize, materialize, mergeMap} from 'rxjs/operators'; import {delay, dematerialize, materialize, mergeMap} from 'rxjs/operators';
const actions = [ interface Action {
id: number;
user: string;
role: string;
action: string;
approval: boolean;
}
interface Token {
name: string;
symbol: string;
address: string;
supply: string;
decimals: string;
reserves: {};
reserveRatio?: string;
owner?: string;
}
interface Category {
name: string;
products: Array<string>;
}
interface AreaName {
name: string;
locations: Array<string>;
}
interface AreaType {
name: string;
area: Array<string>;
}
const actions: Array<Action> = [
{ id: 1, user: 'Tom', role: 'enroller', action: 'Disburse RSV 100', approval: false }, { id: 1, user: 'Tom', role: 'enroller', action: 'Disburse RSV 100', approval: false },
{ id: 2, user: 'Christine', role: 'admin', action: 'Change user phone number', approval: true }, { id: 2, user: 'Christine', role: 'admin', action: 'Change user phone number', approval: true },
{ id: 3, user: 'Will', role: 'superadmin', action: 'Reclaim RSV 1000', approval: true }, { id: 3, user: 'Will', role: 'superadmin', action: 'Reclaim RSV 1000', approval: true },
@ -12,7 +46,7 @@ const actions = [
{ id: 6, user: 'Patience', role: 'enroller', action: 'Change user information', approval: false } { id: 6, user: 'Patience', role: 'enroller', action: 'Change user information', approval: false }
]; ];
const tokens = [ const tokens: Array<Token> = [
{ {
name: 'Giftable Reserve', symbol: 'GRZ', address: '0xa686005CE37Dce7738436256982C3903f2E4ea8E', supply: '1000000001000000000000000000', name: 'Giftable Reserve', symbol: 'GRZ', address: '0xa686005CE37Dce7738436256982C3903f2E4ea8E', supply: '1000000001000000000000000000',
decimals: '18', reserves: {} decimals: '18', reserves: {}
@ -44,7 +78,7 @@ const tokens = [
} }
]; ];
const categories = [ const categories: Array<Category> = [
{ {
name: 'system', name: 'system',
products: ['system', 'office main', 'office main phone'] products: ['system', 'office main', 'office main phone']
@ -146,7 +180,7 @@ const categories = [
} }
]; ];
const areaNames = [ const areaNames: Array<AreaName> = [
{ {
name: 'Mukuru Nairobi', name: 'Mukuru Nairobi',
locations: ['kayaba', 'kayba', 'kambi', 'mukuru', 'masai', 'hazina', 'south', 'tetra', 'tetrapak', 'ruben', 'rueben', 'kingston', locations: ['kayaba', 'kayba', 'kambi', 'mukuru', 'masai', 'hazina', 'south', 'tetra', 'tetrapak', 'ruben', 'rueben', 'kingston',
@ -211,7 +245,7 @@ const areaNames = [
} }
]; ];
const areaTypes = [ const areaTypes: Array<AreaType> = [
{ {
name: 'urban', name: 'urban',
area: ['urban', 'nairobi', 'mombasa'] area: ['urban', 'nairobi', 'mombasa']
@ -230,9 +264,9 @@ const areaTypes = [
} }
]; ];
const accountTypes = ['user', 'cashier', 'vendor', 'tokenagent', 'group']; const accountTypes: Array<string> = ['user', 'cashier', 'vendor', 'tokenagent', 'group'];
const transactionTypes = ['transactions', 'conversions', 'disbursements', 'rewards', 'reclamation']; const transactionTypes: Array<string> = ['transactions', 'conversions', 'disbursements', 'rewards', 'reclamation'];
const genders = ['male', 'female', 'other']; const genders: Array<string> = ['male', 'female', 'other'];
@Injectable() @Injectable()
export class MockBackendInterceptor implements HttpInterceptor { export class MockBackendInterceptor implements HttpInterceptor {
@ -285,77 +319,77 @@ export class MockBackendInterceptor implements HttpInterceptor {
// route functions // route functions
function getActions(): Observable<any> { function getActions(): Observable<HttpResponse<any>> {
return ok(actions); return ok(actions);
} }
function getActionById(): Observable<any> { function getActionById(): Observable<HttpResponse<any>> {
const queriedAction = actions.find(action => action.id === idFromUrl()); const queriedAction: Action = actions.find(action => action.id === idFromUrl());
return ok(queriedAction); return ok(queriedAction);
} }
function approveAction(): Observable<any> { function approveAction(): Observable<HttpResponse<any>> {
const queriedAction = actions.find(action => action.id === idFromUrl()); const queriedAction: Action = actions.find(action => action.id === idFromUrl());
queriedAction.approval = body.approval; queriedAction.approval = body.approval;
const message = `Action approval status set to ${body.approval} successfully!`; const message: string = `Action approval status set to ${body.approval} successfully!`;
return ok(message); return ok(message);
} }
function getTokens(): Observable<any> { function getTokens(): Observable<HttpResponse<any>> {
return ok(tokens); return ok(tokens);
} }
function getTokenBySymbol(): Observable<any> { function getTokenBySymbol(): Observable<HttpResponse<any>> {
const queriedToken = tokens.find(token => token.symbol === stringFromUrl()); const queriedToken: Token = tokens.find(token => token.symbol === stringFromUrl());
return ok(queriedToken); return ok(queriedToken);
} }
function getCategories(): Observable<any> { function getCategories(): Observable<HttpResponse<any>> {
const categoryList = categories.map(category => category.name); const categoryList: Array<string> = categories.map(category => category.name);
return ok(categoryList); return ok(categoryList);
} }
function getCategoryByProduct(): Observable<any> { function getCategoryByProduct(): Observable<HttpResponse<any>> {
const queriedCategory = categories.find(category => category.products.includes(stringFromUrl())); const queriedCategory: Category = categories.find(category => category.products.includes(stringFromUrl()));
return ok(queriedCategory.name); return ok(queriedCategory.name);
} }
function getAreaNames(): Observable<any> { function getAreaNames(): Observable<HttpResponse<any>> {
const areaNameList = areaNames.map(areaName => areaName.name); const areaNameList: Array<string> = areaNames.map(areaName => areaName.name);
return ok(areaNameList); return ok(areaNameList);
} }
function getAreaNameByLocation(): Observable<any> { function getAreaNameByLocation(): Observable<HttpResponse<any>> {
const queriedAreaName = areaNames.find(areaName => areaName.locations.includes(stringFromUrl())); const queriedAreaName: AreaName = areaNames.find(areaName => areaName.locations.includes(stringFromUrl()));
return ok(queriedAreaName.name); return ok(queriedAreaName.name);
} }
function getAreaTypes(): Observable<any> { function getAreaTypes(): Observable<HttpResponse<any>> {
const areaTypeList = areaTypes.map(areaType => areaType.name); const areaTypeList: Array<string> = areaTypes.map(areaType => areaType.name);
return ok(areaTypeList); return ok(areaTypeList);
} }
function getAreaTypeByArea(): Observable<any> { function getAreaTypeByArea(): Observable<HttpResponse<any>> {
const queriedAreaType = areaTypes.find(areaType => areaType.area.includes(stringFromUrl())); const queriedAreaType: AreaType = areaTypes.find(areaType => areaType.area.includes(stringFromUrl()));
return ok(queriedAreaType.name); return ok(queriedAreaType.name);
} }
function getAccountTypes(): Observable<any> { function getAccountTypes(): Observable<HttpResponse<any>> {
return ok(accountTypes); return ok(accountTypes);
} }
function getTransactionTypes(): Observable<any> { function getTransactionTypes(): Observable<HttpResponse<any>> {
return ok(transactionTypes); return ok(transactionTypes);
} }
function getGenders(): Observable<any> { function getGenders(): Observable<HttpResponse<any>> {
return ok(genders); return ok(genders);
} }
// helper functions // helper functions
function ok(body): Observable<any> { function ok(responseBody: any): Observable<HttpResponse<any>> {
return of(new HttpResponse({ status: 200, body })); return of(new HttpResponse({ status: 200, body: responseBody }));
} }
function error(message): Observable<any> { function error(message): Observable<any> {
@ -363,12 +397,12 @@ export class MockBackendInterceptor implements HttpInterceptor {
} }
function idFromUrl(): number { function idFromUrl(): number {
const urlParts = url.split('/'); const urlParts: Array<string> = url.split('/');
return parseInt(urlParts[urlParts.length - 1], 10); return parseInt(urlParts[urlParts.length - 1], 10);
} }
function stringFromUrl(): string { function stringFromUrl(): string {
const urlParts = url.split('/'); const urlParts: Array<string> = url.split('/');
return urlParts[urlParts.length - 1]; return urlParts[urlParts.length - 1];
} }
} }

View File

@ -1,24 +1,23 @@
let objCsv = { const objCsv: { size: number, dataFile: any } = {
size: 0, size: 0,
dataFile: [] dataFile: []
}; };
function readCsv(input: any): any { function readCsv(input: any): Array<any> | void {
if (input.files && input.files[0]) { if (input.files && input.files[0]) {
let reader = new FileReader(); const reader: FileReader = new FileReader();
reader.readAsBinaryString(input.files[0]); reader.readAsBinaryString(input.files[0]);
reader.onload = event => { reader.onload = event => {
objCsv.size = event.total; objCsv.size = event.total;
// @ts-ignore
objCsv.dataFile = event.target.result; objCsv.dataFile = event.target.result;
return parseData(objCsv.dataFile); return parseData(objCsv.dataFile);
}; };
} }
} }
function parseData(data: any): any { function parseData(data: any): Array<any> {
let csvData = []; const csvData: Array<any> = [];
const lineBreak = data.split('\n'); const lineBreak: Array<any> = data.split('\n');
lineBreak.forEach(res => { lineBreak.forEach(res => {
csvData.push(res.split(',')); csvData.push(res.split(','));
}); });

View File

@ -1,7 +1,7 @@
import { validatePerson, validateVcard } from 'cic-schemas-data-validator'; import { validatePerson, validateVcard } from 'cic-schemas-data-validator';
async function personValidation(person: any): Promise<void> { async function personValidation(person: any): Promise<void> {
const personValidationErrors = await validatePerson(person); const personValidationErrors: any = await validatePerson(person);
if (personValidationErrors) { if (personValidationErrors) {
personValidationErrors.map(error => console.error(`${error.message}`)); personValidationErrors.map(error => console.error(`${error.message}`));
@ -9,7 +9,7 @@ async function personValidation(person: any): Promise<void> {
} }
async function vcardValidation(vcard: any): Promise<void> { async function vcardValidation(vcard: any): Promise<void> {
const vcardValidationErrors = await validateVcard(vcard); const vcardValidationErrors: any = await validateVcard(vcard);
if (vcardValidationErrors) { if (vcardValidationErrors) {
vcardValidationErrors.map(error => console.error(`${error.message}`)); vcardValidationErrors.map(error => console.error(`${error.message}`));

View File

@ -1,4 +1,4 @@
import {Injectable, isDevMode} from '@angular/core'; import {Injectable} from '@angular/core';
import { import {
HttpRequest, HttpRequest,
HttpHandler, HttpHandler,
@ -6,7 +6,7 @@ import {
HttpInterceptor, HttpErrorResponse HttpInterceptor, HttpErrorResponse
} from '@angular/common/http'; } from '@angular/common/http';
import {Observable, throwError} from 'rxjs'; import {Observable, throwError} from 'rxjs';
import {catchError, retry} from 'rxjs/operators'; import {catchError} from 'rxjs/operators';
import {ErrorDialogService, LoggingService} from '@app/_services'; import {ErrorDialogService, LoggingService} from '@app/_services';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
@ -22,7 +22,7 @@ export class ErrorInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe( return next.handle(request).pipe(
catchError((err: HttpErrorResponse) => { catchError((err: HttpErrorResponse) => {
let errorMessage; let errorMessage: string;
if (err.error instanceof ErrorEvent) { if (err.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly. // A client-side or network error occurred. Handle it accordingly.
errorMessage = `An error occurred: ${err.error.message}`; errorMessage = `An error occurred: ${err.error.message}`;

View File

@ -13,7 +13,7 @@ export class HttpConfigInterceptor implements HttpInterceptor {
constructor() {} constructor() {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
// const token = sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN')); // const token: string = sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN'));
// if (token) { // if (token) {
// request = request.clone({headers: request.headers.set('Authorization', 'Bearer ' + token)}); // request = request.clone({headers: request.headers.set('Authorization', 'Bearer ' + token)});

View File

@ -19,20 +19,20 @@ export class LoggingInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> { intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request); return next.handle(request);
// this.loggingService.sendInfoLevelMessage(request); // this.loggingService.sendInfoLevelMessage(request);
// const startTime = Date.now(); // const startTime: number = Date.now();
// let status: string; // let status: string;
//
// return next.handle(request).pipe(tap(event => { // return next.handle(request).pipe(tap(event => {
// status = ''; // status = '';
// if (event instanceof HttpResponse) { // if (event instanceof HttpResponse) {
// status = 'succeeded'; // status = 'succeeded';
// } // }
// }, error => status = 'failed'), // }, error => status = 'failed'),
// finalize(() => { // finalize(() => {
// const elapsedTime = Date.now() - startTime; // const elapsedTime: number = Date.now() - startTime;
// const message = `${request.method} request for ${request.urlWithParams} ${status} in ${elapsedTime} ms`; // const message: string = `${request.method} request for ${request.urlWithParams} ${status} in ${elapsedTime} ms`;
// this.loggingService.sendInfoLevelMessage(message); // this.loggingService.sendInfoLevelMessage(message);
// })); // }));
} }
} }

View File

@ -1,8 +1,9 @@
export interface AccountDetails { interface AccountDetails {
date_registered: number; date_registered: number;
gender: string; gender: string;
age?: string; age?: string;
type?: string; type?: string;
balance?: number;
identities: { identities: {
evm: { evm: {
'bloxberg:8996': string[]; 'bloxberg:8996': string[];
@ -40,25 +41,25 @@ export interface AccountDetails {
}; };
} }
export interface Signature { interface Signature {
algo: string; algo: string;
data: string; data: string;
digest: string; digest: string;
engine: string; engine: string;
} }
export interface Meta { interface Meta {
data: AccountDetails; data: AccountDetails;
id: string; id: string;
signature: Signature; signature: Signature;
} }
export interface MetaResponse { interface MetaResponse {
id: string; id: string;
m: Meta; m: Meta;
} }
export const defaultAccount: AccountDetails = { const defaultAccount: AccountDetails = {
date_registered: Date.now(), date_registered: Date.now(),
gender: 'other', gender: 'other',
identities: { identities: {
@ -94,3 +95,11 @@ export const defaultAccount: AccountDetails = {
}], }],
}, },
}; };
export {
AccountDetails,
Signature,
Meta,
MetaResponse,
defaultAccount
};

View File

@ -1,4 +1,5 @@
export * from '@app/_models/transaction'; export * from '@app/_models/transaction';
export * from '@app/_models/settings'; export * from '@app/_models/settings';
export * from '@app/_models/user';
export * from '@app/_models/account'; export * from '@app/_models/account';
export * from '@app/_models/staff';
export * from '@app/_models/token';

View File

@ -1,4 +1,4 @@
export class Settings { class Settings {
w3: W3 = { w3: W3 = {
engine: undefined, engine: undefined,
provider: undefined, provider: undefined,
@ -12,7 +12,12 @@ export class Settings {
} }
} }
export class W3 { class W3 {
engine: any; engine: any;
provider: any; provider: any;
} }
export {
Settings,
W3
};

View File

@ -1,7 +1,11 @@
export interface Staff { interface Staff {
comment: string; comment: string;
email: string; email: string;
name: string; name: string;
tag: number; tag: number;
userid: string; userid: string;
} }
export {
Staff
};

View File

@ -1,4 +1,4 @@
export interface Token { interface Token {
name: string; name: string;
symbol: string; symbol: string;
address: string; address: string;
@ -13,3 +13,7 @@ export interface Token {
reserveRatio?: string; reserveRatio?: string;
owner?: string; owner?: string;
} }
export {
Token
};

View File

@ -1,6 +1,6 @@
import {User} from '@app/_models/user'; import {AccountDetails} from '@app/_models/account';
export class BlocksBloom { class BlocksBloom {
low: number; low: number;
blockFilter: string; blockFilter: string;
blocktxFilter: string; blocktxFilter: string;
@ -8,13 +8,13 @@ export class BlocksBloom {
filterRounds: number; filterRounds: number;
} }
export class Token { class TxToken {
address: string; address: string;
name: string; name: string;
symbol: string; symbol: string;
} }
export class Tx { class Tx {
block: number; block: number;
success: boolean; success: boolean;
timestamp: number; timestamp: number;
@ -22,22 +22,30 @@ export class Tx {
txIndex: number; txIndex: number;
} }
export class Transaction { class Transaction {
from: string; from: string;
sender: User; sender: AccountDetails;
to: string; to: string;
recipient: User; recipient: AccountDetails;
token: Token; token: TxToken;
tx: Tx; tx: Tx;
value: number; value: number;
} }
export class Conversion { class Conversion {
destinationToken: Token; destinationToken: TxToken;
fromValue: number; fromValue: number;
sourceToken: Token; sourceToken: TxToken;
toValue: number; toValue: number;
trader: string; trader: string;
user: User; user: AccountDetails;
tx: Tx; tx: Tx;
} }
export {
BlocksBloom,
TxToken,
Tx,
Transaction,
Conversion
};

View File

@ -1,22 +0,0 @@
export class User {
dateRegistered: number;
vcard: {
fn: string;
version: string;
tel: [{
meta: {
TYP: string;
};
value: string[];
}];
};
key: {
ethereum: string[];
};
location: {
latitude: string;
longitude: string;
external: {};
};
selling: string[];
}

View File

@ -1,5 +1,5 @@
import { KeyStore } from 'cic-client-meta'; import { KeyStore } from 'cic-client-meta';
// TODO should we put this on the mutalble key store object // TODO should we put this on the mutable key store object
import * as openpgp from 'openpgp'; import * as openpgp from 'openpgp';
const keyring = new openpgp.Keyring(); const keyring = new openpgp.Keyring();
@ -76,15 +76,14 @@ class MutablePgpKeyStore implements MutableKeyStore{
} }
async isValidKey(key): Promise<boolean> { async isValidKey(key): Promise<boolean> {
// There is supposed to be an opengpg.readKey() method but I can't find it? // There is supposed to be an openpgp.readKey() method but I can't find it?
const _key = await openpgp.key.readArmored(key); const _key = await openpgp.key.readArmored(key);
return !_key.err; return !_key.err;
} }
async isEncryptedPrivateKey(privateKey: any): Promise<boolean> { async isEncryptedPrivateKey(privateKey: any): Promise<boolean> {
const imported = await openpgp.key.readArmored(privateKey); const imported = await openpgp.key.readArmored(privateKey);
for (let i = 0; i < imported.keys.length; i++) { for (const key of imported.keys) {
const key = imported.keys[i];
if (key.isDecrypted()) { if (key.isDecrypted()) {
return false; return false;
} }

View File

@ -1,20 +1,19 @@
import { Injectable } from '@angular/core'; import {Injectable} from '@angular/core';
import { hobaParseChallengeHeader } from '@src/assets/js/hoba.js'; import {hobaParseChallengeHeader} from '@src/assets/js/hoba.js';
import { signChallenge } from '@src/assets/js/hoba-pgp.js'; import {signChallenge} from '@src/assets/js/hoba-pgp.js';
import { environment } from '@src/environments/environment'; import {environment} from '@src/environments/environment';
import { LoggingService } from '@app/_services/logging.service'; import {LoggingService} from '@app/_services/logging.service';
import { MutableKeyStore, MutablePgpKeyStore } from '@app/_pgp'; import {MutableKeyStore, MutablePgpKeyStore} from '@app/_pgp';
import { ErrorDialogService } from '@app/_services/error-dialog.service'; import {ErrorDialogService} from '@app/_services/error-dialog.service';
import { HttpClient } from '@angular/common/http'; import {HttpClient} from '@angular/common/http';
import { Observable } from 'rxjs'; import {HttpError} from '@app/_helpers/global-error-handler';
import { HttpError } from '@app/_helpers/global-error-handler';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class AuthService { export class AuthService {
sessionToken: any; sessionToken: any;
sessionLoginCount = 0; sessionLoginCount: number = 0;
mutableKeyStore: MutableKeyStore; mutableKeyStore: MutableKeyStore;
constructor( constructor(
@ -22,18 +21,17 @@ export class AuthService {
private loggingService: LoggingService, private loggingService: LoggingService,
private errorDialogService: ErrorDialogService private errorDialogService: ErrorDialogService
) { ) {
this.mutableKeyStore = new MutablePgpKeyStore() this.mutableKeyStore = new MutablePgpKeyStore();
} }
async init(): Promise<void> { async init(): Promise<void> {
this.mutableKeyStore.loadKeyring(); await this.mutableKeyStore.loadKeyring();
// TODO setting these together should be atomic // TODO setting these together should be atomic
if (sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN'))) { if (sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN'))) {
this.sessionToken = sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN')); this.sessionToken = sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN'));
} }
if (localStorage.getItem(btoa('CICADA_PRIVATE_KEY'))) { if (localStorage.getItem(btoa('CICADA_PRIVATE_KEY'))) {
this.mutableKeyStore.importPrivateKey(localStorage.getItem(btoa('CICADA_PRIVATE_KEY'))) await this.mutableKeyStore.importPrivateKey(localStorage.getItem(btoa('CICADA_PRIVATE_KEY')));
// this.privateKey = localStorage.getItem(btoa('CICADA_PRIVATE_KEY'));
} }
} }
@ -42,7 +40,7 @@ export class AuthService {
} }
getWithToken(): void { getWithToken(): void {
const xhr = new XMLHttpRequest(); const xhr: XMLHttpRequest = new XMLHttpRequest();
xhr.responseType = 'text'; xhr.responseType = 'text';
xhr.open('GET', environment.cicMetaUrl + window.location.search.substring(1)); xhr.open('GET', environment.cicMetaUrl + window.location.search.substring(1));
xhr.setRequestHeader('Authorization', 'Bearer ' + this.sessionToken); xhr.setRequestHeader('Authorization', 'Bearer ' + this.sessionToken);
@ -59,10 +57,10 @@ export class AuthService {
xhr.send(); xhr.send();
} }
//TODO renmae to send signed challenge and set session. Also seperate these responsibilities // TODO rename to send signed challenge and set session. Also separate these responsibilities
sendResponse(hobaResponseEncoded): Promise<boolean> { sendResponse(hobaResponseEncoded: any): Promise<boolean> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest(); const xhr: XMLHttpRequest = new XMLHttpRequest();
xhr.responseType = 'text'; xhr.responseType = 'text';
xhr.open('GET', environment.cicMetaUrl + window.location.search.substring(1)); xhr.open('GET', environment.cicMetaUrl + window.location.search.substring(1));
xhr.setRequestHeader('Authorization', 'HOBA ' + hobaResponseEncoded); xhr.setRequestHeader('Authorization', 'HOBA ' + hobaResponseEncoded);
@ -80,11 +78,11 @@ export class AuthService {
return resolve(true); return resolve(true);
}); });
xhr.send(); xhr.send();
}) });
} }
getChallenge(): void { getChallenge(): void {
const xhr = new XMLHttpRequest(); const xhr: XMLHttpRequest = new XMLHttpRequest();
xhr.responseType = 'arraybuffer'; xhr.responseType = 'arraybuffer';
xhr.open('GET', environment.cicMetaUrl + window.location.search.substring(1)); xhr.open('GET', environment.cicMetaUrl + window.location.search.substring(1));
xhr.onload = async (e) => { xhr.onload = async (e) => {
@ -117,25 +115,26 @@ export class AuthService {
} }
async loginResponse(o): Promise<any> { async loginResponse(o: { challenge: string, realm: any }): Promise<any> {
return new Promise(async(resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
const r = await signChallenge(o.challenge, const r = await signChallenge(o.challenge,
o.realm, o.realm,
environment.cicMetaUrl, environment.cicMetaUrl,
this.mutableKeyStore); this.mutableKeyStore);
const sessionTokenResult = await this.sendResponse(r); const sessionTokenResult: boolean = await this.sendResponse(r);
} catch (error) { } catch (error) {
if (error instanceof HttpError) { if (error instanceof HttpError) {
if (error.status === 403) { if (error.status === 403) {
this.errorDialogService.openDialog({ message: 'You are not authorized to use this system' }) this.errorDialogService.openDialog({ message: 'You are not authorized to use this system' });
} }
if (error.status === 401) { if (error.status === 401) {
this.errorDialogService.openDialog({ message: 'Unable to authenticate with the service. ' + this.errorDialogService.openDialog({
'Please speak with the staff at Grassroots ' + message: 'Unable to authenticate with the service. ' +
'Economics for requesting access ' + 'Please speak with the staff at Grassroots ' +
'staff@grassrootseconomics.net.' }) 'Economics for requesting access ' +
'staff@grassrootseconomics.net.'
});
} }
} }
// TODO define this error // TODO define this error
@ -158,10 +157,10 @@ export class AuthService {
throw Error('The private key is invalid'); throw Error('The private key is invalid');
} }
// TODO leaving this out for now. // TODO leaving this out for now.
//const isEncryptedKeyCheck = await this.mutableKeyStore.isEncryptedPrivateKey(privateKeyArmored); // const isEncryptedKeyCheck = await this.mutableKeyStore.isEncryptedPrivateKey(privateKeyArmored);
//if (!isEncryptedKeyCheck) { // if (!isEncryptedKeyCheck) {
// throw Error('The private key doesn\'t have a password!'); // throw Error('The private key doesn\'t have a password!');
//} // }
const key = await this.mutableKeyStore.importPrivateKey(privateKeyArmored); const key = await this.mutableKeyStore.importPrivateKey(privateKeyArmored);
localStorage.setItem(btoa('CICADA_PRIVATE_KEY'), privateKeyArmored); localStorage.setItem(btoa('CICADA_PRIVATE_KEY'), privateKeyArmored);
} catch (err) { } catch (err) {
@ -182,21 +181,20 @@ export class AuthService {
} }
getTrustedUsers(): any { getTrustedUsers(): any {
let trustedUsers = []; const trustedUsers: Array<any> = [];
this.mutableKeyStore.getPublicKeys().forEach(key => trustedUsers.push(key.users[0].userId)); this.mutableKeyStore.getPublicKeys().forEach(key => trustedUsers.push(key.users[0].userId));
return trustedUsers; return trustedUsers;
} }
async getPublicKeys(): Promise<any> { async getPublicKeys(): Promise<any> {
const data = await fetch(environment.publicKeysUrl) return await fetch(environment.publicKeysUrl)
.then(res => { .then(res => {
if (!res.ok) { if (!res.ok) {
//TODO does angular recommend an error interface? // TODO does angular recommend an error interface?
throw Error(`${res.statusText} - ${res.status}`); throw Error(`${res.statusText} - ${res.status}`);
} }
return res.text(); return res.text();
}) });
return data;
} }
getPrivateKey(): any { getPrivateKey(): any {

View File

@ -20,10 +20,10 @@ export class BlockSyncService {
private registryService: RegistryService, private registryService: RegistryService,
) { } ) { }
blockSync(address: string = null, offset: number = 0, limit: number = 100): any { blockSync(address: string = null, offset: number = 0, limit: number = 100): void {
this.transactionService.resetTransactionsList(); this.transactionService.resetTransactionsList();
const settings = new Settings(this.scan); const settings: Settings = new Settings(this.scan);
const readyStateElements = { network: 2 }; const readyStateElements: { network: number } = { network: 2 };
settings.w3.provider = environment.web3Provider; settings.w3.provider = environment.web3Provider;
settings.w3.engine = this.registryService.getWeb3(); settings.w3.engine = this.registryService.getWeb3();
settings.registry = this.registryService.getRegistry(); settings.registry = this.registryService.getRegistry();
@ -46,7 +46,7 @@ export class BlockSyncService {
readyStateProcessor(settings: Settings, bit: number, address: string, offset: number, limit: number): void { readyStateProcessor(settings: Settings, bit: number, address: string, offset: number, limit: number): void {
this.readyState |= bit; this.readyState |= bit;
if (this.readyStateTarget === this.readyState && this.readyStateTarget) { if (this.readyStateTarget === this.readyState && this.readyStateTarget) {
const wHeadSync = new Worker('./../assets/js/block-sync/head.js'); const wHeadSync: Worker = new Worker('./../assets/js/block-sync/head.js');
wHeadSync.onmessage = (m) => { wHeadSync.onmessage = (m) => {
settings.txHelper.processReceipt(m.data); settings.txHelper.processReceipt(m.data);
}; };
@ -65,7 +65,7 @@ export class BlockSyncService {
} }
} }
newTransferEvent(tx): any { newTransferEvent(tx: any): any {
return new CustomEvent('cic_transfer', { return new CustomEvent('cic_transfer', {
detail: { detail: {
tx, tx,
@ -73,7 +73,7 @@ export class BlockSyncService {
}); });
} }
newConversionEvent(tx): any { newConversionEvent(tx: any): any {
return new CustomEvent('cic_convert', { return new CustomEvent('cic_convert', {
detail: { detail: {
tx, tx,
@ -81,8 +81,8 @@ export class BlockSyncService {
}); });
} }
async scan(settings, lo, hi, bloomBlockBytes, bloomBlocktxBytes, bloomRounds): Promise<void> { async scan(settings: Settings, lo: number, hi: number, bloomBlockBytes: Uint8Array, bloomBlocktxBytes: Uint8Array, bloomRounds: any): Promise<void> {
const w = new Worker('./../assets/js/block-sync/ondemand.js'); const w: Worker = new Worker('./../assets/js/block-sync/ondemand.js');
w.onmessage = (m) => { w.onmessage = (m) => {
settings.txHelper.processReceipt(m.data); settings.txHelper.processReceipt(m.data);
}; };
@ -99,12 +99,12 @@ export class BlockSyncService {
} }
fetcher(settings: Settings, transactionsInfo: any): void { fetcher(settings: Settings, transactionsInfo: any): void {
const blockFilterBinstr = window.atob(transactionsInfo.block_filter); const blockFilterBinstr: string = window.atob(transactionsInfo.block_filter);
const bOne = new Uint8Array(blockFilterBinstr.length); const bOne: Uint8Array = new Uint8Array(blockFilterBinstr.length);
bOne.map((e, i, v) => v[i] = blockFilterBinstr.charCodeAt(i)); bOne.map((e, i, v) => v[i] = blockFilterBinstr.charCodeAt(i));
const blocktxFilterBinstr = window.atob(transactionsInfo.blocktx_filter); const blocktxFilterBinstr: string = window.atob(transactionsInfo.blocktx_filter);
const bTwo = new Uint8Array(blocktxFilterBinstr.length); const bTwo: Uint8Array = new Uint8Array(blocktxFilterBinstr.length);
bTwo.map((e, i, v) => v[i] = blocktxFilterBinstr.charCodeAt(i)); bTwo.map((e, i, v) => v[i] = blocktxFilterBinstr.charCodeAt(i));
settings.scanFilter(settings, transactionsInfo.low, transactionsInfo.high, bOne, bTwo, transactionsInfo.filter_rounds); settings.scanFilter(settings, transactionsInfo.low, transactionsInfo.high, bOne, bTwo, transactionsInfo.filter_rounds);

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import {MatDialog} from '@angular/material/dialog'; import {MatDialog, MatDialogRef} from '@angular/material/dialog';
import {ErrorDialogComponent} from '@app/shared/error-dialog/error-dialog.component'; import {ErrorDialogComponent} from '@app/shared/error-dialog/error-dialog.component';
@Injectable({ @Injectable({
@ -17,7 +17,7 @@ export class ErrorDialogService {
return false; return false;
} }
this.isDialogOpen = true; this.isDialogOpen = true;
const dialogRef = this.dialog.open(ErrorDialogComponent, { const dialogRef: MatDialogRef<any> = this.dialog.open(ErrorDialogComponent, {
width: '300px', width: '300px',
data data
}); });

View File

@ -15,31 +15,31 @@ export class LoggingService {
} }
} }
sendTraceLevelMessage(message, source, error): void { sendTraceLevelMessage(message: any, source: any, error: any): void {
this.logger.trace(message, source, error); this.logger.trace(message, source, error);
} }
sendDebugLevelMessage(message, source, error): void { sendDebugLevelMessage(message: any, source: any, error: any): void {
this.logger.debug(message, source, error); this.logger.debug(message, source, error);
} }
sendInfoLevelMessage(message): void { sendInfoLevelMessage(message: any): void {
this.logger.info(message); this.logger.info(message);
} }
sendLogLevelMessage(message, source, error): void { sendLogLevelMessage(message: any, source: any, error: any): void {
this.logger.log(message, source, error); this.logger.log(message, source, error);
} }
sendWarnLevelMessage(message, error): void { sendWarnLevelMessage(message: any, error: any): void {
this.logger.warn(message, error); this.logger.warn(message, error);
} }
sendErrorLevelMessage(message, source, error): void { sendErrorLevelMessage(message: any, source: any, error: any): void {
this.logger.error(message, source, error); this.logger.error(message, source, error);
} }
sendFatalLevelMessage(message, source, error): void { sendFatalLevelMessage(message: any, source: any, error: any): void {
this.logger.fatal(message, source, error); this.logger.fatal(message, source, error);
} }
} }

View File

@ -1,16 +1,16 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import Web3 from 'web3'; import Web3 from 'web3';
import {environment} from '@src/environments/environment'; import {environment} from '@src/environments/environment';
import {CICRegistry} from 'cic-client'; import {CICRegistry, FileGetter} from 'cic-client';
import {HttpGetter} from '@app/_helpers'; import {HttpGetter} from '@app/_helpers';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class RegistryService { export class RegistryService {
web3 = new Web3(environment.web3Provider); web3: Web3 = new Web3(environment.web3Provider);
fileGetter = new HttpGetter(); fileGetter: FileGetter = new HttpGetter();
registry = new CICRegistry(this.web3, environment.registryAddress, 'CICRegistry', this.fileGetter, registry: CICRegistry = new CICRegistry(this.web3, environment.registryAddress, 'CICRegistry', this.fileGetter,
['../../assets/js/block-sync/data']); ['../../assets/js/block-sync/data']);
constructor() { constructor() {

View File

@ -1,4 +1,4 @@
import { Injectable } from '@angular/core'; import { EventEmitter, Injectable } from '@angular/core';
import {environment} from '@src/environments/environment'; import {environment} from '@src/environments/environment';
import {BehaviorSubject, Observable} from 'rxjs'; import {BehaviorSubject, Observable} from 'rxjs';
import {CICRegistry} from 'cic-client'; import {CICRegistry} from 'cic-client';
@ -12,9 +12,7 @@ import {RegistryService} from '@app/_services/registry.service';
export class TokenService { export class TokenService {
registry: CICRegistry; registry: CICRegistry;
tokenRegistry: TokenRegistry; tokenRegistry: TokenRegistry;
tokens: any = ''; LoadEvent: EventEmitter<number> = new EventEmitter<number>();
private tokensList = new BehaviorSubject<any>(this.tokens);
tokensSubject = this.tokensList.asObservable();
constructor( constructor(
private httpClient: HttpClient, private httpClient: HttpClient,
@ -24,11 +22,12 @@ export class TokenService {
this.registry.load(); this.registry.load();
this.registry.onload = async (address: string): Promise<void> => { this.registry.onload = async (address: string): Promise<void> => {
this.tokenRegistry = new TokenRegistry(await this.registry.getContractAddressByName('TokenRegistry')); this.tokenRegistry = new TokenRegistry(await this.registry.getContractAddressByName('TokenRegistry'));
this.LoadEvent.next(Date.now());
}; };
} }
async getTokens(): Promise<any> { async getTokens(): Promise<Array<Promise<string>>> {
const count = await this.tokenRegistry.totalTokens(); const count: number = await this.tokenRegistry.totalTokens();
return Array.from({length: count}, async (v, i) => await this.tokenRegistry.entry(i)); return Array.from({length: count}, async (v, i) => await this.tokenRegistry.entry(i));
} }

View File

@ -16,6 +16,7 @@ import {LoggingService} from '@app/_services/logging.service';
import {HttpClient} from '@angular/common/http'; import {HttpClient} from '@angular/common/http';
import {CICRegistry} from 'cic-client'; import {CICRegistry} from 'cic-client';
import {RegistryService} from '@app/_services/registry.service'; import {RegistryService} from '@app/_services/registry.service';
import Web3 from 'web3';
const vCard = require('vcard-parser'); const vCard = require('vcard-parser');
@Injectable({ @Injectable({
@ -26,7 +27,7 @@ export class TransactionService {
private transactionList = new BehaviorSubject<any[]>(this.transactions); private transactionList = new BehaviorSubject<any[]>(this.transactions);
transactionsSubject = this.transactionList.asObservable(); transactionsSubject = this.transactionList.asObservable();
userInfo: any; userInfo: any;
web3: any; web3: Web3;
registry: CICRegistry; registry: CICRegistry;
constructor( constructor(
@ -115,7 +116,7 @@ export class TransactionService {
const data = fromHex(methodSignature + strip0x(abi)); const data = fromHex(methodSignature + strip0x(abi));
const tx = new Tx(environment.bloxbergChainId); const tx = new Tx(environment.bloxbergChainId);
tx.nonce = await this.web3.eth.getTransactionCount(senderAddress); tx.nonce = await this.web3.eth.getTransactionCount(senderAddress);
tx.gasPrice = await this.web3.eth.getGasPrice(); tx.gasPrice = Number(await this.web3.eth.getGasPrice());
tx.gasLimit = 8000000; tx.gasLimit = 8000000;
tx.to = fromHex(strip0x(transferAuthAddress)); tx.to = fromHex(strip0x(transferAuthAddress));
tx.value = toValue(value); tx.value = toValue(value);

View File

@ -25,18 +25,13 @@ export class UserService {
signer: Signer; signer: Signer;
registry: CICRegistry; registry: CICRegistry;
accountsMeta = []; accounts: Array<AccountDetails> = [];
accounts: any = []; private accountsList: BehaviorSubject<Array<AccountDetails>> = new BehaviorSubject<Array<AccountDetails>>(this.accounts);
private accountsList = new BehaviorSubject<any>(this.accounts); accountsSubject: Observable<Array<AccountDetails>> = this.accountsList.asObservable();
accountsSubject = this.accountsList.asObservable();
actions: any = ''; actions: Array<any> = [];
private actionsList = new BehaviorSubject<any>(this.actions); private actionsList: BehaviorSubject<any> = new BehaviorSubject<any>(this.actions);
actionsSubject = this.actionsList.asObservable(); actionsSubject: Observable<Array<any>> = this.actionsList.asObservable();
staff: any = '';
private staffList = new BehaviorSubject<any>(this.staff);
staffSubject = this.staffList.asObservable();
constructor( constructor(
private httpClient: HttpClient, private httpClient: HttpClient,
@ -54,23 +49,23 @@ export class UserService {
} }
resetPin(phone: string): Observable<any> { resetPin(phone: string): Observable<any> {
const params = new HttpParams().set('phoneNumber', phone); const params: HttpParams = new HttpParams().set('phoneNumber', phone);
return this.httpClient.get(`${environment.cicUssdUrl}/pin`, {params}); return this.httpClient.get(`${environment.cicUssdUrl}/pin`, {params});
} }
getAccountStatus(phone: string): any { getAccountStatus(phone: string): Observable<any> {
const params = new HttpParams().set('phoneNumber', phone); const params: HttpParams = new HttpParams().set('phoneNumber', phone);
return this.httpClient.get(`${environment.cicUssdUrl}/pin`, {params}); return this.httpClient.get(`${environment.cicUssdUrl}/pin`, {params});
} }
getLockedAccounts(offset: number, limit: number): any { getLockedAccounts(offset: number, limit: number): Observable<any> {
return this.httpClient.get(`${environment.cicUssdUrl}/accounts/locked/${offset}/${limit}`); return this.httpClient.get(`${environment.cicUssdUrl}/accounts/locked/${offset}/${limit}`);
} }
async changeAccountInfo(address: string, name: string, phoneNumber: string, age: string, type: string, bio: string, gender: string, async changeAccountInfo(address: string, name: string, phoneNumber: string, age: string, type: string, bio: string, gender: string,
businessCategory: string, userLocation: string, location: string, locationType: string businessCategory: string, userLocation: string, location: string, locationType: string
): Promise<any> { ): Promise<any> {
let accountInfo: any = { const accountInfo: any = {
vcard: { vcard: {
fn: [{}], fn: [{}],
n: [{}], n: [{}],
@ -91,10 +86,10 @@ export class UserService {
accountInfo.location.area_type = locationType; accountInfo.location.area_type = locationType;
await vcardValidation(accountInfo.vcard); await vcardValidation(accountInfo.vcard);
accountInfo.vcard = btoa(vCard.generate(accountInfo.vcard)); accountInfo.vcard = btoa(vCard.generate(accountInfo.vcard));
const accountKey = await User.toKey(address); const accountKey: string = await User.toKey(address);
this.getAccountDetailsFromMeta(accountKey).pipe(first()).subscribe(async res => { this.getAccountDetailsFromMeta(accountKey).pipe(first()).subscribe(async res => {
const syncableAccount: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap(); const syncableAccount: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
let update = []; const update: Array<ArgPair> = [];
for (const prop in accountInfo) { for (const prop in accountInfo) {
update.push(new ArgPair(prop, accountInfo[prop])); update.push(new ArgPair(prop, accountInfo[prop]));
} }
@ -110,8 +105,8 @@ export class UserService {
} }
async updateMeta(syncableAccount: Syncable, accountKey: string, headers: HttpHeaders): Promise<any> { async updateMeta(syncableAccount: Syncable, accountKey: string, headers: HttpHeaders): Promise<any> {
const envelope = await this.wrap(syncableAccount , this.signer); const envelope: Envelope = await this.wrap(syncableAccount , this.signer);
const reqBody = envelope.toJSON(); const reqBody: string = envelope.toJSON();
this.httpClient.put(`${environment.cicMetaUrl}/${accountKey}`, reqBody , { headers }).pipe(first()).subscribe(res => { this.httpClient.put(`${environment.cicMetaUrl}/${accountKey}`, reqBody , { headers }).pipe(first()).subscribe(res => {
this.loggingService.sendInfoLevelMessage(`Response: ${res}`); this.loggingService.sendInfoLevelMessage(`Response: ${res}`);
}); });
@ -121,7 +116,7 @@ export class UserService {
this.httpClient.get(`${environment.cicCacheUrl}/actions`).pipe(first()).subscribe(res => this.actionsList.next(res)); this.httpClient.get(`${environment.cicCacheUrl}/actions`).pipe(first()).subscribe(res => this.actionsList.next(res));
} }
getActionById(id: string): any { getActionById(id: string): Observable<any> {
return this.httpClient.get(`${environment.cicCacheUrl}/actions/${id}`); return this.httpClient.get(`${environment.cicCacheUrl}/actions/${id}`);
} }
@ -138,14 +133,14 @@ export class UserService {
} }
wrap(syncable: Syncable, signer: Signer): Promise<Envelope> { wrap(syncable: Syncable, signer: Signer): Promise<Envelope> {
return new Promise<Envelope>(async (whohoo, doh) => { return new Promise<Envelope>(async (resolve, reject) => {
syncable.setSigner(signer); syncable.setSigner(signer);
syncable.onwrap = async (env) => { syncable.onwrap = async (env) => {
if (env === undefined) { if (env === undefined) {
doh(); reject();
return; return;
} }
whohoo(env); resolve(env);
}; };
await syncable.sign(); await syncable.sign();
}); });
@ -153,9 +148,9 @@ export class UserService {
async loadAccounts(limit: number = 100, offset: number = 0): Promise<void> { async loadAccounts(limit: number = 100, offset: number = 0): Promise<void> {
this.resetAccountsList(); this.resetAccountsList();
const accountIndexAddress = await this.registry.getContractAddressByName('AccountRegistry'); const accountIndexAddress: string = await this.registry.getContractAddressByName('AccountRegistry');
const accountIndexQuery = new AccountIndex(accountIndexAddress); const accountIndexQuery = new AccountIndex(accountIndexAddress);
const accountAddresses = await accountIndexQuery.last(await accountIndexQuery.totalAccounts()); const accountAddresses: Array<string> = await accountIndexQuery.last(await accountIndexQuery.totalAccounts());
this.loggingService.sendInfoLevelMessage(accountAddresses); this.loggingService.sendInfoLevelMessage(accountAddresses);
for (const accountAddress of accountAddresses.slice(offset, offset + limit)) { for (const accountAddress of accountAddresses.slice(offset, offset + limit)) {
await this.getAccountByAddress(accountAddress, limit); await this.getAccountByAddress(accountAddress, limit);
@ -163,13 +158,12 @@ export class UserService {
} }
async getAccountByAddress(accountAddress: string, limit: number = 100): Promise<Observable<AccountDetails>> { async getAccountByAddress(accountAddress: string, limit: number = 100): Promise<Observable<AccountDetails>> {
let accountSubject = new Subject<any>(); let accountSubject: Subject<any> = new Subject<any>();
this.getAccountDetailsFromMeta(await User.toKey(add0x(accountAddress))).pipe(first()).subscribe(async res => { this.getAccountDetailsFromMeta(await User.toKey(add0x(accountAddress))).pipe(first()).subscribe(async res => {
const account = Envelope.fromJSON(JSON.stringify(res)).unwrap(); const account: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
this.accountsMeta.push(account);
const accountInfo = account.m.data; const accountInfo = account.m.data;
await personValidation(accountInfo); await personValidation(accountInfo);
accountInfo.balance = await this.tokenService.getTokenBalance(accountInfo.identities.evm['bloxberg:8996'][0]); accountInfo.balance = await this.tokenService.getTokenBalance(accountInfo.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0]);
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard)); accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
await vcardValidation(accountInfo.vcard); await vcardValidation(accountInfo.vcard);
this.accounts.unshift(accountInfo); this.accounts.unshift(accountInfo);
@ -183,11 +177,11 @@ export class UserService {
} }
async getAccountByPhone(phoneNumber: string, limit: number = 100): Promise<Observable<AccountDetails>> { async getAccountByPhone(phoneNumber: string, limit: number = 100): Promise<Observable<AccountDetails>> {
let accountSubject = new Subject<any>(); let accountSubject: Subject<any> = new Subject<any>();
this.getAccountDetailsFromMeta(await Phone.toKey(phoneNumber)).pipe(first()).subscribe(async res => { this.getAccountDetailsFromMeta(await Phone.toKey(phoneNumber)).pipe(first()).subscribe(async res => {
const response = Envelope.fromJSON(JSON.stringify(res)).unwrap(); const response: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
const address = response.m.data; const address: string = response.m.data;
const account = await this.getAccountByAddress(address, limit); const account: Observable<AccountDetails> = await this.getAccountByAddress(address, limit);
account.subscribe(result => { account.subscribe(result => {
accountSubject.next(result); accountSubject.next(result);
}); });

View File

@ -22,19 +22,18 @@ export class AppComponent {
) { ) {
(async () => { (async () => {
try { try {
await this.authService.mutableKeyStore.loadKeyring(); await this.authService.init();
// this.authService.getPublicKeys() // this.authService.getPublicKeys()
// .pipe(catchError(async (error) => { // .pipe(catchError(async (error) => {
// this.loggingService.sendErrorLevelMessage('Unable to load trusted public keys.', this, {error}); // this.loggingService.sendErrorLevelMessage('Unable to load trusted public keys.', this, {error});
// this.errorDialogService.openDialog({message: 'Trusted keys endpoint can\'t be reached. Please try again later.'}); // this.errorDialogService.openDialog({message: 'Trusted keys endpoint can\'t be reached. Please try again later.'});
// })).subscribe(this.authService.mutableKeyStore.importPublicKey); // })).subscribe(this.authService.mutableKeyStore.importPublicKey);
const publicKeys = await this.authService.getPublicKeys() const publicKeys = await this.authService.getPublicKeys();
await this.authService.mutableKeyStore.importPublicKey(publicKeys); await this.authService.mutableKeyStore.importPublicKey(publicKeys);
} catch(error) { } catch (error) {
this.errorDialogService.openDialog({message: 'Trusted keys endpoint can\'t be reached. Please try again later.'}); this.errorDialogService.openDialog({message: 'Trusted keys endpoint can\'t be reached. Please try again later.'});
// TODO do something to halt user progress...show a sad cicada page 🦗? // TODO do something to halt user progress...show a sad cicada page 🦗?
} }
})(); })();
this.mediaQuery.addListener(this.onResize); this.mediaQuery.addListener(this.onResize);
this.onResize(this.mediaQuery); this.onResize(this.mediaQuery);

View File

@ -27,10 +27,10 @@ export class AuthComponent implements OnInit {
key: ['', Validators.required], key: ['', Validators.required],
}); });
await this.authService.init(); await this.authService.init();
//if (this.authService.privateKey !== undefined) { // if (this.authService.privateKey !== undefined) {
// const setKey = await this.authService.setKey(this.authService.privateKey); // const setKey = await this.authService.setKey(this.authService.privateKey);
// } // }
//} // }
} }
get keyFormStub(): any { return this.keyForm.controls; } get keyFormStub(): any { return this.keyForm.controls; }

View File

@ -9,6 +9,7 @@ import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {copyToClipboard, CustomErrorStateMatcher, exportCsv} from '@app/_helpers'; import {copyToClipboard, CustomErrorStateMatcher, exportCsv} from '@app/_helpers';
import {MatSnackBar} from '@angular/material/snack-bar'; import {MatSnackBar} from '@angular/material/snack-bar';
import {add0x, strip0x} from '@src/assets/js/ethtx/dist/hex'; import {add0x, strip0x} from '@src/assets/js/ethtx/dist/hex';
import {environment} from '@src/environments/environment';
@Component({ @Component({
selector: 'app-account-details', selector: 'app-account-details',
@ -139,7 +140,7 @@ export class AccountDetailsComponent implements OnInit {
} }
viewAccount(account): void { viewAccount(account): void {
this.router.navigateByUrl(`/accounts/${strip0x(account.identities.evm['bloxberg:8996'][0])}`); this.router.navigateByUrl(`/accounts/${strip0x(account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`);
} }
get accountInfoFormStub(): any { return this.accountInfoForm.controls; } get accountInfoFormStub(): any { return this.accountInfoForm.controls; }

View File

@ -4,6 +4,7 @@ import {CustomErrorStateMatcher} from '@app/_helpers';
import {UserService} from '@app/_services'; import {UserService} from '@app/_services';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import {strip0x} from '@src/assets/js/ethtx/dist/hex'; import {strip0x} from '@src/assets/js/ethtx/dist/hex';
import {environment} from '@src/environments/environment';
@Component({ @Component({
selector: 'app-account-search', selector: 'app-account-search',
@ -60,7 +61,7 @@ export class AccountSearchComponent implements OnInit {
(await this.userService.getAccountByPhone(this.phoneSearchFormStub.phoneNumber.value, 100)).subscribe(async res => { (await this.userService.getAccountByPhone(this.phoneSearchFormStub.phoneNumber.value, 100)).subscribe(async res => {
console.log(res); console.log(res);
if (res !== undefined) { if (res !== undefined) {
await this.router.navigateByUrl(`/accounts/${strip0x(res.identities.evm['bloxberg:8996'][0])}`); await this.router.navigateByUrl(`/accounts/${strip0x(res.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`);
} else { } else {
alert('Account not found!'); alert('Account not found!');
} }
@ -74,7 +75,7 @@ export class AccountSearchComponent implements OnInit {
this.addressSearchLoading = true; this.addressSearchLoading = true;
(await this.userService.getAccountByAddress(this.addressSearchFormStub.address.value, 100)).subscribe(async res => { (await this.userService.getAccountByAddress(this.addressSearchFormStub.address.value, 100)).subscribe(async res => {
if (res !== undefined) { if (res !== undefined) {
await this.router.navigateByUrl(`/accounts/${strip0x(res.identities.evm['bloxberg:8996'][0])}`); await this.router.navigateByUrl(`/accounts/${strip0x(res.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`);
} else { } else {
alert('Account not found!'); alert('Account not found!');
} }

View File

@ -7,6 +7,7 @@ import {Router} from '@angular/router';
import {exportCsv} from '@app/_helpers'; import {exportCsv} from '@app/_helpers';
import {strip0x} from '@src/assets/js/ethtx/dist/hex'; import {strip0x} from '@src/assets/js/ethtx/dist/hex';
import {first} from 'rxjs/operators'; import {first} from 'rxjs/operators';
import {environment} from '@src/environments/environment';
@Component({ @Component({
selector: 'app-accounts', selector: 'app-accounts',
@ -57,7 +58,7 @@ export class AccountsComponent implements OnInit {
} }
async viewAccount(account): Promise<void> { async viewAccount(account): Promise<void> {
await this.router.navigateByUrl(`/accounts/${strip0x(account.identities.evm['bloxberg:8996'][0])}`); await this.router.navigateByUrl(`/accounts/${strip0x(account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`);
} }
filterAccounts(): void { filterAccounts(): void {

View File

@ -5,6 +5,7 @@ import {LoggingService, TokenService} from '@app/_services';
import {MatTableDataSource} from '@angular/material/table'; import {MatTableDataSource} from '@angular/material/table';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import {exportCsv} from '@app/_helpers'; import {exportCsv} from '@app/_helpers';
import {TokenRegistry} from '../../_eth';
@Component({ @Component({
selector: 'app-tokens', selector: 'app-tokens',
@ -26,13 +27,14 @@ export class TokensComponent implements OnInit {
) { } ) { }
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
this.tokenService.LoadEvent.subscribe(async () => {
this.tokens = await this.tokenService.getTokens();
});
this.tokens = await this.tokenService.getTokens(); this.tokens = await this.tokenService.getTokens();
this.loggingService.sendInfoLevelMessage(this.tokens); this.loggingService.sendInfoLevelMessage(this.tokens);
this.tokenService.tokensSubject.subscribe(tokens => { this.dataSource = new MatTableDataSource(this.tokens);
this.dataSource = new MatTableDataSource(tokens); this.dataSource.paginator = this.paginator;
this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort;
this.dataSource.sort = this.sort;
});
} }
doFilter(value: string): void { doFilter(value: string): void {