Skip to content

Commit

Permalink
Integrate MetaMask into AccountDialogComponent
Browse files Browse the repository at this point in the history
  • Loading branch information
manuelwedler committed Aug 9, 2021
1 parent c929992 commit 9439334
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 6 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@angular/platform-browser": "12.1.4",
"@angular/platform-browser-dynamic": "12.1.4",
"@angular/router": "12.1.4",
"@metamask/detect-provider": "^1.2.0",
"ajv": "8.6.2",
"assert": "2.0.0",
"bignumber.js": "9.0.1",
Expand Down
33 changes: 30 additions & 3 deletions src/app/components/account-dialog/account-dialog.component.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
<app-raiden-dialog
acceptText="Done"
[acceptText]="
defaultAccount
? 'Send ' + (ethSelected ? 'ETH' : token.symbol)
: 'Connect Wallet'
"
[acceptDisabled]="!web3 || (defaultAccount && form.invalid)"
infoText="You can use this dialog to top up your account with ETH or tokens from a wallet."
[showCancel]="false"
[formGroup]="form"
(accept)="close()"
[noButtons]="requesting"
(accept)="accept()"
(cancel)="close()"
>
<div fxLayout="column" fxLayoutAlign="start center" fxLayoutGap="16px">
Expand Down Expand Up @@ -77,6 +83,27 @@
<span class="info__label info__label--white">
Send {{ ethSelected ? 'ETH' : token.symbol }} to your account
</span>
<app-token-input formControlName="amount"></app-token-input>
<app-token-input
class="token-input"
formControlName="amount"
></app-token-input>
<mat-progress-spinner
*ngIf="requesting"
diameter="38"
mode="indeterminate"
color="accent"
></mat-progress-spinner>
<div class="error-box" [@fallDown]="'in'">
<span *ngIf="!web3">
Could not detect wallet. You need MetaMask to proceed.
</span>
<span *ngIf="wrongChainID" class="error-box__item">
The chain ids of your Web3 provider and your Raiden client do
not match.
</span>
<span *ngIf="accountRequestRejected" class="error-box__item">
Access to accounts rejected.
</span>
</div>
</div>
</app-raiden-dialog>
18 changes: 18 additions & 0 deletions src/app/components/account-dialog/account-dialog.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,21 @@
line-height: 14px;
}
}

.token-input {
width: 224px;
}

.error-box {
width: 100%;
font-size: 12px;
line-height: 15px;
color: $red;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;

&__item {
height: 32px;
}
}
155 changes: 153 additions & 2 deletions src/app/components/account-dialog/account-dialog.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,32 @@ import { TokenPollingService } from 'app/services/token-polling.service';
import { UserDepositService } from 'app/services/user-deposit.service';
import { Network } from 'app/utils/network-info';
import BigNumber from 'bignumber.js';
import { combineLatest, Observable, Subject, zip } from 'rxjs';
import {
combineLatest,
defer,
from,
Observable,
Subject,
throwError,
zip,
} from 'rxjs';
import {
catchError,
filter,
finalize,
first,
map,
switchMap,
takeUntil,
tap,
} from 'rxjs/operators';
import { TokenInputComponent } from '../token-input/token-input.component';
import detectEthereumProvider from '@metamask/detect-provider';
import Web3 from 'web3';
import { Animations } from 'app/animations/animations';
import { tokenabi } from 'app/models/tokenabi';
import { NotificationService } from 'app/services/notification.service';
import { amountToDecimal } from 'app/utils/amount.converter';

