From 5033871cfb38300cbc182c2f4546f93cebebd651 Mon Sep 17 00:00:00 2001 From: Murat Baybosunov Date: Mon, 28 Oct 2019 20:47:14 +0600 Subject: [PATCH 01/10] metamask wip 1 --- .../interactor/interactor.component.ts | 14 +- front/src/app/guards/wallet.guard.ts | 8 +- .../wallet-account.component.html | 8 +- .../wallet-account.component.ts | 18 +- .../wallet-main/wallet-main.component.html | 102 ++++-- .../wallet-main/wallet-main.component.ts | 10 + front/src/app/services/common.service.ts | 10 +- front/src/app/services/wallet.service.ts | 320 ++++++++++++------ 8 files changed, 336 insertions(+), 154 deletions(-) diff --git a/front/src/app/components/interactor/interactor.component.ts b/front/src/app/components/interactor/interactor.component.ts index a8bb82b9..65ac9187 100644 --- a/front/src/app/components/interactor/interactor.component.ts +++ b/front/src/app/components/interactor/interactor.component.ts @@ -48,7 +48,7 @@ export class InteractorComponent implements OnInit { contract: Web3Contract; abiFunctions: AbiItem[]; selectedFunction: AbiItem; - functionResult: {output:any[][], error: string}; + functionResult: { output: any[][], error: string }; addr: Address; hasData = false; @@ -101,7 +101,7 @@ export class InteractorComponent implements OnInit { this._subsArr$.push(this.form.get('contractAddress').valueChanges.pipe( debounceTime(500), distinctUntilChanged(), - ).subscribe(val => { + ).subscribe((val: string) => { this.updateContract(); this.getContractData(val); })); @@ -117,7 +117,7 @@ export class InteractorComponent implements OnInit { this._subsArr$.push((this.form.get('functionParameters') as FormArray).valueChanges.pipe( debounceTime(1200), distinctUntilChanged(), - ).subscribe((values) => { + ).subscribe((values: string[]) => { this.estimateFunctionGas(values); })); this._subsArr$.push(this.form.get('erc').valueChanges.subscribe(value => { @@ -176,12 +176,12 @@ export class InteractorComponent implements OnInit { callABIFunction(func: AbiItem, params: string[] = []): void { this._walletService.call(this.contract.options.address, func, params).subscribe((decoded: object) => { if (!decoded) { - this.functionResult = {error:'Result is empty', output:null}; + this.functionResult = {error: 'Result is empty', output: null}; return; } - this.functionResult = {output:getDecodedData(decoded, func, this.addr), error: null}; + this.functionResult = {output: getDecodedData(decoded, func, this.addr), error: null}; }, err => { - this.functionResult = {error:err, output:null}; + this.functionResult = {error: err, output: null}; }); } @@ -301,7 +301,7 @@ export class InteractorComponent implements OnInit { this.abiFunctions = getAbiMethods(abiItems); }, err => { this._toastrService.danger('Can\'t initiate contract, check entered data'); - console.error(`Failed to initiate contract (${addrHash}): ${err}`) + console.error(`Failed to initiate contract (${addrHash}): ${err}`); }); } diff --git a/front/src/app/guards/wallet.guard.ts b/front/src/app/guards/wallet.guard.ts index ea9c7010..75d34332 100644 --- a/front/src/app/guards/wallet.guard.ts +++ b/front/src/app/guards/wallet.guard.ts @@ -3,6 +3,7 @@ import {Injectable} from '@angular/core'; import {CanActivate, Router} from '@angular/router'; /*SERVICES*/ import {WalletService} from '../services/wallet.service'; +import {Observable} from 'rxjs'; @Injectable({ providedIn: 'root' @@ -14,11 +15,12 @@ export class WalletGuard implements CanActivate { ) { } - canActivate(): boolean { - if (!this._walletService.account) { + canActivate(): Observable { + return this._walletService.logged$; + /*if (!this._walletService.account) { this._router.navigate(['wallet']); return false; } - return true; + return true;*/ } } diff --git a/front/src/app/scenes/wallet-account/wallet-account.component.html b/front/src/app/scenes/wallet-account/wallet-account.component.html index 86939f55..862692e2 100644 --- a/front/src/app/scenes/wallet-account/wallet-account.component.html +++ b/front/src/app/scenes/wallet-account/wallet-account.component.html @@ -1,8 +1,8 @@ -
+
Account ACCOUNT
-

Address: {{walletService.account.address}}

+

Address: {{walletService.accountAddress$ | async}}

Balance (GO): {{walletService.accountBalance | number}}

- +
+
+ +
+
+ +
+
-
+ + + + +
+
+ + + Use metamask + + +
+ It seems that you have metamask installed but GoChain is not configured, please use the following + guide to configure it. +
+
+
+ + To use wallet without private key, please install or enable + MetaMask + and + + configure it to work with Gochain + + +
diff --git a/front/src/app/scenes/wallet-main/wallet-main.component.ts b/front/src/app/scenes/wallet-main/wallet-main.component.ts index 1e6c371e..b9e4311a 100644 --- a/front/src/app/scenes/wallet-main/wallet-main.component.ts +++ b/front/src/app/scenes/wallet-main/wallet-main.component.ts @@ -10,6 +10,8 @@ import {WalletService} from '../../services/wallet.service'; import {PasswordField} from '../../models/password-field.model'; /*UTILS*/ import {META_TITLES} from '../../utils/constants'; +import {LayoutService} from '../../services/layout.service'; +import {filter, flatMap} from 'rxjs/operators'; @Component({ selector: 'app-wallet-main', @@ -42,11 +44,19 @@ export class WalletMainComponent implements OnInit { private _fb: FormBuilder, private _toastrService: ToastrService, private _router: Router, + private _layoutService: LayoutService, ) { } ngOnInit() { + /*this._layoutService.onLoading();*/ this._metaService.setTitle(META_TITLES.WALLET.title); + this.walletService.metamaskConfigured$.pipe( + filter(v => !!v), + flatMap(() => this.walletService.openAccount()), + ).subscribe((v) => { + this._router.navigate(['/wallet/account']); + }); } onPrivateKeySubmit() { diff --git a/front/src/app/services/common.service.ts b/front/src/app/services/common.service.ts index 3d9d77ee..75850631 100644 --- a/front/src/app/services/common.service.ts +++ b/front/src/app/services/common.service.ts @@ -17,11 +17,11 @@ import {Stats} from '../models/stats.model'; import {Contract} from '../models/contract.model'; import {SignerData, SignerStat} from '../models/signer-stats'; import {SignerNode} from '../models/signer-node'; +import {AbiItem} from 'web3-utils'; /*UTILS*/ import {ContractAbi, ContractEventsAbi, ContractAbiByID, AbiItemIDed} from '../utils/types'; import {FunctionName} from '../utils/enums'; import {objIsEmpty} from '../utils/functions'; -import {AbiItem} from 'web3-utils'; @Injectable() export class CommonService implements Resolve { @@ -36,7 +36,7 @@ export class CommonService implements Resolve { }); } return this._rpcProvider$.pipe( - filter(v => !!v), + filter(v => !!v), take(1), ); } @@ -47,7 +47,7 @@ export class CommonService implements Resolve { this.initAbi(); } return this._abi$.pipe( - filter(v => v !== null), + filter(v => v !== null), take(1), ); } @@ -58,7 +58,7 @@ export class CommonService implements Resolve { this.initAbi(); } return this._abiByID$.pipe( - filter(v => v !== null), + filter(v => v !== null), take(1), ); } @@ -72,7 +72,7 @@ export class CommonService implements Resolve { }); } return this._eventsAbi$.pipe( - filter(v => v !== null), + filter(v => v !== null), take(1), ); } diff --git a/front/src/app/services/wallet.service.ts b/front/src/app/services/wallet.service.ts index ba679ff3..19c69f3d 100644 --- a/front/src/app/services/wallet.service.ts +++ b/front/src/app/services/wallet.service.ts @@ -1,14 +1,14 @@ /*CORE*/ import {Injectable} from '@angular/core'; import {Router} from '@angular/router'; -import {BehaviorSubject, forkJoin, Observable, of} from 'rxjs'; -import {concatMap, filter, map, take, finalize, catchError, mergeMap} from 'rxjs/operators'; -import {fromPromise} from 'rxjs/internal-compatibility'; +import {BehaviorSubject, forkJoin, Observable, of, throwError} from 'rxjs'; +import {concatMap, filter, map, take, finalize, catchError, mergeMap, flatMap, tap} from 'rxjs/operators'; +import {fromPromise, tryCatch} from 'rxjs/internal-compatibility'; /*WEB3*/ import Web3 from 'web3'; -import {SignedTransaction, Transaction as Web3Tx, TransactionConfig, TransactionReceipt} from 'web3-core'; +import {RLPEncodedTransaction, SignedTransaction, Transaction as Web3Tx, TransactionConfig, TransactionReceipt} from 'web3-core'; import {Account} from 'web3-eth-accounts'; -import {AbiItem, fromWei, toWei, isAddress} from 'web3-utils'; +import {AbiItem, fromWei, toWei, isAddress, AbiOutput} from 'web3-utils'; /*SERVICES*/ import {ToastrService} from '../modules/toastr/toastr.service'; import {CommonService} from './common.service'; @@ -17,30 +17,116 @@ import {Transaction} from '../models/transaction.model'; /*UTILS*/ import {objIsEmpty} from '../utils/functions'; +interface IWallet { + w3: Web3; + + logged$: BehaviorSubject; + + send(tx: TransactionConfig): Observable; + + call(tx: TransactionConfig): Observable; + + logIn(privateKey: string): Observable; +} + +abstract class Wallet { + w3: Web3; + logged$: BehaviorSubject = new BehaviorSubject(null); + + constructor(w3: Web3) { + this.w3 = w3; + } +} + +class MetamaskStrategy extends Wallet implements IWallet { + + send(tx: TransactionConfig): Observable { + return fromPromise(this.w3.eth.sendTransaction(tx)); + } + + call(tx: TransactionConfig): Observable { + return fromPromise(this.w3.eth.call(tx)); + } + + logIn(): Observable { + try { + (window as any).ethereum.enable(); + return fromPromise(this.w3.eth.getAccounts()).pipe( + map((v: string[]) => v[0]), + ); + } catch (e) { + return throwError('Access not granted'); + } + } +} + +class PrivateKeyStrategy extends Wallet implements IWallet { + private privateKey: string; + private account: Account; + + send(tx: TransactionConfig): Observable { + return fromPromise(this.w3.eth.signTransaction(tx)).pipe( + flatMap((signedTx: RLPEncodedTransaction) => fromPromise(this.w3.eth.sendSignedTransaction(signedTx.raw))), + ); + } + + call(tx: TransactionConfig): Observable { + return fromPromise(this.w3.eth.call(tx)); + } + + logIn(privateKey: string): Observable { + if (privateKey.length === 64 && privateKey.indexOf('0x') !== 0) { + privateKey = '0x' + privateKey; + } + if (privateKey.length === 66) { + this.account = this.w3.eth.accounts.privateKeyToAccount(privateKey); + this.logged$.next(true); + return of(this.account.address); + } + return throwError('Given private key is not valid'); + } +} + @Injectable() export class WalletService { isProcessing = false; // ACCOUNT INFO account: Account; + accountAddress: string; + accountAddress$: BehaviorSubject = new BehaviorSubject(null); accountBalance: string; receipt: TransactionReceipt; + metamaskIntalled$: BehaviorSubject = new BehaviorSubject(false); + metamaskConfigured$: BehaviorSubject = new BehaviorSubject(false); + logged$: BehaviorSubject = new BehaviorSubject(false); + + private _ready$: BehaviorSubject = new BehaviorSubject(false); + get ready$(): Observable { + return this._ready$.pipe( + filter(v => !!v), + take(1), + ); + } + private _web3Callable$: BehaviorSubject = new BehaviorSubject(null); - private _web3Payable$: BehaviorSubject = new BehaviorSubject(null); + private _web3Metamask$: BehaviorSubject = new BehaviorSubject(null); + + private providerContext: IWallet; get w3Call(): Observable { return this._web3Callable$.pipe( - filter(v => !!v), - take(1), + filter(v => !!v), + take(1), ); } get w3Pay(): Observable { - return this._web3Payable$.pipe( - filter(v => !!v), - take(1), + return this._web3Metamask$.pipe( + filter(v => !!v), + take(1), ); } @@ -49,45 +135,57 @@ export class WalletService { private _commonService: CommonService, private _router: Router, ) { - this._commonService.rpcProvider$ - .pipe( - filter(value => !!value), - ) - .subscribe((rpcProvider: string) => { - const metaMaskProvider = new Web3(Web3.givenProvider, null, {transactionConfirmationBlocks: 1,}); - const web3Provider = new Web3(new Web3.providers.HttpProvider(rpcProvider), null, {transactionConfirmationBlocks: 1,}); - this._web3Callable$.next(web3Provider); - if (!metaMaskProvider.currentProvider) { - this._web3Payable$.error('Metamask is not enabled'); + this._commonService.rpcProvider$.subscribe((rpcProvider: string) => { + this.initProvider(rpcProvider); + }); + } + + initProvider(rpcProvider: string): void { + const metaMaskProvider = new Web3(Web3.givenProvider, null, {transactionConfirmationBlocks: 1}); + const web3Provider = new Web3(new Web3.providers.HttpProvider(rpcProvider), null, {transactionConfirmationBlocks: 1}); + this._web3Callable$.next(web3Provider); + this.providerContext = new PrivateKeyStrategy(web3Provider); + if (!metaMaskProvider.currentProvider) { + this._web3Metamask$.error('Metamask is not installed/enabled'); + this.metamaskIntalled$.next(false); + this.metamaskConfigured$.next(false); + return; + } + web3Provider.eth.net.getId((web3err, web3NetID) => { + if (web3err) { + this._toastrService.danger('Metamask is enabled but can\'t get network id'); + this._web3Metamask$.error(`Failed to get network id: ${web3err}`); + this.metamaskIntalled$.next(true); + this.metamaskConfigured$.next(false); + this._ready$.next(true); + return; + } + metaMaskProvider.eth.net.getId((metamaskErr, metamask3NetID) => { + if (metamaskErr) { + this._toastrService.danger('Metamask is enabled but can\'t get network id from Metamask'); + this._web3Metamask$.error(`Failed to Metamask network id: ${metamaskErr}`); + this.metamaskIntalled$.next(true); + this.metamaskConfigured$.next(false); + this._ready$.next(true); return; } - web3Provider.eth.net.getId((err, web3NetID) => { - if (err) { - this._toastrService.danger('Metamask is enabled but can\'t get network id'); - this._web3Payable$.error(`Failed to get network id: ${err}`); - return; - } - metaMaskProvider.eth.net.getId((err, metamask3NetID) => { - if (err) { - this._toastrService.danger('Metamask is enabled but can\'t get network id from Metamask'); - this._web3Payable$.error(`Failed to Metamask network id: ${err}`); - return; - } - if (web3NetID !== metamask3NetID) { - this._toastrService.danger('Metamask is enabled but networks are different'); - this._web3Payable$.error(`Metamask network ID (${metamask3NetID}) doesn't match expected (${web3NetID})`); - return; - } - this._web3Payable$.next(web3Provider); - }); - }); + if (web3NetID !== metamask3NetID) { + this._toastrService.warning('Metamask is enabled but networks are different'); + this._web3Metamask$.error(`Metamask network ID (${metamask3NetID}) doesn't match expected (${web3NetID})`); + this.metamaskIntalled$.next(true); + this.metamaskConfigured$.next(false); + this._ready$.next(true); + return; + } + console.log('connecting metamask'); + this._web3Metamask$.next(web3Provider); + this.providerContext = new MetamaskStrategy(metaMaskProvider); + this.metamaskIntalled$.next(true); + this.metamaskConfigured$.next(true); + this.logged$.next(true); + this._ready$.next(true); }); - } - - sendSignedTx(signed: SignedTransaction): Observable { - return this.w3Pay.pipe(concatMap((web3: Web3) => { - return fromPromise(web3.eth.sendSignedTransaction(signed.rawTransaction)); - })) + }); } /** @@ -105,9 +203,10 @@ export class WalletService { return fromPromise(web3.eth.call({ to: addr, data: encoded, - })) - }),map((res: string) => { - if (!res || res==='0x' || res==='0X') { + })); + }), + map((res: string) => { + if (!res || res === '0x' || res === '0X') { return null; } const decoded: object = web3.eth.abi.decodeParameters(abi.outputs, res); @@ -129,33 +228,33 @@ export class WalletService { fromPromise(web3.eth.getTransaction(txHash)), fromPromise(web3.eth.getTransactionReceipt(txHash)), ]).pipe( - map((res: [Web3Tx, TransactionReceipt]) => { - if (!res[0]) { - return null; - } - const tx: Web3Tx = res[0]; - const txReceipt = res[1]; - const finalTx: Transaction = new Transaction(); - finalTx.tx_hash = tx.hash; - finalTx.value = tx.value; - finalTx.gas_price = tx.gasPrice; - finalTx.gas_limit = '' + tx.gas; - finalTx.nonce = tx.nonce; - finalTx.input_data = tx.input.replace(/^0x/, ''); - finalTx.from = tx.from; - finalTx.to = tx.to; - if (txReceipt) { - finalTx.block_number = tx.blockNumber; - finalTx.gas_fee = '' + (+tx.gasPrice * txReceipt.gasUsed); - finalTx.contract_address = - (txReceipt.contractAddress && txReceipt.contractAddress !== '0x0000000000000000000000000000000000000000') - ? txReceipt.contractAddress - : null; - finalTx.status = txReceipt.status; - finalTx.created_at = new Date(); - } - return finalTx; - }), + map((res: [Web3Tx, TransactionReceipt]) => { + if (!res[0]) { + return null; + } + const tx: Web3Tx = res[0]; + const txReceipt = res[1]; + const finalTx: Transaction = new Transaction(); + finalTx.tx_hash = tx.hash; + finalTx.value = tx.value; + finalTx.gas_price = tx.gasPrice; + finalTx.gas_limit = '' + tx.gas; + finalTx.nonce = tx.nonce; + finalTx.input_data = tx.input.replace(/^0x/, ''); + finalTx.from = tx.from; + finalTx.to = tx.to; + if (txReceipt) { + finalTx.block_number = tx.blockNumber; + finalTx.gas_fee = '' + (+tx.gasPrice * txReceipt.gasUsed); + finalTx.contract_address = + (txReceipt.contractAddress && txReceipt.contractAddress !== '0x0000000000000000000000000000000000000000') + ? txReceipt.contractAddress + : null; + finalTx.status = txReceipt.status; + finalTx.created_at = new Date(); + } + return finalTx; + }), ); })); } @@ -176,6 +275,7 @@ export class WalletService { */ sendGo(to: string, value: string, gas: string): void { if (this.isProcessing) { + this._toastrService.warning('another process in action'); return; } @@ -192,6 +292,7 @@ export class WalletService { } const tx: TransactionConfig = { + from: this.accountAddress, to, value, gas @@ -215,6 +316,7 @@ export class WalletService { } const tx: TransactionConfig = { + from: this.accountAddress, data: byteCode, gas }; @@ -228,17 +330,26 @@ export class WalletService { */ sendTx(tx: TransactionConfig): void { this.isProcessing = true; - this.w3Pay.subscribe((web3: Web3) => { + this.ready$.pipe( + flatMap(() => this.providerContext.send(tx)) + ).subscribe((receipt: TransactionReceipt) => { + this.receipt = receipt; + this.getBalance(); + }, (err) => { + this._toastrService.danger(err); + this.resetProcessing(); + }); + /*this.w3Pay.subscribe((web3: Web3) => { const p: Promise = web3.eth.getTransactionCount(this.account.address); fromPromise(p).pipe( - concatMap(nonce => { - tx.nonce = nonce; - const p2: Promise = web3.eth.accounts.signTransaction(tx, this.account.privateKey); - return fromPromise(p2); - }), - concatMap((signed: SignedTransaction) => { - return this.sendSignedTx(signed); - }) + concatMap(nonce => { + tx.nonce = nonce; + const p2: Promise = web3.eth.accounts.signTransaction(tx, this.account.privateKey); + return fromPromise(p2); + }), + concatMap((signed: SignedTransaction) => { + return this.sendSignedTx(signed); + }) ).subscribe((receipt: TransactionReceipt) => { this.receipt = receipt; this.getBalance(); @@ -246,7 +357,7 @@ export class WalletService { this._toastrService.danger(err); this.resetProcessing(); }); - }); + });*/ } resetProcessing(): void { @@ -257,45 +368,60 @@ export class WalletService { // ACCOUNT METHODS createAccount(): Observable { - return this.w3Pay.pipe(map((web3: Web3) => { + return this.w3Call.pipe(map((web3: Web3) => { return web3.eth.accounts.create(); })); } - openAccount(privateKey: string): Observable { + openAccount(privateKey: string = null): Observable { this.isProcessing = true; - if (privateKey.length === 64 && privateKey.indexOf('0x') !== 0) { + return this.ready$.pipe( + flatMap(() => this.providerContext.logIn(privateKey)), catchError(err => { + this._toastrService.danger(err); + return of(null); + }), + tap((accountAddress: string) => { + this.accountAddress = accountAddress; + this.accountAddress$.next(accountAddress); + this.isProcessing = false; + this.getBalance(); + }), + ); + /*if (privateKey.length === 64 && privateKey.indexOf('0x') !== 0) { privateKey = '0x' + privateKey; } if (privateKey.length === 66) { return this.w3Call.pipe(map((web3: Web3) => { this.account = web3.eth.accounts.privateKeyToAccount(privateKey); + this.accountAddress = this.account.address; + this.logged$.next(true); this.getBalance(); return true; }), catchError(err => { this._toastrService.danger(err); return of(false); - }), finalize(()=> this.isProcessing = false )); + }), finalize(() => this.isProcessing = false)); } this.isProcessing = false; this._toastrService.danger('Given private key is not valid'); - return of(false); + return of(false);*/ } closeAccount(): void { this.account = null; this.accountBalance = null; + this.accountAddress = null; this._router.navigate(['wallet']); } getBalance() { this.w3Call.pipe(concatMap((web3: Web3) => { - return fromPromise(web3.eth.getBalance(this.account.address)); + return fromPromise(web3.eth.getBalance(this.accountAddress)); })).subscribe((balance: string) => { - this._toastrService.info('Updated balance.'); - this.accountBalance = fromWei(balance, 'ether').toString(); - }, err => { - this._toastrService.danger(err); + this._toastrService.info('Updated balance.'); + this.accountBalance = fromWei(balance, 'ether').toString(); + }, err => { + this._toastrService.danger(err); }); } } From 81e544895486538063c302868c199ec130d7b79d Mon Sep 17 00:00:00 2001 From: Murat Baybosunov Date: Wed, 30 Oct 2019 17:14:38 +0600 Subject: [PATCH 02/10] metamask wip 2 --- front/src/app/app.component.html | 2 +- front/src/app/app.component.spec.ts | 6 - front/src/app/app.component.ts | 17 +- .../interactor/interactor.component.html | 2 +- .../interactor/interactor.component.ts | 34 ++- front/src/app/guards/wallet.guard.ts | 18 +- .../contracts/contracts.component.spec.ts | 10 +- .../transaction/transaction.component.ts | 15 +- .../wallet-account.component.html | 2 +- .../wallet-create.component.html | 2 +- .../wallet-create/wallet-create.component.ts | 8 +- .../wallet-main/wallet-main.component.html | 39 +-- .../wallet-main/wallet-main.component.ts | 28 +- front/src/app/services/layout.service.ts | 8 +- front/src/app/services/wallet.service.ts | 286 ++++++++---------- 15 files changed, 204 insertions(+), 273 deletions(-) diff --git a/front/src/app/app.component.html b/front/src/app/app.component.html index 2ec51955..fa97d33a 100644 --- a/front/src/app/app.component.html +++ b/front/src/app/app.component.html @@ -1,7 +1,7 @@ -
+
Loading
diff --git a/front/src/app/app.component.spec.ts b/front/src/app/app.component.spec.ts index 3049b0e3..df74344b 100644 --- a/front/src/app/app.component.spec.ts +++ b/front/src/app/app.component.spec.ts @@ -34,10 +34,4 @@ describe('AppComponent', () => { it('should create the app', async(() => { expect(comp).toBeTruthy(); })); - /** - * DEFAULT VALUES - */ - it(`should have as isPageLoading 'false'`, async(() => { - expect(comp.isPageLoading).toEqual(false); - })); }); diff --git a/front/src/app/app.component.ts b/front/src/app/app.component.ts index 93a1cbef..b2475149 100644 --- a/front/src/app/app.component.ts +++ b/front/src/app/app.component.ts @@ -9,20 +9,7 @@ import { Subscription } from 'rxjs'; styleUrls: ['./app.component.scss'] }) @AutoUnsubscribe('_subsArr$') -export class AppComponent implements OnInit { - isPageLoading = false; - - private _subsArr$: Subscription[] = []; - - constructor(private _layoutService: LayoutService, private _cdr: ChangeDetectorRef) { - } - - ngOnInit() { - this._subsArr$.push( - this._layoutService.isPageLoading.subscribe((state: boolean) => { - this.isPageLoading = state; - this._cdr.detectChanges(); - }) - ); +export class AppComponent { + constructor(private _layoutService: LayoutService) { } } diff --git a/front/src/app/components/interactor/interactor.component.html b/front/src/app/components/interactor/interactor.component.html index a742cf30..53640582 100644 --- a/front/src/app/components/interactor/interactor.component.html +++ b/front/src/app/components/interactor/interactor.component.html @@ -53,7 +53,7 @@
Interact with a Smart - +
-

NOTE: Once you leave this page, you cannot recover the address or private key.

+

NOTE: Once you leaonCopyve this page, you cannot recover the address or private key.

Please copy this somewhere safe!

diff --git a/front/src/app/scenes/wallet-create/wallet-create.component.ts b/front/src/app/scenes/wallet-create/wallet-create.component.ts index 9c73c0ea..bccaec73 100644 --- a/front/src/app/scenes/wallet-create/wallet-create.component.ts +++ b/front/src/app/scenes/wallet-create/wallet-create.component.ts @@ -31,7 +31,7 @@ export class WalletCreateComponent implements OnInit { private _toastrService: ToastrService, private _clipboardService: ClipboardService, ) { - this._clipboardService.configure({ cleanUpAfterCopy: true }); + this._clipboardService.configure({cleanUpAfterCopy: true}); } ngOnInit(): void { @@ -42,10 +42,8 @@ export class WalletCreateComponent implements OnInit { } useWallet(): void { - this._walletService.openAccount(this.account.privateKey).subscribe((ok: boolean) => { - if (ok) { - this._router.navigate(['/wallet/account']); - } + this._walletService.openAccount(this.account.privateKey).subscribe(() => { + this._router.navigate(['/wallet/account']); }); } diff --git a/front/src/app/scenes/wallet-main/wallet-main.component.html b/front/src/app/scenes/wallet-main/wallet-main.component.html index 42f3999f..85f4a9cd 100644 --- a/front/src/app/scenes/wallet-main/wallet-main.component.html +++ b/front/src/app/scenes/wallet-main/wallet-main.component.html @@ -65,42 +65,13 @@
- - - - -
+
- - Use metamask - - -
- It seems that you have metamask installed but GoChain is not configured, please use the following - guide to configure it. -
-
+
+ It seems that you have metamask installed but GoChain is not configured, please use the following + guide to configure it. +
To use wallet without private key, please install or enable diff --git a/front/src/app/scenes/wallet-main/wallet-main.component.ts b/front/src/app/scenes/wallet-main/wallet-main.component.ts index b9e4311a..a22e2c51 100644 --- a/front/src/app/scenes/wallet-main/wallet-main.component.ts +++ b/front/src/app/scenes/wallet-main/wallet-main.component.ts @@ -49,22 +49,34 @@ export class WalletMainComponent implements OnInit { } ngOnInit() { - /*this._layoutService.onLoading();*/ + this._layoutService.onLoading(); this._metaService.setTitle(META_TITLES.WALLET.title); this.walletService.metamaskConfigured$.pipe( - filter(v => !!v), + filter((v: boolean) => { + if (!v) { + this._layoutService.offLoading(); + } + return v; + }), flatMap(() => this.walletService.openAccount()), - ).subscribe((v) => { + ).subscribe(() => { + this._layoutService.offLoading(); this._router.navigate(['/wallet/account']); + }, (err) => { + this._toastrService.danger(err); + this._layoutService.offLoading(); }); } onPrivateKeySubmit() { const privateKey: string = this.privateKeyForm.get('privateKey').value; - this.walletService.openAccount(privateKey).subscribe((ok: boolean) => { - if (ok) { - this._router.navigate(['/wallet/account']); - } - }); + if (!privateKey) { + this._toastrService.danger('Please enter private key'); + return; + } + this.walletService.openAccount(privateKey).subscribe( + () => this._router.navigate(['/wallet/account']), + (err) => this._toastrService.danger(err), + ); } } diff --git a/front/src/app/services/layout.service.ts b/front/src/app/services/layout.service.ts index a18610a3..f5ac7ded 100644 --- a/front/src/app/services/layout.service.ts +++ b/front/src/app/services/layout.service.ts @@ -11,7 +11,7 @@ import {ThemeColor} from '../utils/enums'; providedIn: 'root', }) export class LayoutService { - isPageLoading: BehaviorSubject = new BehaviorSubject(false); + isPageLoading$: BehaviorSubject = new BehaviorSubject(false); themeColor$: BehaviorSubject = new BehaviorSubject(ThemeColor.LIGHT); themeSettings: ThemeSettings; mobileMenuState: BehaviorSubject = new BehaviorSubject(false); @@ -30,14 +30,14 @@ export class LayoutService { } toggleLoading() { - this.isPageLoading.next(!this.isPageLoading.value); + this.isPageLoading$.next(!this.isPageLoading$.value); } onLoading() { - this.isPageLoading.next(true); + this.isPageLoading$.next(true); } offLoading() { - this.isPageLoading.next(false); + this.isPageLoading$.next(false); } } diff --git a/front/src/app/services/wallet.service.ts b/front/src/app/services/wallet.service.ts index 19c69f3d..33762c51 100644 --- a/front/src/app/services/wallet.service.ts +++ b/front/src/app/services/wallet.service.ts @@ -2,13 +2,14 @@ import {Injectable} from '@angular/core'; import {Router} from '@angular/router'; import {BehaviorSubject, forkJoin, Observable, of, throwError} from 'rxjs'; -import {concatMap, filter, map, take, finalize, catchError, mergeMap, flatMap, tap} from 'rxjs/operators'; -import {fromPromise, tryCatch} from 'rxjs/internal-compatibility'; +import {catchError, concatMap, filter, flatMap, map, mergeMap, take, tap} from 'rxjs/operators'; +import {fromPromise} from 'rxjs/internal-compatibility'; /*WEB3*/ import Web3 from 'web3'; -import {RLPEncodedTransaction, SignedTransaction, Transaction as Web3Tx, TransactionConfig, TransactionReceipt} from 'web3-core'; +import {SignedTransaction, Transaction as Web3Tx, TransactionConfig, TransactionReceipt} from 'web3-core'; import {Account} from 'web3-eth-accounts'; -import {AbiItem, fromWei, toWei, isAddress, AbiOutput} from 'web3-utils'; +import {Contract as Web3Contract} from 'web3-eth-contract'; +import {AbiItem, fromWei, isAddress, toWei} from 'web3-utils'; /*SERVICES*/ import {ToastrService} from '../modules/toastr/toastr.service'; import {CommonService} from './common.service'; @@ -20,8 +21,6 @@ import {objIsEmpty} from '../utils/functions'; interface IWallet { w3: Web3; - logged$: BehaviorSubject; - send(tx: TransactionConfig): Observable; call(tx: TransactionConfig): Observable; @@ -31,11 +30,14 @@ interface IWallet { abstract class Wallet { w3: Web3; - logged$: BehaviorSubject = new BehaviorSubject(null); constructor(w3: Web3) { this.w3 = w3; } + + call(tx: TransactionConfig): Observable { + return fromPromise(this.w3.eth.call(tx)); + } } class MetamaskStrategy extends Wallet implements IWallet { @@ -44,43 +46,36 @@ class MetamaskStrategy extends Wallet implements IWallet { return fromPromise(this.w3.eth.sendTransaction(tx)); } - call(tx: TransactionConfig): Observable { - return fromPromise(this.w3.eth.call(tx)); - } - logIn(): Observable { - try { - (window as any).ethereum.enable(); - return fromPromise(this.w3.eth.getAccounts()).pipe( - map((v: string[]) => v[0]), - ); - } catch (e) { - return throwError('Access not granted'); - } + return fromPromise((window as any).ethereum.enable()).pipe( + map((accounts: string[]) => { + return accounts[0]; + }), + ); } } class PrivateKeyStrategy extends Wallet implements IWallet { - private privateKey: string; private account: Account; send(tx: TransactionConfig): Observable { - return fromPromise(this.w3.eth.signTransaction(tx)).pipe( - flatMap((signedTx: RLPEncodedTransaction) => fromPromise(this.w3.eth.sendSignedTransaction(signedTx.raw))), + return fromPromise(this.w3.eth.accounts.signTransaction(tx, this.account.privateKey)).pipe( + flatMap((signedTx: SignedTransaction) => fromPromise(this.w3.eth.sendSignedTransaction(signedTx.rawTransaction))), ); } - call(tx: TransactionConfig): Observable { - return fromPromise(this.w3.eth.call(tx)); - } - logIn(privateKey: string): Observable { if (privateKey.length === 64 && privateKey.indexOf('0x') !== 0) { privateKey = '0x' + privateKey; } if (privateKey.length === 66) { - this.account = this.w3.eth.accounts.privateKeyToAccount(privateKey); - this.logged$.next(true); + let account: Account; + try { + account = this.w3.eth.accounts.privateKeyToAccount(privateKey); + } catch (e) { + return throwError(e); + } + this.account = account; return of(this.account.address); } return throwError('Given private key is not valid'); @@ -92,7 +87,6 @@ export class WalletService { isProcessing = false; // ACCOUNT INFO - account: Account; accountAddress: string; accountAddress$: BehaviorSubject = new BehaviorSubject(null); accountBalance: string; @@ -100,32 +94,34 @@ export class WalletService { receipt: TransactionReceipt; metamaskIntalled$: BehaviorSubject = new BehaviorSubject(false); - metamaskConfigured$: BehaviorSubject = new BehaviorSubject(false); - logged$: BehaviorSubject = new BehaviorSubject(false); - private _ready$: BehaviorSubject = new BehaviorSubject(false); - get ready$(): Observable { - return this._ready$.pipe( - filter(v => !!v), - take(1), + get metamaskConfigured$(): Observable { + return this.ready$.pipe( + mergeMap(() => this._metamaskConfigured$), + filter(v => v !== null), ); } - private _web3Callable$: BehaviorSubject = new BehaviorSubject(null); - private _web3Metamask$: BehaviorSubject = new BehaviorSubject(null); + private _metamaskConfigured$: BehaviorSubject = new BehaviorSubject(null); + + logged$: BehaviorSubject = new BehaviorSubject(false); - private providerContext: IWallet; + // used for paid + private _walletContext: IWallet; - get w3Call(): Observable { - return this._web3Callable$.pipe( - filter(v => !!v), - take(1), + // used for interaction with chain, only free methods + private _w3: Web3; + + get w3$(): Observable { + return this.ready$.pipe( + map(() => this._w3), ); } - get w3Pay(): Observable { - return this._web3Metamask$.pipe( - filter(v => !!v), + private _ready$: BehaviorSubject = new BehaviorSubject(false); + get ready$(): Observable { + return this._ready$.pipe( + filter(v => !!v), take(1), ); } @@ -143,46 +139,39 @@ export class WalletService { initProvider(rpcProvider: string): void { const metaMaskProvider = new Web3(Web3.givenProvider, null, {transactionConfirmationBlocks: 1}); const web3Provider = new Web3(new Web3.providers.HttpProvider(rpcProvider), null, {transactionConfirmationBlocks: 1}); - this._web3Callable$.next(web3Provider); - this.providerContext = new PrivateKeyStrategy(web3Provider); + this._w3 = web3Provider; + this._walletContext = new PrivateKeyStrategy(web3Provider); if (!metaMaskProvider.currentProvider) { - this._web3Metamask$.error('Metamask is not installed/enabled'); - this.metamaskIntalled$.next(false); - this.metamaskConfigured$.next(false); + this._metamaskConfigured$.next(false); + this._ready$.next(true); return; } web3Provider.eth.net.getId((web3err, web3NetID) => { if (web3err) { - this._toastrService.danger('Metamask is enabled but can\'t get network id'); - this._web3Metamask$.error(`Failed to get network id: ${web3err}`); + this._toastrService.danger('Metamask is enabled but can\'t get Gochain network id'); this.metamaskIntalled$.next(true); - this.metamaskConfigured$.next(false); + this._metamaskConfigured$.next(false); this._ready$.next(true); return; } metaMaskProvider.eth.net.getId((metamaskErr, metamask3NetID) => { if (metamaskErr) { this._toastrService.danger('Metamask is enabled but can\'t get network id from Metamask'); - this._web3Metamask$.error(`Failed to Metamask network id: ${metamaskErr}`); this.metamaskIntalled$.next(true); - this.metamaskConfigured$.next(false); + this._metamaskConfigured$.next(false); this._ready$.next(true); return; } if (web3NetID !== metamask3NetID) { this._toastrService.warning('Metamask is enabled but networks are different'); - this._web3Metamask$.error(`Metamask network ID (${metamask3NetID}) doesn't match expected (${web3NetID})`); this.metamaskIntalled$.next(true); - this.metamaskConfigured$.next(false); + this._metamaskConfigured$.next(false); this._ready$.next(true); return; } - console.log('connecting metamask'); - this._web3Metamask$.next(web3Provider); - this.providerContext = new MetamaskStrategy(metaMaskProvider); + this._walletContext = new MetamaskStrategy(metaMaskProvider); this.metamaskIntalled$.next(true); - this.metamaskConfigured$.next(true); - this.logged$.next(true); + this._metamaskConfigured$.next(true); this._ready$.next(true); }); }); @@ -194,22 +183,22 @@ export class WalletService { * @param abi * @param params */ - call(addr: string, abi: AbiItem, params: any[]): Observable | null { - let web3; - return (abi.constant ? this.w3Call : this.w3Pay).pipe( - mergeMap((_web3: Web3) => { - web3 = _web3; - const encoded: string = web3.eth.abi.encodeFunctionCall(abi, params); - return fromPromise(web3.eth.call({ + call(addr: string, abi: AbiItem, params: any[]): Observable { + return this.ready$.pipe( + mergeMap(() => { + const encoded: string = this._w3.eth.abi.encodeFunctionCall(abi, params); + const tx: TransactionConfig = { + from: this.accountAddress, to: addr, data: encoded, - })); + }; + return abi.constant ? this._w3.eth.call(tx) : this._walletContext.call(tx); }), map((res: string) => { if (!res || res === '0x' || res === '0X') { return null; } - const decoded: object = web3.eth.abi.decodeParameters(abi.outputs, res); + const decoded: object = this._w3.eth.abi.decodeParameters(abi.outputs, res); if (objIsEmpty(decoded)) { return null; } @@ -223,46 +212,49 @@ export class WalletService { * @param txHash */ getTxData(txHash: string): Observable { - return this.w3Call.pipe(concatMap((web3: Web3) => { - return forkJoin([ - fromPromise(web3.eth.getTransaction(txHash)), - fromPromise(web3.eth.getTransactionReceipt(txHash)), - ]).pipe( - map((res: [Web3Tx, TransactionReceipt]) => { - if (!res[0]) { - return null; - } - const tx: Web3Tx = res[0]; - const txReceipt = res[1]; - const finalTx: Transaction = new Transaction(); - finalTx.tx_hash = tx.hash; - finalTx.value = tx.value; - finalTx.gas_price = tx.gasPrice; - finalTx.gas_limit = '' + tx.gas; - finalTx.nonce = tx.nonce; - finalTx.input_data = tx.input.replace(/^0x/, ''); - finalTx.from = tx.from; - finalTx.to = tx.to; - if (txReceipt) { - finalTx.block_number = tx.blockNumber; - finalTx.gas_fee = '' + (+tx.gasPrice * txReceipt.gasUsed); - finalTx.contract_address = - (txReceipt.contractAddress && txReceipt.contractAddress !== '0x0000000000000000000000000000000000000000') - ? txReceipt.contractAddress - : null; - finalTx.status = txReceipt.status; - finalTx.created_at = new Date(); - } - return finalTx; - }), - ); - })); + return this.ready$.pipe( + concatMap(() => { + return forkJoin([ + fromPromise(this._w3.eth.getTransaction(txHash)), + fromPromise(this._w3.eth.getTransactionReceipt(txHash)), + ]).pipe( + map((res: [Web3Tx, TransactionReceipt]) => { + if (!res[0]) { + return null; + } + const tx: Web3Tx = res[0]; + const txReceipt = res[1]; + const finalTx: Transaction = new Transaction(); + finalTx.tx_hash = tx.hash; + finalTx.value = tx.value; + finalTx.gas_price = tx.gasPrice; + finalTx.gas_limit = '' + tx.gas; + finalTx.nonce = tx.nonce; + finalTx.input_data = tx.input.replace(/^0x/, ''); + finalTx.from = tx.from; + finalTx.to = tx.to; + if (txReceipt) { + finalTx.block_number = tx.blockNumber; + finalTx.gas_fee = '' + (+tx.gasPrice * txReceipt.gasUsed); + finalTx.contract_address = + (txReceipt.contractAddress && txReceipt.contractAddress !== '0x0000000000000000000000000000000000000000') + ? txReceipt.contractAddress + : null; + finalTx.status = txReceipt.status; + finalTx.created_at = new Date(); + } + return finalTx; + }), + ); + })); } estimateGas(tx: TransactionConfig): Observable { - return this.w3Call.pipe(concatMap((web3: Web3) => { - return fromPromise(web3.eth.estimateGas(tx)); - })); + return this.ready$.pipe( + concatMap(() => { + return fromPromise(this._w3.eth.estimateGas(tx)); + }), + ); } // WALLET METHODS @@ -280,7 +272,7 @@ export class WalletService { } if (to.length !== 42 || !isAddress(to)) { - this._toastrService.danger('ERROR: Invalid TO address.'); + this._toastrService.danger('Invalid TO address.'); return; } @@ -331,7 +323,7 @@ export class WalletService { sendTx(tx: TransactionConfig): void { this.isProcessing = true; this.ready$.pipe( - flatMap(() => this.providerContext.send(tx)) + flatMap(() => this._walletContext.send(tx)), ).subscribe((receipt: TransactionReceipt) => { this.receipt = receipt; this.getBalance(); @@ -339,25 +331,6 @@ export class WalletService { this._toastrService.danger(err); this.resetProcessing(); }); - /*this.w3Pay.subscribe((web3: Web3) => { - const p: Promise = web3.eth.getTransactionCount(this.account.address); - fromPromise(p).pipe( - concatMap(nonce => { - tx.nonce = nonce; - const p2: Promise = web3.eth.accounts.signTransaction(tx, this.account.privateKey); - return fromPromise(p2); - }), - concatMap((signed: SignedTransaction) => { - return this.sendSignedTx(signed); - }) - ).subscribe((receipt: TransactionReceipt) => { - this.receipt = receipt; - this.getBalance(); - }, err => { - this._toastrService.danger(err); - this.resetProcessing(); - }); - });*/ } resetProcessing(): void { @@ -368,60 +341,55 @@ export class WalletService { // ACCOUNT METHODS createAccount(): Observable { - return this.w3Call.pipe(map((web3: Web3) => { - return web3.eth.accounts.create(); - })); + return this.ready$.pipe( + map(() => this._w3.eth.accounts.create()), + ); } openAccount(privateKey: string = null): Observable { this.isProcessing = true; return this.ready$.pipe( - flatMap(() => this.providerContext.logIn(privateKey)), catchError(err => { - this._toastrService.danger(err); - return of(null); - }), + flatMap(() => this._walletContext.logIn(privateKey)), tap((accountAddress: string) => { this.accountAddress = accountAddress; this.accountAddress$.next(accountAddress); + this.logged$.next(true); this.isProcessing = false; this.getBalance(); + }, (err) => { + this.isProcessing = false; }), ); - /*if (privateKey.length === 64 && privateKey.indexOf('0x') !== 0) { - privateKey = '0x' + privateKey; - } - if (privateKey.length === 66) { - return this.w3Call.pipe(map((web3: Web3) => { - this.account = web3.eth.accounts.privateKeyToAccount(privateKey); - this.accountAddress = this.account.address; - this.logged$.next(true); - this.getBalance(); - return true; - }), catchError(err => { - this._toastrService.danger(err); - return of(false); - }), finalize(() => this.isProcessing = false)); - } - this.isProcessing = false; - this._toastrService.danger('Given private key is not valid'); - return of(false);*/ } closeAccount(): void { - this.account = null; this.accountBalance = null; this.accountAddress = null; + this.logged$.next(false); this._router.navigate(['wallet']); } getBalance() { - this.w3Call.pipe(concatMap((web3: Web3) => { - return fromPromise(web3.eth.getBalance(this.accountAddress)); - })).subscribe((balance: string) => { + this.ready$.pipe( + concatMap(() => fromPromise(this._w3.eth.getBalance(this.accountAddress))), + ).subscribe((balance: string) => { this._toastrService.info('Updated balance.'); this.accountBalance = fromWei(balance, 'ether').toString(); }, err => { this._toastrService.danger(err); }); } + + + initContract(addrHash: string, abiItems: AbiItem[]): Observable { + return this.ready$.pipe( + map(() => new this._w3.eth.Contract(abiItems, addrHash)) + ); + } + + getBlockNumber(): Observable { + return this.ready$.pipe( + mergeMap(() => this._w3.eth.getBlockNumber()), + ); + } } From 2e325d1ecd9b5d3454fbfd898311d1199c7de76f Mon Sep 17 00:00:00 2001 From: Murat Baybosunov Date: Wed, 30 Oct 2019 17:31:35 +0600 Subject: [PATCH 03/10] build dix --- front/src/app/app.component.html | 2 +- front/src/app/app.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/front/src/app/app.component.html b/front/src/app/app.component.html index fa97d33a..bebadafc 100644 --- a/front/src/app/app.component.html +++ b/front/src/app/app.component.html @@ -1,7 +1,7 @@ -
+
Loading
diff --git a/front/src/app/app.component.ts b/front/src/app/app.component.ts index b2475149..e99d16d4 100644 --- a/front/src/app/app.component.ts +++ b/front/src/app/app.component.ts @@ -10,6 +10,6 @@ import { Subscription } from 'rxjs'; }) @AutoUnsubscribe('_subsArr$') export class AppComponent { - constructor(private _layoutService: LayoutService) { + constructor(public layoutService: LayoutService) { } } From 7540d2e45cafc086bbd36f09a98c75d668d79ef0 Mon Sep 17 00:00:00 2001 From: Murat Baybosunov Date: Wed, 30 Oct 2019 17:45:15 +0600 Subject: [PATCH 04/10] some improvements --- front/src/app/models/query_params.ts | 2 +- .../app/scenes/richlist/richlist.component.ts | 9 +++- .../wallet-account.component.html | 4 +- .../wallet-account.component.ts | 5 +- front/src/app/services/wallet.service.ts | 52 +++++++++++++------ 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/front/src/app/models/query_params.ts b/front/src/app/models/query_params.ts index 40146837..cef56870 100644 --- a/front/src/app/models/query_params.ts +++ b/front/src/app/models/query_params.ts @@ -1,7 +1,7 @@ import {BehaviorSubject, Subject} from 'rxjs'; import {removeEmpty} from '../utils/functions'; -interface IParams { +export interface IParams { limit: number; skip: number; } diff --git a/front/src/app/scenes/richlist/richlist.component.ts b/front/src/app/scenes/richlist/richlist.component.ts index 4ac036e5..ba1be223 100644 --- a/front/src/app/scenes/richlist/richlist.component.ts +++ b/front/src/app/scenes/richlist/richlist.component.ts @@ -9,7 +9,7 @@ import {MetaService} from '../../services/meta.service'; /*MODELS*/ import {RichList} from '../../models/rich_list.model'; import {Address} from '../../models/address.model'; -import {QueryParams} from '../../models/query_params'; +import {IParams, QueryParams} from '../../models/query_params'; /*UTILS*/ import {AutoUnsubscribe} from '../../decorators/auto-unsubscribe'; import {META_TITLES} from '../../utils/constants'; @@ -55,7 +55,9 @@ export class RichlistComponent implements OnInit, OnDestroy { initSub() { this._subsArr$.push(this.richListQueryParams.state.pipe( - tap(() => this.isLoading = true), + tap(() => { + this.isLoading = true; + }), flatMap(params => this._commonService.getRichlist(params)), filter((data: RichList) => !!data), ).subscribe((data: RichList) => { @@ -68,6 +70,9 @@ export class RichlistComponent implements OnInit, OnDestroy { } this.isLoading = false; this._layoutService.offLoading(); + }, (err) => { + this.isLoading = false; + this._layoutService.offLoading(); })); } } diff --git a/front/src/app/scenes/wallet-account/wallet-account.component.html b/front/src/app/scenes/wallet-account/wallet-account.component.html index c04deb38..ff29262f 100644 --- a/front/src/app/scenes/wallet-account/wallet-account.component.html +++ b/front/src/app/scenes/wallet-account/wallet-account.component.html @@ -1,8 +1,8 @@ -
+
Account ACCOUNT
-

Address: {{walletService.accountAddress$ | async}}

+

Address: {{walletService.accountAddress}}

Balance (GO): {{walletService.accountBalance | number}}

+
+ +
diff --git a/front/src/app/scenes/wallet-main/wallet-main.component.ts b/front/src/app/scenes/wallet-main/wallet-main.component.ts index a22e2c51..1dea2ab3 100644 --- a/front/src/app/scenes/wallet-main/wallet-main.component.ts +++ b/front/src/app/scenes/wallet-main/wallet-main.component.ts @@ -49,9 +49,9 @@ export class WalletMainComponent implements OnInit { } ngOnInit() { - this._layoutService.onLoading(); + /*this._layoutService.onLoading();*/ this._metaService.setTitle(META_TITLES.WALLET.title); - this.walletService.metamaskConfigured$.pipe( + /*this.walletService.metamaskConfigured$.pipe( filter((v: boolean) => { if (!v) { this._layoutService.offLoading(); @@ -65,14 +65,17 @@ export class WalletMainComponent implements OnInit { }, (err) => { this._toastrService.danger(err); this._layoutService.offLoading(); - }); + });*/ } - onPrivateKeySubmit() { - const privateKey: string = this.privateKeyForm.get('privateKey').value; - if (!privateKey) { - this._toastrService.danger('Please enter private key'); - return; + onSubmit(metamask: boolean = false) { + let privateKey: string = null; + if (!metamask) { + privateKey = this.privateKeyForm.get('privateKey').value; + if (!privateKey) { + this._toastrService.danger('Please enter private key'); + return; + } } this.walletService.openAccount(privateKey).subscribe( () => this._router.navigate(['/wallet/account']), diff --git a/front/src/app/services/wallet.service.ts b/front/src/app/services/wallet.service.ts index 527a738c..d382c937 100644 --- a/front/src/app/services/wallet.service.ts +++ b/front/src/app/services/wallet.service.ts @@ -133,6 +133,7 @@ export class WalletService { // used for interaction with chain, only free methods private _w3: Web3; + private _metamaskw3: Web3; get w3$(): Observable { return this.ready$.pipe( @@ -162,7 +163,6 @@ export class WalletService { const metaMaskProvider = new Web3(Web3.givenProvider, null, {transactionConfirmationBlocks: 1}); const web3Provider = new Web3(new Web3.providers.HttpProvider(rpcProvider), null, {transactionConfirmationBlocks: 1}); this._w3 = web3Provider; - this._walletContext = new PrivateKeyStrategy(web3Provider); if (!metaMaskProvider.currentProvider) { this._metamaskConfigured$.next(false); this._ready$.next(true); @@ -191,7 +191,7 @@ export class WalletService { this._ready$.next(true); return; } - this._walletContext = new MetamaskStrategy(metaMaskProvider); + this._metamaskw3 = metaMaskProvider; this._metamaskIntalled$.next(true); this._metamaskConfigured$.next(true); this._ready$.next(true); @@ -371,7 +371,10 @@ export class WalletService { openAccount(privateKey: string = null): Observable { this.isProcessing = true; return this.ready$.pipe( - mergeMap(() => this._walletContext.logIn(privateKey)), + mergeMap(() => { + this._walletContext = new MetamaskStrategy(privateKey === null ? this._metamaskw3 : this._w3); + return this._walletContext.logIn(privateKey); + }), tap((accountAddress: string) => { this.accountAddress = accountAddress; this._logged$.next(true); From 3a594a4179a7ab5fc71b503f85eb7ba98cdc15c0 Mon Sep 17 00:00:00 2001 From: Murat Baybosunov Date: Wed, 30 Oct 2019 20:24:39 +0600 Subject: [PATCH 06/10] fixed wallet provider init --- front/src/app/services/wallet.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/front/src/app/services/wallet.service.ts b/front/src/app/services/wallet.service.ts index d382c937..86b53269 100644 --- a/front/src/app/services/wallet.service.ts +++ b/front/src/app/services/wallet.service.ts @@ -372,7 +372,7 @@ export class WalletService { this.isProcessing = true; return this.ready$.pipe( mergeMap(() => { - this._walletContext = new MetamaskStrategy(privateKey === null ? this._metamaskw3 : this._w3); + this._walletContext = privateKey === null ? new MetamaskStrategy(this._metamaskw3) : new PrivateKeyStrategy(this._w3); return this._walletContext.logIn(privateKey); }), tap((accountAddress: string) => { From 003e52be51e59bb326f85fdec2d9e7e0ebc02242 Mon Sep 17 00:00:00 2001 From: Murat Baybosunov Date: Mon, 20 Jan 2020 14:19:19 +0600 Subject: [PATCH 07/10] phase 1 from issue #440 --- .../wallet-account.component.html | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/front/src/app/scenes/wallet-account/wallet-account.component.html b/front/src/app/scenes/wallet-account/wallet-account.component.html index 65ba486a..86f798b0 100644 --- a/front/src/app/scenes/wallet-account/wallet-account.component.html +++ b/front/src/app/scenes/wallet-account/wallet-account.component.html @@ -2,7 +2,8 @@
Account ACCOUNT
-

Address: {{walletService.accountAddress}}

+

Address: {{walletService.accountAddress}}

Balance (GO): {{walletService.accountBalance | number}}