on master help sign in
Added Metamask Authentication
commit45e69c254c34d5a23a1fc5b87719f296e6997504 authorLiam Fitzgerald <hastuc-dibtux@gmail.com> dateThu 5 Sep 2019, 17:07 (7 years ago) parent3523743
6 files changed+118−1
src/components/Buttons.js+4−1 src/lib/metamask.js+27 src/lib/txn.js+17 src/lib/wallet.js+1 src/views/Login.js+4 src/views/Login/Metamask.js+65
src/components/Buttons.js+4−1
@@ -25,7 +25,10 @@ export const OfflineButton = props => (
2525);
2626
2727export const BootArvoButton = props => (
28− <OutButton href="https://urbit.org/docs/getting-started" detail="Boot your computer" {...props}>
28+ <OutButton
29+ href="https://urbit.org/docs/getting-started"
30+ detail="Boot your computer"
31+ {...props}>
2932 Boot Arvo
3033 </OutButton>
3134);
src/lib/metamask.jsnew file+27
@@ -0,0 +1,27 @@
1+export function MetamaskWallet(address) {
2+ this.address = address;
3+}
4+
5+export function FakeMetamaskTransaction(txnData) {
6+ this.txnData = txnData;
7+
8+ this.serialize = function() {
9+ return '0';
10+ };
11+}
12+
13+// Cheat a bit and pretend to sign transaction
14+// Sign it actually when sending
15+export const metamaskSignTransaction = async (txn, from) => {
16+ const metamaskFormattedTxn = {
17+ to: txn.to.toString('hex'),
18+ value: txn.value.toString('hex'),
19+ data: txn.data.toString('hex'),
20+ gasLimit: txn.gasLimit.toString('hex'),
21+ gasPrice: txn.gasPrice.toString('hex'),
22+ nonce: txn.nonce.length === 0 ? '00' : txn.nonce.toString('hex'),
23+ from: from,
24+ };
25+
26+ return new FakeMetamaskTransaction(metamaskFormattedTxn);
27+};
src/lib/txn.js+17
@@ -5,6 +5,7 @@ import retry from 'async-retry';
55import { NETWORK_TYPES } from './network';
66import { ledgerSignTransaction } from './ledger';
77import { trezorSignTransaction } from './trezor';
8+import { metamaskSignTransaction, FakeMetamaskTransaction } from './metamask';
89import { WALLET_TYPES, addHexPrefix } from './wallet';
910import { CHECK_BLOCK_EVERY_MS } from './constants';
1011import patp2dec from './patp2dec';
@@ -89,6 +90,8 @@ const signTransaction = async ({
8990 await ledgerSignTransaction(stx, walletHdPath);
9091 } else if (walletType === WALLET_TYPES.TREZOR) {
9192 await trezorSignTransaction(stx, walletHdPath);
93+ } else if (walletType === WALLET_TYPES.METAMASK) {
94+ return metamaskSignTransaction(stx, wallet.address);
9295 } else {
9396 stx.sign(wallet.privateKey);
9497 }
@@ -97,6 +100,20 @@ const signTransaction = async ({
97100};
98101
99102const sendSignedTransaction = (web3, stx, doubtNonceError) => {
103+ // Handle fake metamask transaction
104+ if (stx instanceof FakeMetamaskTransaction) {
105+ const { ethereum } = window;
106+ const sendTxs = {
107+ method: 'eth_sendTransaction',
108+ params: [stx.txnData],
109+ from: stx.txnData.from,
110+ };
111+ return new Promise((resolve, reject) =>
112+ ethereum.sendAsync(sendTxs, (err, data) =>
113+ err ? reject(err) : resolve(data.result)
114+ )
115+ );
116+ }
100117 const rawTx = hexify(stx.serialize());
101118
102119 return new Promise(async (resolve, reject) => {
src/lib/wallet.js+1
@@ -19,6 +19,7 @@ export const WALLET_TYPES = {
1919 TREZOR: Symbol('TREZOR'),
2020 PRIVATE_KEY: Symbol('PRIVATE_KEY'),
2121 KEYSTORE: Symbol('KEYSTORE'),
22+ METAMASK: Symbol('METAMASK'),
2223};
2324
2425export function EthereumWallet(privateKey) {
src/views/Login.js+4
@@ -16,12 +16,14 @@ import Ticket from './Login/Ticket';
1616import Mnemonic from './Login/Mnemonic';
1717import Advanced from './Login/Advanced';
1818import Hardware from './Login/Hardware';
19+import Metamask from './Login/Metamask';
1920
2021const NAMES = {
2122 TICKET: 'TICKET',
2223 MNEMONIC: 'MNEMONIC',
2324 HARDWARE: 'HARDWARE',
2425 ADVANCED: 'ADVANCED',
26+ METAMASK: 'METAMASK',
2527};
2628
2729const VIEWS = {
@@ -29,6 +31,7 @@ const VIEWS = {
2931 [NAMES.MNEMONIC]: Mnemonic,
3032 [NAMES.HARDWARE]: Hardware,
3133 [NAMES.ADVANCED]: Advanced,
34+ [NAMES.METAMASK]: Metamask,
3235};
3336
3437const OPTIONS = [
@@ -36,6 +39,7 @@ const OPTIONS = [
3639 { text: 'Mnemonic', value: NAMES.MNEMONIC },
3740 { text: 'Hardware', value: NAMES.HARDWARE },
3841 { text: 'Advanced', value: NAMES.ADVANCED },
42+ { text: 'Metamask', value: NAMES.METAMASK },
3943];
4044
4145const walletTypeToViewName = walletType => {
src/views/Login/Metamask.jsnew file+65
@@ -0,0 +1,65 @@
1+import React, { useCallback } from 'react';
2+import cn from 'classnames';
3+import { Grid, Text, LinkButton, H5 } from 'indigo-react';
4+import { Just } from 'folktale/maybe';
5+
6+import { useWallet } from 'store/wallet';
7+
8+import { WALLET_TYPES } from 'lib/wallet';
9+import { MetamaskWallet } from 'lib/metamask';
10+
11+import SubmitButton from 'form/SubmitButton';
12+import BridgeForm from 'form/BridgeForm';
13+
14+export default function Metamask({ className, goHome }) {
15+ const { setWallet, setWalletType } = useWallet();
16+
17+ const onSubmit = useCallback(async () => {
18+ const accounts = await window.ethereum.enable();
19+ const wallet = new MetamaskWallet(accounts[0]);
20+ setWallet(Just(wallet));
21+ setWalletType(WALLET_TYPES.METAMASK);
22+ }, [setWallet]);
23+
24+ const login = () => (
25+ <>
26+ <Grid.Item full as={H5}>
27+ Authenticate with Metamask
28+ </Grid.Item>
29+ <Grid.Item full as={Text} className="f6 mb3">
30+ If you wish to login with a different wallet, please change it in the
31+ Metamask extension
32+ </Grid.Item>
33+ <BridgeForm onSubmit={onSubmit} afterSubmit={goHome}>
34+ {({ handleSubmit }) => (
35+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
36+ Login
37+ {window.ethereum.selectedAddress &&
38+ ' as ' + window.ethereum.selectedAddress}
39+ </Grid.Item>
40+ )}
41+ </BridgeForm>
42+ </>
43+ );
44+ return (
45+ <Grid className={cn('mt4', className)}>
46+ {(window.ethereum && login()) || MetamaskUnsupported()}
47+ </Grid>
48+ );
49+}
50+
51+function MetamaskUnsupported() {
52+ return (
53+ <>
54+ <Grid.Item full as={H5}>
55+ Metamask unsupported
56+ </Grid.Item>
57+ <Grid.Item full as={Text} className="f6 mb3">
58+ Metamask is not installed on this browser.
59+ <LinkButton href="https://metamask.io" as={LinkButton}>
60+ Get Metamask
61+ </LinkButton>
62+ </Grid.Item>
63+ </>
64+ );
65+}