Add fetching of transaction participants from cic-meta.
Add token registry to query tokens.
This commit is contained in:
parent
7447bf2499
commit
32ab27730b
@ -22,7 +22,7 @@ export class AccountIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async totalAccounts(): Promise<number> {
|
public async totalAccounts(): Promise<number> {
|
||||||
return this.contract.methods.count().call();
|
return await this.contract.methods.count().call();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async haveAccount(address: string): Promise<boolean> {
|
public async haveAccount(address: string): Promise<boolean> {
|
||||||
|
@ -8,3 +8,4 @@ export * from '@app/_helpers/accountIndex';
|
|||||||
export * from '@app/_helpers/http-getter';
|
export * from '@app/_helpers/http-getter';
|
||||||
export * from '@app/_helpers/pgp-signer';
|
export * from '@app/_helpers/pgp-signer';
|
||||||
export * from '@app/_helpers/registry';
|
export * from '@app/_helpers/registry';
|
||||||
|
export * from '@app/_helpers/token-registry';
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Registry } from './registry';
|
import { Registry } from '@app/_helpers/registry';
|
||||||
|
import {environment} from '@src/environments/environment';
|
||||||
|
|
||||||
describe('Registry', () => {
|
describe('Registry', () => {
|
||||||
it('should create an instance', () => {
|
it('should create an instance', () => {
|
||||||
expect(new Registry()).toBeTruthy();
|
expect(new Registry(environment.registryAddress)).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
8
src/app/_helpers/token-registry.spec.ts
Normal file
8
src/app/_helpers/token-registry.spec.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { TokenRegistry } from '@app/_helpers/token-registry';
|
||||||
|
import {environment} from '@src/environments/environment';
|
||||||
|
|
||||||
|
describe('TokenRegistry', () => {
|
||||||
|
it('should create an instance', () => {
|
||||||
|
expect(new TokenRegistry(environment.registryAddress)).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
36
src/app/_helpers/token-registry.ts
Normal file
36
src/app/_helpers/token-registry.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
import * as registryClient from '@src/assets/js/block-sync/data/RegistryClient.json';
|
||||||
|
import Web3 from 'web3';
|
||||||
|
import {environment} from '@src/environments/environment';
|
||||||
|
|
||||||
|
const web3 = new Web3(environment.web3Provider);
|
||||||
|
const abi = registryClient.default;
|
||||||
|
|
||||||
|
export class TokenRegistry {
|
||||||
|
contractAddress: string;
|
||||||
|
signerAddress: string;
|
||||||
|
contract: any;
|
||||||
|
|
||||||
|
constructor(contractAddress: string, signerAddress?: string) {
|
||||||
|
this.contractAddress = contractAddress;
|
||||||
|
this.contract = new web3.eth.Contract(abi, this.contractAddress);
|
||||||
|
if (signerAddress) {
|
||||||
|
this.signerAddress = signerAddress;
|
||||||
|
} else {
|
||||||
|
this.signerAddress = web3.eth.accounts[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async totalTokens(): Promise<number> {
|
||||||
|
return await this.contract.methods.registryCount().call();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async entry(serial: number): Promise<string> {
|
||||||
|
return await this.contract.methods.entry(serial).call();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async addressOf(identifier: string): Promise<string> {
|
||||||
|
const id = '0x' + web3.utils.padRight(new Buffer(identifier).toString('hex'), 64);
|
||||||
|
return await this.contract.methods.addressOf(id).call();
|
||||||
|
}
|
||||||
|
}
|
@ -52,3 +52,40 @@ export interface MetaResponse {
|
|||||||
id: string;
|
id: string;
|
||||||
m: Meta;
|
m: Meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const defaultAccount: AccountDetails = {
|
||||||
|
date_registered: Date.now(),
|
||||||
|
gender: 'other',
|
||||||
|
identities: {
|
||||||
|
evm: {
|
||||||
|
'bloxberg:8996': [''],
|
||||||
|
'oldchain:1': [''],
|
||||||
|
},
|
||||||
|
latitude: 0,
|
||||||
|
longitude: 0,
|
||||||
|
},
|
||||||
|
location: {
|
||||||
|
area_name: 'Kilifi',
|
||||||
|
},
|
||||||
|
products: [],
|
||||||
|
vcard: {
|
||||||
|
email: [{
|
||||||
|
value: '',
|
||||||
|
}],
|
||||||
|
fn: [{
|
||||||
|
value: 'GE',
|
||||||
|
}],
|
||||||
|
n: [{
|
||||||
|
value: ['GE'],
|
||||||
|
}],
|
||||||
|
tel: [{
|
||||||
|
meta: {
|
||||||
|
TYP: [],
|
||||||
|
},
|
||||||
|
value: '',
|
||||||
|
}],
|
||||||
|
version: [{
|
||||||
|
value: '3.0',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -3,11 +3,18 @@ import {HttpClient} from '@angular/common/http';
|
|||||||
import {environment} from '@src/environments/environment';
|
import {environment} from '@src/environments/environment';
|
||||||
import {first} from 'rxjs/operators';
|
import {first} from 'rxjs/operators';
|
||||||
import {BehaviorSubject} from 'rxjs';
|
import {BehaviorSubject} from 'rxjs';
|
||||||
|
import {HttpGetter, Registry, TokenRegistry} from '@app/_helpers';
|
||||||
|
import {CICRegistry} from 'cic-client';
|
||||||
|
import Web3 from 'web3';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class TokenService {
|
export class TokenService {
|
||||||
|
web3 = new Web3(environment.web3Provider);
|
||||||
|
fileGetter = new HttpGetter();
|
||||||
|
registry = new Registry(environment.registryAddress);
|
||||||
|
cicRegistry = new CICRegistry(this.web3, environment.registryAddress, this.fileGetter, ['../../assets/js/block-sync/data']);
|
||||||
tokens: any = '';
|
tokens: any = '';
|
||||||
private tokensList = new BehaviorSubject<any>(this.tokens);
|
private tokensList = new BehaviorSubject<any>(this.tokens);
|
||||||
tokensSubject = this.tokensList.asObservable();
|
tokensSubject = this.tokensList.asObservable();
|
||||||
@ -16,11 +23,19 @@ export class TokenService {
|
|||||||
private http: HttpClient
|
private http: HttpClient
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
getTokens(): any {
|
async getTokens(): Promise<any> {
|
||||||
this.http.get(`${environment.cicCacheUrl}/tokens`).pipe(first()).subscribe(tokens => this.tokensList.next(tokens));
|
const tokenRegistryQuery = new TokenRegistry(await this.registry.addressOf('TokenRegistry'));
|
||||||
|
const count = await tokenRegistryQuery.totalTokens();
|
||||||
|
return Array.from({length: count}, async (v, i) => await tokenRegistryQuery.entry(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
getTokenBySymbol(symbol: string): any {
|
getTokenBySymbol(symbol: string): any {
|
||||||
return this.http.get(`${environment.cicCacheUrl}/tokens/${symbol}`);
|
return this.http.get(`${environment.cicCacheUrl}/tokens/${symbol}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getTokenBalance(address: string): Promise<number> {
|
||||||
|
const tokenRegistryQuery = new TokenRegistry(await this.registry.addressOf('TokenRegistry'));
|
||||||
|
const sarafuToken = await this.cicRegistry.addToken(await tokenRegistryQuery.entry(0));
|
||||||
|
return await sarafuToken.methods.balanceOf(address).call();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import {toValue} from '@src/assets/js/ethtx/dist/tx';
|
|||||||
import * as secp256k1 from 'secp256k1';
|
import * as secp256k1 from 'secp256k1';
|
||||||
import {AuthService} from '@app/_services/auth.service';
|
import {AuthService} from '@app/_services/auth.service';
|
||||||
import {Registry} from '@app/_helpers';
|
import {Registry} from '@app/_helpers';
|
||||||
|
import {defaultAccount} from '@app/_models';
|
||||||
const Web3 = require('web3');
|
const Web3 = require('web3');
|
||||||
const vCard = require('vcard-parser');
|
const vCard = require('vcard-parser');
|
||||||
|
|
||||||
@ -48,20 +49,39 @@ export class TransactionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setTransaction(transaction, cacheSize: number): Promise<void> {
|
async setTransaction(transaction, cacheSize: number): Promise<void> {
|
||||||
const cachedTransaction = this.transactions.find(cachedTx => cachedTx.tx.txHash === transaction.tx.txHash);
|
transaction.value = Number(transaction.value);
|
||||||
if (cachedTransaction) { return; }
|
|
||||||
transaction.type = 'transaction';
|
transaction.type = 'transaction';
|
||||||
transaction.sender = await this.getUser(transaction.from);
|
if (this.transactions.find(cachedTx => cachedTx.tx.txHash === transaction.tx.txHash)) { return; }
|
||||||
transaction.recipient = await this.getUser(transaction.to);
|
try {
|
||||||
await this.addTransaction(transaction, cacheSize);
|
this.userService.getAccountDetailsFromMeta(await User.toKey(transaction.from)).pipe(first()).subscribe(async (res) => {
|
||||||
|
transaction.sender = this.getAccountInfo(res);
|
||||||
|
}, error => {
|
||||||
|
transaction.sender = defaultAccount;
|
||||||
|
});
|
||||||
|
this.userService.getAccountDetailsFromMeta(await User.toKey(transaction.to)).pipe(first()).subscribe(async (res) => {
|
||||||
|
transaction.recipient = this.getAccountInfo(res);
|
||||||
|
}, error => {
|
||||||
|
transaction.recipient = defaultAccount;
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
await this.addTransaction(transaction, cacheSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async setConversion(conversion, cacheSize): Promise<void> {
|
async setConversion(conversion, cacheSize): Promise<void> {
|
||||||
const cachedConversion = this.transactions.find(cachedTx => cachedTx.tx.txHash === conversion.tx.txHash);
|
if (this.transactions.find(cachedTx => cachedTx.tx.txHash === conversion.tx.txHash)) { return; }
|
||||||
if (cachedConversion) { return; }
|
|
||||||
conversion.type = 'conversion';
|
conversion.type = 'conversion';
|
||||||
conversion.sender = conversion.recipient = await this.getUser(conversion.trader);
|
conversion.fromValue = Number(conversion.fromValue);
|
||||||
await this.addTransaction(conversion, cacheSize);
|
conversion.toValue = Number(conversion.toValue);
|
||||||
|
try {
|
||||||
|
this.userService.getAccountDetailsFromMeta(await User.toKey(conversion.trader)).pipe(first()).subscribe(async (res) => {
|
||||||
|
conversion.sender = conversion.recipient = this.getAccountInfo(res);
|
||||||
|
}, error => {
|
||||||
|
conversion.sender = conversion.recipient = defaultAccount;
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
await this.addTransaction(conversion, cacheSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async addTransaction(transaction, cacheSize: number): Promise<void> {
|
async addTransaction(transaction, cacheSize: number): Promise<void> {
|
||||||
@ -72,14 +92,10 @@ export class TransactionService {
|
|||||||
this.transactionList.next(this.transactions);
|
this.transactionList.next(this.transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUser(address: string): Promise<any> {
|
getAccountInfo(account: string): any {
|
||||||
return this.userService.getAccountDetailsFromMeta(await User.toKey(address)).pipe(first()).subscribe(res => {
|
let accountInfo = Envelope.fromJSON(JSON.stringify(account)).unwrap().m.data;
|
||||||
const account = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
||||||
const accountInfo = account.m.data;
|
return accountInfo;
|
||||||
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
|
||||||
this.userInfo = accountInfo;
|
|
||||||
return accountInfo;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async transferRequest(tokenAddress: string, senderAddress: string, recipientAddress: string, value: number): Promise<any> {
|
async transferRequest(tokenAddress: string, senderAddress: string, recipientAddress: string, value: number): Promise<any> {
|
||||||
|
@ -134,7 +134,7 @@ export class UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getUser(userKey: string): any {
|
getUser(userKey: string): any {
|
||||||
this.http.get(`${environment.cicMetaUrl}/${userKey}`, { headers: this.headers }).pipe(first()).subscribe(async res => {
|
return this.http.get(`${environment.cicMetaUrl}/${userKey}`, { headers: this.headers }).pipe(first()).subscribe(async res => {
|
||||||
return Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
return Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -154,19 +154,27 @@ export class UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async loadAccounts(limit: number, offset: number = 0): Promise<void> {
|
async loadAccounts(limit: number, offset: number = 0): Promise<void> {
|
||||||
|
this.resetAccountsList();
|
||||||
const accountIndexAddress = await this.registry.addressOf('AccountRegistry');
|
const accountIndexAddress = await this.registry.addressOf('AccountRegistry');
|
||||||
const accountIndexQuery = new AccountIndex(accountIndexAddress);
|
const accountIndexQuery = new AccountIndex(accountIndexAddress);
|
||||||
const accountAddresses = await accountIndexQuery.last(await accountIndexQuery.totalAccounts());
|
const accountAddresses = await accountIndexQuery.last(await accountIndexQuery.totalAccounts());
|
||||||
console.log(accountAddresses);
|
|
||||||
for (const accountAddress of accountAddresses.slice(offset, offset + limit)) {
|
for (const accountAddress of accountAddresses.slice(offset, offset + limit)) {
|
||||||
this.getAccountDetailsFromMeta(await User.toKey(accountAddress)).pipe(first()).subscribe(res => {
|
this.getAccountDetailsFromMeta(await User.toKey(accountAddress)).pipe(first()).subscribe(res => {
|
||||||
const account = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
const account = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
||||||
this.accountsMeta.push(account);
|
this.accountsMeta.push(account);
|
||||||
const accountInfo = account.m.data;
|
const accountInfo = account.m.data;
|
||||||
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
||||||
this.accounts.push(accountInfo);
|
this.accounts.unshift(accountInfo);
|
||||||
|
if (this.accounts.length > limit) {
|
||||||
|
this.accounts.length = limit;
|
||||||
|
}
|
||||||
this.accountsList.next(this.accounts);
|
this.accountsList.next(this.accounts);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetAccountsList(): void {
|
||||||
|
this.accounts = [];
|
||||||
|
this.accountsList.next(this.accounts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {Component, HostListener} from '@angular/core';
|
import {Component, HostListener} from '@angular/core';
|
||||||
import {TransactionService} from '@app/_services';
|
import {TokenService, TransactionService} from '@app/_services';
|
||||||
import {AuthService} from '@app/_services';
|
import {AuthService} from '@app/_services';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -15,9 +15,11 @@ export class AppComponent {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
|
private tokenService: TokenService,
|
||||||
private transactionService: TransactionService,
|
private transactionService: TransactionService,
|
||||||
) {
|
) {
|
||||||
this.authService.mutableKeyStore.loadKeyring().then(r => this.authService.getPublicKeys().then());
|
this.authService.mutableKeyStore.loadKeyring().then(r => this.authService.getPublicKeys().then());
|
||||||
|
this.tokenService.getTokens().then(async r => console.log('Tokens:', await r));
|
||||||
this.mediaQuery.addListener(this.onResize);
|
this.mediaQuery.addListener(this.onResize);
|
||||||
this.onResize(this.mediaQuery);
|
this.onResize(this.mediaQuery);
|
||||||
}
|
}
|
||||||
|
@ -17,18 +17,6 @@
|
|||||||
<!-- <li *ngIf="account" class="breadcrumb-item active" aria-current="page">{{account?.fn[0].value}}</li>-->
|
<!-- <li *ngIf="account" class="breadcrumb-item active" aria-current="page">{{account?.fn[0].value}}</li>-->
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="card mb-3">
|
|
||||||
<div class="row card-body">
|
|
||||||
<h3>
|
|
||||||
<strong> {{account?.fn[0].value}} </strong>
|
|
||||||
</h3>
|
|
||||||
<span class="ml-auto"><strong>Balance:</strong> {{account?.balance}} RCU</span>
|
|
||||||
<span class="ml-2"><strong>Created:</strong> {{account?.date_registered | date}}</span>
|
|
||||||
<!-- <span class="ml-2"><strong>Address:</strong><a href="{{bloxbergLink}}" target="_blank"> {{account?.identities.evm['bloxberg:8996']}} </a></span>-->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<app-disbursement *ngIf="isDisbursing" (cancelDisbursmentEvent)="addTransfer()" [account]="account">
|
|
||||||
</app-disbursement>
|
|
||||||
<div *ngIf="!account" class="text-center">
|
<div *ngIf="!account" class="text-center">
|
||||||
<div class="spinner-grow text-primary m-1" role="status" style="width: 3rem; height: 3rem;">
|
<div class="spinner-grow text-primary m-1" role="status" style="width: 3rem; height: 3rem;">
|
||||||
<span class="sr-only">Loading...</span>
|
<span class="sr-only">Loading...</span>
|
||||||
@ -41,6 +29,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="account" class="card mt-3 mb-3">
|
<div *ngIf="account" class="card mt-3 mb-3">
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="row card-body">
|
||||||
|
<h3>
|
||||||
|
<strong> {{account?.vcard?.fn[0].value}} </strong>
|
||||||
|
</h3>
|
||||||
|
<span class="ml-auto"><strong>Balance:</strong> {{accountBalance}} RCU</span>
|
||||||
|
<span class="ml-2"><strong>Created:</strong> {{account?.date_registered | date}}</span>
|
||||||
|
<span class="ml-2"><strong>Address:</strong><a href="{{bloxbergLink}}" target="_blank"> {{account?.identities.evm['bloxberg:8996']}} </a></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-disbursement *ngIf="isDisbursing" (cancelDisbursmentEvent)="addTransfer()" [account]="account">
|
||||||
|
</app-disbursement>
|
||||||
<mat-card-title class="card-header">
|
<mat-card-title class="card-header">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
DETAILS
|
DETAILS
|
||||||
|
@ -3,7 +3,7 @@ import {MatTableDataSource} from '@angular/material/table';
|
|||||||
import {SelectionModel} from '@angular/cdk/collections';
|
import {SelectionModel} from '@angular/cdk/collections';
|
||||||
import {MatPaginator} from '@angular/material/paginator';
|
import {MatPaginator} from '@angular/material/paginator';
|
||||||
import {MatSort} from '@angular/material/sort';
|
import {MatSort} from '@angular/material/sort';
|
||||||
import {LocationService, TransactionService, UserService} from '@app/_services';
|
import {LocationService, TokenService, TransactionService, UserService} from '@app/_services';
|
||||||
import {ActivatedRoute, Params, Router} from '@angular/router';
|
import {ActivatedRoute, Params, Router} from '@angular/router';
|
||||||
import {first} from 'rxjs/operators';
|
import {first} from 'rxjs/operators';
|
||||||
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
||||||
@ -34,6 +34,7 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
|
|
||||||
accountInfoForm: FormGroup;
|
accountInfoForm: FormGroup;
|
||||||
account: any;
|
account: any;
|
||||||
|
accountBalance: number;
|
||||||
metaAccount: any;
|
metaAccount: any;
|
||||||
accounts: any[] = [];
|
accounts: any[] = [];
|
||||||
accountsType = 'all';
|
accountsType = 'all';
|
||||||
@ -57,7 +58,8 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
private transactionService: TransactionService,
|
private transactionService: TransactionService,
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
private tokenService: TokenService
|
||||||
) {
|
) {
|
||||||
this.accountInfoForm = this.formBuilder.group({
|
this.accountInfoForm = this.formBuilder.group({
|
||||||
status: ['', Validators.required],
|
status: ['', Validators.required],
|
||||||
@ -79,6 +81,7 @@ export class AccountDetailsComponent implements OnInit {
|
|||||||
this.userService.getAccountDetailsFromMeta(await User.toKey(params.get('id'))).pipe(first()).subscribe(res => {
|
this.userService.getAccountDetailsFromMeta(await User.toKey(params.get('id'))).pipe(first()).subscribe(res => {
|
||||||
this.metaAccount = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
this.metaAccount = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
||||||
this.account = this.metaAccount.m.data;
|
this.account = this.metaAccount.m.data;
|
||||||
|
this.tokenService.getTokenBalance(this.account.identities.evm['bloxberg:8996'][0]).then(r => this.accountBalance = r);
|
||||||
this.account.vcard = vCard.parse(atob(this.account.vcard));
|
this.account.vcard = vCard.parse(atob(this.account.vcard));
|
||||||
console.log(this.account);
|
console.log(this.account);
|
||||||
this.accountInfoForm.patchValue({
|
this.accountInfoForm.patchValue({
|
||||||
|
@ -14,27 +14,29 @@
|
|||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Sender: {{transaction.sender?.vcard.fn[0].value}}</span><br><br>
|
<span>Sender: {{transaction.sender?.vcard.fn[0].value}}</span><br><br>
|
||||||
<span>Sender Address: {{transaction.from}}</span><br><br>
|
<span>Sender Address: {{transaction.from}}</span><br><br>
|
||||||
<button mat-raised-button color="primary" class="btn btn-outline-info" routerLink="/accounts/1">View Sender</button>
|
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewSender()">View Sender</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Recipient: {{transaction.recipient?.vcard.fn[0].value}}</span><br><br>
|
<span>Recipient: {{transaction.recipient?.vcard.fn[0].value}}</span><br><br>
|
||||||
<span>Recipient Address: {{transaction.to}}</span><br><br>
|
<span>Recipient Address: {{transaction.to}}</span><br><br>
|
||||||
<button mat-raised-button color="primary" class="btn btn-outline-info" routerLink="/accounts/1">View Recipient</button>
|
<button mat-raised-button color="primary" class="btn btn-outline-info" (click)="viewRecipient()">View Recipient</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Amount: {{transaction.token.symbol + ' ' + transaction.value}}</span>
|
<span>Amount: SRF {{transaction.value | tokenRatio}}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h4 class="mt-2">Token: </h4>
|
<h4 class="mt-2">Token: </h4>
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Address: {{transaction.token.address}}</span>
|
<span>Address: {{transaction.token._address}}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Name: {{transaction.token.name}}</span>
|
<!-- <span>Name: {{transaction.token.name}}</span>-->
|
||||||
|
<span>Name: Sarafu Token</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<span>Symbol: {{transaction.token.symbol}}</span>
|
<!-- <span>Symbol: {{transaction.token.symbol}}</span>-->
|
||||||
|
<span>Symbol: SRF</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import {Component, Input, OnInit} from '@angular/core';
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
|
import {Router} from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-transaction-details',
|
selector: 'app-transaction-details',
|
||||||
@ -8,9 +9,16 @@ import {Component, Input, OnInit} from '@angular/core';
|
|||||||
export class TransactionDetailsComponent implements OnInit {
|
export class TransactionDetailsComponent implements OnInit {
|
||||||
@Input() transaction;
|
@Input() transaction;
|
||||||
|
|
||||||
constructor() { }
|
constructor(private router: Router) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewSender(): void {
|
||||||
|
this.router.navigateByUrl(`/accounts/${this.transaction.from}`).then();
|
||||||
|
}
|
||||||
|
|
||||||
|
viewRecipient(): void {
|
||||||
|
this.router.navigateByUrl(`/accounts/${this.transaction.to}`).then();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,82 +56,75 @@
|
|||||||
<mat-icon matSuffix>search</mat-icon>
|
<mat-icon matSuffix>search</mat-icon>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-table class="mat-elevation-z10" [dataSource]="transactionDataSource" matSort matSortActive="created"
|
<table mat-table class="mat-elevation-z10" [dataSource]="transactionDataSource" matSort matSortActive="created"
|
||||||
matSortDirection="desc" matSortDisableClear>
|
matSortDirection="desc" matSortDisableClear>
|
||||||
|
|
||||||
<ng-container matColumnDef="view">
|
|
||||||
<mat-header-cell *matHeaderCellDef> View </mat-header-cell>
|
|
||||||
<mat-cell *matCellDef="let transaction" (click)="viewTransaction(transaction)">
|
|
||||||
<i class="fa fa-eye"></i>
|
|
||||||
</mat-cell>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="sender">
|
<ng-container matColumnDef="sender">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Sender </mat-header-cell>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Sender </th>
|
||||||
<mat-cell *matCellDef="let transaction"> {{transaction.sender?.vcard.fn[0].value}} </mat-cell>
|
<td mat-cell *matCellDef="let transaction"> {{transaction?.sender?.vcard.fn[0].value}} </td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="senderLocation">
|
<!-- <ng-container matColumnDef="senderLocation">-->
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Sender Location </mat-header-cell>
|
<!-- <mat-header-cell *matHeaderCellDef mat-sort-header> Sender Location </mat-header-cell>-->
|
||||||
<mat-cell *matCellDef="let transaction"> {{transaction.sender?.location.area_name}} </mat-cell>
|
<!-- <mat-cell *matCellDef="let transaction"> {{transaction?.sender?.location.area_name}} </mat-cell>-->
|
||||||
</ng-container>
|
<!-- </ng-container>-->
|
||||||
|
|
||||||
<ng-container matColumnDef="recipient">
|
<ng-container matColumnDef="recipient">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Recipient </mat-header-cell>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Recipient </th>
|
||||||
<mat-cell *matCellDef="let transaction"> {{transaction.recipient?.vcard.fn[0].value}} </mat-cell>
|
<td mat-cell *matCellDef="let transaction"> {{transaction?.recipient?.vcard.fn[0].value}} </td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="recipientLocation">
|
<!-- <ng-container matColumnDef="recipientLocation">-->
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Recipient Location </mat-header-cell>
|
<!-- <mat-header-cell *matHeaderCellDef mat-sort-header> Recipient Location </mat-header-cell>-->
|
||||||
<mat-cell *matCellDef="let transaction"> {{transaction.recipient?.location.area_name}} </mat-cell>
|
<!-- <mat-cell *matCellDef="let transaction"> {{transaction?.recipient?.location.area_name}} </mat-cell>-->
|
||||||
</ng-container>
|
<!-- </ng-container>-->
|
||||||
|
|
||||||
<ng-container matColumnDef="token">
|
<!-- <ng-container matColumnDef="token">-->
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Token </mat-header-cell>
|
<!-- <mat-header-cell *matHeaderCellDef mat-sort-header> Token </mat-header-cell>-->
|
||||||
<mat-cell *matCellDef="let transaction">
|
<!-- <mat-cell *matCellDef="let transaction">-->
|
||||||
<span *ngIf="transaction.type == 'transaction'">{{transaction.token.name}}</span>
|
<!-- <span *ngIf="transaction.type == 'transaction'">{{transaction?.token.name}}</span>-->
|
||||||
<span *ngIf="transaction.type == 'conversion'">{{transaction.destinationToken.name}}</span>
|
<!-- <span *ngIf="transaction.type == 'conversion'">{{transaction?.destinationToken.name}}</span>-->
|
||||||
</mat-cell>
|
<!-- </mat-cell>-->
|
||||||
</ng-container>
|
<!-- </ng-container>-->
|
||||||
|
|
||||||
<ng-container matColumnDef="value">
|
<ng-container matColumnDef="value">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Value </mat-header-cell>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Value </th>
|
||||||
<mat-cell *matCellDef="let transaction">
|
<td mat-cell *matCellDef="let transaction">
|
||||||
<span *ngIf="transaction.type == 'transaction'">{{transaction.value | tokenRatio}}</span>
|
<span *ngIf="transaction.type == 'transaction'">{{transaction?.value | tokenRatio}}</span>
|
||||||
<span *ngIf="transaction.type == 'conversion'">{{transaction.toValue | tokenRatio}}</span>
|
<span *ngIf="transaction.type == 'conversion'">{{transaction?.toValue | tokenRatio}}</span>
|
||||||
</mat-cell>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="created">
|
<ng-container matColumnDef="created">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> Created </mat-header-cell>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> Created </th>
|
||||||
<mat-cell *matCellDef="let transaction"> {{transaction.tx.timestamp | date}} </mat-cell>
|
<td mat-cell *matCellDef="let transaction"> {{transaction?.tx.timestamp | date}} </td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="type">
|
<ng-container matColumnDef="type">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header> TYPE </mat-header-cell>
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> TYPE </th>
|
||||||
<mat-cell *matCellDef="let transaction">
|
<td mat-cell *matCellDef="let transaction">
|
||||||
<span class="badge badge-success badge-pill"> {{transaction.type}} </span>
|
<span class="badge badge-success badge-pill"> {{transaction?.type}} </span>
|
||||||
</mat-cell>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container matColumnDef="select">
|
<!-- <ng-container matColumnDef="select">-->
|
||||||
<mat-header-cell *matHeaderCellDef>
|
<!-- <mat-header-cell *matHeaderCellDef>-->
|
||||||
<mat-checkbox (change)="$event ? masterToggle(transactionSelection, transactionDataSource) : null"
|
<!-- <mat-checkbox (change)="$event ? masterToggle(transactionSelection, transactionDataSource) : null"-->
|
||||||
[checked]="transactionSelection.hasValue() && isAllSelected(transactionSelection, transactionDataSource)"
|
<!-- [checked]="transactionSelection.hasValue() && isAllSelected(transactionSelection, transactionDataSource)"-->
|
||||||
[indeterminate]="transactionSelection.hasValue() && !isAllSelected(transactionSelection, transactionDataSource)">
|
<!-- [indeterminate]="transactionSelection.hasValue() && !isAllSelected(transactionSelection, transactionDataSource)">-->
|
||||||
</mat-checkbox>
|
<!-- </mat-checkbox>-->
|
||||||
</mat-header-cell>
|
<!-- </mat-header-cell>-->
|
||||||
<mat-cell *matCellDef="let transaction">
|
<!-- <mat-cell *matCellDef="let transaction">-->
|
||||||
<mat-checkbox (click)="$event.stopPropagation()"
|
<!-- <mat-checkbox (click)="$event.stopPropagation()"-->
|
||||||
(change)="$event ? transactionSelection.toggle(transaction) : null"
|
<!-- (change)="$event ? transactionSelection.toggle(transaction) : null"-->
|
||||||
[checked]="transactionSelection.isSelected(transaction)">
|
<!-- [checked]="transactionSelection.isSelected(transaction)">-->
|
||||||
</mat-checkbox>
|
<!-- </mat-checkbox>-->
|
||||||
</mat-cell>
|
<!-- </mat-cell>-->
|
||||||
</ng-container>
|
<!-- </ng-container>-->
|
||||||
|
|
||||||
<mat-header-row *matHeaderRowDef="transactionDisplayedColumns"></mat-header-row>
|
<tr mat-header-row *matHeaderRowDef="transactionDisplayedColumns"></tr>
|
||||||
<mat-row *matRowDef="let transaction; columns: transactionDisplayedColumns" (click)="viewTransaction(transaction)"></mat-row>
|
<tr mat-row *matRowDef="let transaction; columns: transactionDisplayedColumns;" (click)="viewTransaction(transaction)"></tr>
|
||||||
</mat-table>
|
</table>
|
||||||
|
|
||||||
<mat-paginator [pageSize]="10" [pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
|
<mat-paginator [pageSize]="10" [pageSizeOptions]="[10, 20, 50, 100]" showFirstLastButtons></mat-paginator>
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import {MatSort} from '@angular/material/sort';
|
|||||||
})
|
})
|
||||||
export class TransactionsComponent implements OnInit, AfterViewInit {
|
export class TransactionsComponent implements OnInit, AfterViewInit {
|
||||||
transactionDataSource: MatTableDataSource<any>;
|
transactionDataSource: MatTableDataSource<any>;
|
||||||
transactionDisplayedColumns = ['view', 'sender', 'senderLocation', 'recipient', 'recipientLocation', 'token', 'value', 'created', 'type', 'select'];
|
transactionDisplayedColumns = ['sender', 'recipient', 'value', 'created', 'type'];
|
||||||
initialSelection = [];
|
initialSelection = [];
|
||||||
allowMultiSelect = true;
|
allowMultiSelect = true;
|
||||||
transactionSelection: SelectionModel<any>;
|
transactionSelection: SelectionModel<any>;
|
||||||
|
@ -16,6 +16,7 @@ import {MatButtonModule} from '@angular/material/button';
|
|||||||
import {MatIconModule} from '@angular/material/icon';
|
import {MatIconModule} from '@angular/material/icon';
|
||||||
import {MatSelectModule} from '@angular/material/select';
|
import {MatSelectModule} from '@angular/material/select';
|
||||||
import {MatCardModule} from '@angular/material/card';
|
import {MatCardModule} from '@angular/material/card';
|
||||||
|
import {MatRippleModule} from '@angular/material/core';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -23,21 +24,22 @@ import {MatCardModule} from '@angular/material/card';
|
|||||||
exports: [
|
exports: [
|
||||||
TransactionDetailsComponent
|
TransactionDetailsComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
TransactionsRoutingModule,
|
TransactionsRoutingModule,
|
||||||
DataTablesModule,
|
DataTablesModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatPaginatorModule,
|
MatPaginatorModule,
|
||||||
MatSortModule,
|
MatSortModule,
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatCardModule
|
MatCardModule,
|
||||||
]
|
MatRippleModule
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class TransactionsModule { }
|
export class TransactionsModule { }
|
||||||
|
@ -3,6 +3,6 @@ import {Pipe, PipeTransform} from '@angular/core';
|
|||||||
@Pipe({name: 'tokenRatio'})
|
@Pipe({name: 'tokenRatio'})
|
||||||
export class TokenRatioPipe implements PipeTransform {
|
export class TokenRatioPipe implements PipeTransform {
|
||||||
transform(value: any, ...args): any {
|
transform(value: any, ...args): any {
|
||||||
return Number(value) / Math.pow(10, 18);
|
return Number(value) / Math.pow(10, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<!-- Topbar Start -->
|
<!-- Topbar Start -->
|
||||||
<nav class="navbar navbar-expand-lg navbar-light bg-light sticky-top">
|
<nav class="navbar navbar-expand-lg navbar-light bg-light sticky-top">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<button type="button" id="sidebarCollapse" class="navbar-btn menutoggle" appMenuToggle>
|
<button type="button" id="sidebarCollapse" class="navbar-btn menutoggle" aria-label="Sidebar toggle" appMenuToggle>
|
||||||
<span></span>
|
<span></span>
|
||||||
<span></span>
|
<span></span>
|
||||||
<span></span>
|
<span></span>
|
||||||
|
1
src/assets/js/block-sync/data/RegistryClient.json
Normal file
1
src/assets/js/block-sync/data/RegistryClient.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"addressOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"entry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registryCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
|
@ -1,7 +1,7 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: true,
|
production: true,
|
||||||
bloxbergChainId: 8996,
|
bloxbergChainId: 8996,
|
||||||
cicAuthUrl: 'http://localhost:4444',
|
cicAuthUrl: 'http://localhost:8080',
|
||||||
cicMetaUrl: 'http://localhost:63380',
|
cicMetaUrl: 'http://localhost:63380',
|
||||||
publicKeysUrl: 'http://localhost:8000',
|
publicKeysUrl: 'http://localhost:8000',
|
||||||
cicCacheUrl: 'http://localhost:63313',
|
cicCacheUrl: 'http://localhost:63313',
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
bloxbergChainId: 8996,
|
bloxbergChainId: 8996,
|
||||||
cicAuthUrl: 'http://localhost:4444',
|
cicAuthUrl: 'http://localhost:8080',
|
||||||
cicMetaUrl: 'http://localhost:63380',
|
cicMetaUrl: 'http://localhost:63380',
|
||||||
publicKeysUrl: 'http://localhost:8000',
|
publicKeysUrl: 'http://localhost:8000',
|
||||||
cicCacheUrl: 'http://localhost:63313',
|
cicCacheUrl: 'http://localhost:63313',
|
||||||
|
@ -12,7 +12,7 @@ p {
|
|||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
line-height: 1.7em;
|
line-height: 1.7em;
|
||||||
color: #999;
|
color: #000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
a, a:hover, a:focus {
|
a, a:hover, a:focus {
|
||||||
@ -349,6 +349,10 @@ button {
|
|||||||
html, body { height: 100%; }
|
html, body { height: 100%; }
|
||||||
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
||||||
|
|
||||||
.full-width {
|
.full-width, table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
li.breadcrumb-item.active, footer.footer {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user