import { Injectable } from '@angular/core'; import {HttpClient} from '@angular/common/http'; import {first, map} from 'rxjs/operators'; import {BehaviorSubject, Observable} from 'rxjs'; import {environment} from '@src/environments/environment'; import {Envelope, User} from 'cic-client-meta'; import {UserService} from '@app/_services/user.service'; import { Keccak } from 'sha3'; import { utils } from 'ethers'; import {add0x, fromHex, strip0x, toHex} from '@src/assets/js/ethtx/dist/hex'; import {Tx} from '@src/assets/js/ethtx/dist'; import {toValue} from '@src/assets/js/ethtx/dist/tx'; import * as secp256k1 from 'secp256k1'; import {AuthService} from '@app/_services/auth.service'; import {Registry} from '@app/_helpers'; const Web3 = require('web3'); const vCard = require('vcard-parser'); @Injectable({ providedIn: 'root' }) export class TransactionService { transactions: any[] = []; private transactionList = new BehaviorSubject(this.transactions); transactionsSubject = this.transactionList.asObservable(); userInfo: any; web3 = new Web3(environment.web3Provider); registry = new Registry(environment.registryAddress); constructor( private http: HttpClient, private authService: AuthService, private userService: UserService ) { } getAllTransactions(offset: number, limit: number): Observable { return this.http.get(`${environment.cicCacheUrl}/tx/${offset}/${limit}`) .pipe(map(response => { return response; })); } getAddressTransactions(address: string, offset: number, limit: number): Observable { return this.http.get(`${environment.cicCacheUrl}/tx/${address}/${offset}/${limit}`) .pipe(map(response => { return response; })); } async setTransaction(transaction, cacheSize: number): Promise { const cachedTransaction = this.transactions.find(cachedTx => cachedTx.tx.txHash === transaction.tx.txHash); if (cachedTransaction) { return; } transaction.type = 'transaction'; transaction.sender = await this.getUser(transaction.from); transaction.recipient = await this.getUser(transaction.to); await this.addTransaction(transaction, cacheSize); } async setConversion(conversion, cacheSize): Promise { const cachedConversion = this.transactions.find(cachedTx => cachedTx.tx.txHash === conversion.tx.txHash); if (cachedConversion) { return; } conversion.type = 'conversion'; conversion.sender = conversion.recipient = await this.getUser(conversion.trader); await this.addTransaction(conversion, cacheSize); } async addTransaction(transaction, cacheSize: number): Promise { this.transactions.unshift(transaction); if (this.transactions.length > cacheSize) { this.transactions.length = cacheSize; } this.transactionList.next(this.transactions); } async getUser(address: string): Promise { return this.userService.getAccountDetailsFromMeta(await User.toKey(address)).pipe(first()).subscribe(res => { const account = Envelope.fromJSON(JSON.stringify(res)).unwrap(); const accountInfo = account.m.data; accountInfo.vcard = vCard.parse(atob(accountInfo.vcard)); this.userInfo = accountInfo; return accountInfo; }); } async transferRequest(tokenAddress: string, senderAddress: string, recipientAddress: string, value: number): Promise { const transferAuthAddress = await this.registry.addressOf('TransferAuthorization'); const hashFunction = new Keccak(256); hashFunction.update('createRequest(address,address,address,uint256)'); const hash = hashFunction.digest(); const methodSignature = hash.toString('hex').substring(0, 8); const abiCoder = new utils.AbiCoder(); const abi = await abiCoder.encode(['address', 'address', 'address', 'uint256'], [senderAddress, recipientAddress, tokenAddress, value]); const data = fromHex(methodSignature + strip0x(abi)); const tx = new Tx(environment.bloxbergChainId); tx.nonce = await this.web3.eth.getTransactionCount(senderAddress); tx.gasPrice = await this.web3.eth.getGasPrice(); tx.gasLimit = 8000000; tx.to = fromHex(strip0x(transferAuthAddress)); tx.value = toValue(value); tx.data = data; const txMsg = tx.message(); const privateKey = this.authService.mutableKeyStore.getPrivateKey(); if (!privateKey.isDecrypted()) { const password = window.prompt('password'); await privateKey.decrypt(password); } const signatureObject = secp256k1.ecdsaSign(txMsg, privateKey.keyPacket.privateParams.d); const r = signatureObject.signature.slice(0, 32); const s = signatureObject.signature.slice(32); const v = signatureObject.recid; tx.setSignature(r, s, v); const txWire = add0x(toHex(tx.serializeRLP())); const result = await this.web3.eth.sendSignedTransaction(txWire); console.log('Result', result); const transaction = await this.web3.eth.getTransaction(result.transactionHash); console.log('Transaction', transaction); } }