export interface AccountDialogPayload {
readonly asset: UserToken | 'ETH';
Expand All @@ -26,6 +43,7 @@ export interface AccountDialogPayload {
selector: 'app-account-dialog',
templateUrl: './account-dialog.component.html',
styleUrls: ['./account-dialog.component.scss'],
animations: Animations.fallDown,
})
export class AccountDialogComponent implements OnInit, OnDestroy {
@ViewChild(TokenInputComponent, { static: true })
Expand All @@ -35,6 +53,11 @@ export class AccountDialogComponent implements OnInit, OnDestroy {
token: UserToken;
balance: BigNumber;
ethSelected: boolean;
web3: Web3;
defaultAccount: string;
requesting = false;
accountRequestRejected = false;
wrongChainID = false;

readonly network$: Observable<Network>;
readonly faucetLink$: Observable<string>;
Expand All @@ -49,7 +72,8 @@ export class AccountDialogComponent implements OnInit, OnDestroy {
private raidenService: RaidenService,
private fb: FormBuilder,
private tokenPollingService: TokenPollingService,
private userDepositService: UserDepositService
private userDepositService: UserDepositService,
private notificationService: NotificationService
) {
this.form = this.fb.group({
asset: [data.asset, Validators.required],
Expand Down Expand Up @@ -104,14 +128,141 @@ export class AccountDialogComponent implements OnInit, OnDestroy {
}
});
this.form.controls.asset.updateValueAndValidity();

from(detectEthereumProvider())
.pipe(
filter((provider) => !!provider),
map((provider: any) => new Web3(provider)),
tap((web3) => (this.web3 = web3)),
switchMap((web3) =>
from<Promise<string[]>>(web3.eth.getAccounts())
)
)
.subscribe((accounts) => {
if (accounts.length > 0) {
this.defaultAccount = accounts[0];
}
});
}

ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}

accept() {
if (this.defaultAccount) {
this.sendTransaction();
} else {
this.connectWallet();
}
}

close() {
this.dialogRef.close();
}

private sendTransaction() {
const symbol = this.ethSelected ? 'ETH' : this.token.symbol;
const formattedAmount = amountToDecimal(
this.form.value.amount,
this.ethSelected ? 18 : this.token.decimals
).toFixed();
let notificationIdentifier: number;

defer(() => {
this.dialogRef.close();
notificationIdentifier = this.notificationService.addPendingAction({
title: `Sending ${symbol} to account`,
description: `${formattedAmount} ${symbol}`,
icon: 'deposit',
userToken: this.token,
});
const raidenAddress = this.raidenService.raidenAddress;
const transferValue = (
this.form.value.amount as BigNumber
).toFixed();

if (this.ethSelected) {
return from(
this.web3.eth.sendTransaction({
from: this.defaultAccount,
to: raidenAddress,
value: transferValue,
})
);
} else {
const tokenContract = new this.web3.eth.Contract(
tokenabi,
this.token.address
);
return from(
tokenContract.methods
.transfer(raidenAddress, transferValue)
.send({ from: this.defaultAccount })
);
}
})
.pipe(
catchError((e) => {
console.log(e);
return throwError(e);
}),
finalize(() =>
this.notificationService.removePendingAction(
notificationIdentifier
)
)
)
.subscribe({
next: () =>
this.notificationService.addSuccessNotification({
title: `Sent ${symbol} to account`,
description: `${formattedAmount} ${symbol}`,
icon: 'deposit',
userToken: this.token,
}),
error: (error) =>
this.notificationService.addErrorNotification({
title: `Send ${symbol} to account failed`,
description: error.message
? error.message
: error.toString(),
icon: 'error-mark',
userToken: this.token,
}),
});
}

private connectWallet() {
const requestAccounts$ = defer(() =>
from(this.web3.eth.requestAccounts())
).pipe(
catchError((error) => {
this.accountRequestRejected = true;
return throwError(error);
})
);

defer(() => {
this.requesting = true;
this.accountRequestRejected = false;
this.wrongChainID = false;
return zip(
from(this.web3.eth.getChainId()),
this.raidenService.network$
);
})
.pipe(
switchMap(([web3ChainId, network]) => {
if (web3ChainId !== network.chainId) {
this.wrongChainID = true;
return throwError('Chain ids not matching.');
}
return requestAccounts$;
}),
finalize(() => (this.requesting = false))
)
.subscribe((accounts) => (this.defaultAccount = accounts[0]));
}
}
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"target": "es2015",
"typeRoots": ["node_modules/@types"],
"lib": ["es2017", "dom"],
"baseUrl": "src"
"baseUrl": "src",
"allowSyntheticDefaultImports": true
}
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1492,6 +1492,11 @@
merge-source-map "^1.1.0"
schema-utils "^2.7.0"

"@metamask/detect-provider@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@metamask/detect-provider/-/detect-provider-1.2.0.tgz#3667a7531f2a682e3c3a43eaf3a1958bdb42a696"
integrity sha512-ocA76vt+8D0thgXZ7LxFPyqw3H7988qblgzddTDA6B8a/yU0uKV42QR/DhA+Jh11rJjxW0jKvwb5htA6krNZDQ==

"@ngtools/webpack@12.1.4":
version "12.1.4"
resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-12.1.4.tgz#9f7ac5e26b366831b50558bf71dd6e1689743def"
Expand Down

0 comments on commit 9439334

Please sign in to comment.