on 505d3e2 help sign in
bridge/src/lib/authToken.ts
134 lines 3.9 kB history raw
1import { crypto } from 'bitcoinjs-lib';
2import { ecdsaSign } from 'secp256k1';
3import Web3 from 'web3';
4import { hexToBytes } from 'web3-utils';
5import WalletConnect from '@walletconnect/client';
7import { WALLET_TYPES } from './constants';
8import { ledgerSignMessage } from './ledger';
9import { trezorSignMessage } from './trezor';
10import BridgeWallet from './types/BridgeWallet';
11import { Hash } from '@urbit/roller-api';
12import { keccak256 } from 'ethereumjs-util';
14const MESSAGE = 'Bridge Authentication Token';
16function signMessage(privateKey: Buffer, useLegacyTokenSigning = false) {
17 const msg = '\x19Ethereum Signed Message:\n' + MESSAGE.length + MESSAGE;
18 const hashed = useLegacyTokenSigning
19 ? crypto.sha256(Buffer.from(msg))
20 : keccak256(Buffer.from(msg));
21 const { signature } = ecdsaSign(Buffer.from(hashed), privateKey);
23 // add key recovery parameter
24 const ethSignature = new Uint8Array(65);
25 ethSignature.set(signature);
26 const v = (ethSignature[32] & 1) + 27;
27 ethSignature[64] = v;
29 return ethSignature;
32export function signTransactionHash(msg: Hash, prvKey: Buffer) {
33 // msg is a keccak-256 hash
34 //
35 const hashed = Buffer.from(hexToBytes(msg));
36 const { signature, recid } = ecdsaSign(hashed, prvKey);
37 // add key recovery parameter
38 const ethSignature = new Uint8Array(65);
39 ethSignature.set(signature);
40 ethSignature[64] = recid;
41 return `0x${Buffer.from(ethSignature).toString('hex')}`;
44type MetamaskAuthTokenArgs = {
45 address: string;
46 web3: Web3;
47 walletType: symbol;
48};
50type LedgerAuthTokenArgs = {
51 walletHdPath: string;
52 walletType: symbol;
53};
55type TrezorAuthTokenArgs = LedgerAuthTokenArgs;
57type WalletConnectAuthTokenArgs = {
58 address: string;
59 connector: WalletConnect;
60 walletType: symbol;
61};
63type DefaultAuthTokenArgs = {
64 wallet: BridgeWallet;
65 walletType?: symbol;
66 useLegacyTokenSigning?: boolean;
67};
69type GetAuthTokenArgs =
70 | MetamaskAuthTokenArgs
71 | LedgerAuthTokenArgs
72 | TrezorAuthTokenArgs
73 | WalletConnectAuthTokenArgs
74 | DefaultAuthTokenArgs;
76const getMetamaskAuthToken = ({ address, web3 }: MetamaskAuthTokenArgs) => {
77 if (window.ethereum) {
78 //NOTE this doesn't _seem_ to be affected by #596,
79 // but web3.eth.personal.sign hits it semi-reliably?
80 // no idea what's going on, we should figure it out,
81 // but we apply this bandaid to hopefully stop the bleeding.
82 return window.ethereum.request({
83 method: 'personal_sign',
84 params: [MESSAGE, address],
85 from: address,
86 });
87 } else {
88 return web3.eth.personal.sign(MESSAGE, address, '');
89 }
90};
92const getLedgerAuthToken = ({ walletHdPath }: LedgerAuthTokenArgs) => {
93 return ledgerSignMessage(MESSAGE, walletHdPath);
94};
96const getTrezorAuthToken = ({ walletHdPath }: TrezorAuthTokenArgs) => {
97 return trezorSignMessage(MESSAGE, walletHdPath);
98};
100const getWalletConnectAuthToken = ({
101 address,
102 connector,
103}: WalletConnectAuthTokenArgs) => {
104 return connector.signPersonalMessage([MESSAGE, address]);
105};
107const getDefaultAuthToken = ({
108 wallet,
109 useLegacyTokenSigning = false,
110}: DefaultAuthTokenArgs) => {
111 const signature = signMessage(wallet.privateKey!, useLegacyTokenSigning);
113 const token = `0x${Buffer.from(signature).toString('hex')}`;
115 return token;
116};
118export const getAuthToken = async ({
119 walletType,
120 ...args
121}: GetAuthTokenArgs) => {
122 switch (walletType) {
123 case WALLET_TYPES.METAMASK:
124 return getMetamaskAuthToken(args as MetamaskAuthTokenArgs);
125 case WALLET_TYPES.LEDGER:
126 return getLedgerAuthToken(args as LedgerAuthTokenArgs);
127 case WALLET_TYPES.TREZOR:
128 return getTrezorAuthToken(args as TrezorAuthTokenArgs);
129 case WALLET_TYPES.WALLET_CONNECT:
130 return getWalletConnectAuthToken(args as WalletConnectAuthTokenArgs);
131 default:
132 return getDefaultAuthToken(args as DefaultAuthTokenArgs);
133 }
134};