Transaction signing
This commit is contained in:
parent
e9101516e7
commit
b9bd734cd0
|
@ -38,30 +38,39 @@ export class LedgerWallet extends HardwareWallet implements IFullWallet {
|
|||
|
||||
// modeled after
|
||||
// https://github.com/kvhnuke/etherwallet/blob/3f7ff809e5d02d7ea47db559adaca1c930025e24/app/scripts/uiFuncs.js#L58
|
||||
public signRawTransaction(t: EthTx): Promise<Buffer> {
|
||||
public async signRawTransaction(t: EthTx): Promise<Buffer> {
|
||||
const txFields = getTransactionFields(t);
|
||||
|
||||
if (process.env.BUILD_ELECTRON) {
|
||||
const res = await EnclaveAPI.signTransaction({
|
||||
walletType: WalletTypes.LEDGER,
|
||||
transaction: txFields,
|
||||
path: this.getPath()
|
||||
});
|
||||
return new EthTx(res.signedTransaction).serialize();
|
||||
}
|
||||
|
||||
t.v = Buffer.from([t._chainId]);
|
||||
t.r = toBuffer(0);
|
||||
t.s = toBuffer(0);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.ethApp
|
||||
.signTransaction_async(this.getPath(), t.serialize().toString('hex'))
|
||||
.then(result => {
|
||||
const strTx = getTransactionFields(t);
|
||||
const txToSerialize: TxObj = {
|
||||
...strTx,
|
||||
v: addHexPrefix(result.v),
|
||||
r: addHexPrefix(result.r),
|
||||
s: addHexPrefix(result.s)
|
||||
};
|
||||
try {
|
||||
const result = await this.ethApp.signTransaction_async(
|
||||
this.getPath(),
|
||||
t.serialize().toString('hex')
|
||||
);
|
||||
|
||||
const serializedTx = new EthTx(txToSerialize).serialize();
|
||||
resolve(serializedTx);
|
||||
})
|
||||
.catch(err => {
|
||||
return reject(Error(err + '. Check to make sure contract data is on'));
|
||||
});
|
||||
});
|
||||
const txToSerialize: TxObj = {
|
||||
...txFields,
|
||||
v: addHexPrefix(result.v),
|
||||
r: addHexPrefix(result.r),
|
||||
s: addHexPrefix(result.s)
|
||||
};
|
||||
|
||||
return new EthTx(txToSerialize).serialize();
|
||||
} catch (err) {
|
||||
throw Error(err + '. Check to make sure contract data is on');
|
||||
}
|
||||
}
|
||||
|
||||
// modeled after
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import EthTx from 'ethereumjs-tx';
|
||||
import { makeRequest } from './requests';
|
||||
import {
|
||||
EnclaveMethods,
|
||||
|
@ -18,7 +19,7 @@ const api = {
|
|||
return makeRequest<GetChainCodeResponse>(EnclaveMethods.GET_CHAIN_CODE, params);
|
||||
},
|
||||
|
||||
signTransaction(params: SignTransactionParams) {
|
||||
async signTransaction(params: SignTransactionParams) {
|
||||
return makeRequest<SignTransactionResponse>(EnclaveMethods.SIGN_TRANSACTION, params);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import { getWalletLib } from 'shared/enclave/server/wallets';
|
||||
import { SignTransactionParams, SignTransactionResponse } from 'shared/enclave/types';
|
||||
|
||||
export default function(params: SignTransactionParams): SignTransactionResponse {
|
||||
console.log('Sign transaction called with', params);
|
||||
return {
|
||||
s: 'test',
|
||||
v: 'test',
|
||||
r: 'test'
|
||||
};
|
||||
const wallet = getWalletLib(params.walletType);
|
||||
return wallet.signTransaction(params.transaction, params.path);
|
||||
}
|
||||
|
|
|
@ -31,23 +31,6 @@ export function registerServer(app: App) {
|
|||
cb(JSON.stringify(res));
|
||||
});
|
||||
});
|
||||
|
||||
// Fix trezord requests for every new browser window
|
||||
app.on('web-contents-created', (_, webContents) => {
|
||||
const { session } = webContents;
|
||||
if (!session.webRequest) {
|
||||
return;
|
||||
}
|
||||
session.webRequest.onBeforeSendHeaders((details: any, callback: any) => {
|
||||
const url = details.url;
|
||||
if (url.startsWith('https://localback.net:21324')) {
|
||||
if (details.requestHeaders.Origin === 'null') {
|
||||
delete details.requestHeaders.Origin;
|
||||
}
|
||||
}
|
||||
callback({ cancel: false, requestHeaders: details.requestHeaders });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getMethod(req: Electron.RegisterStringProtocolRequest): EnclaveMethods {
|
||||
|
|
|
@ -1,10 +1,22 @@
|
|||
import { WalletLib } from 'shared/enclave/types';
|
||||
import EthTx from 'ethereumjs-tx';
|
||||
import { addHexPrefix, toBuffer } from 'ethereumjs-util';
|
||||
import { WalletLib, RawTransaction } from 'shared/enclave/types';
|
||||
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
|
||||
import LedgerEth from '@ledgerhq/hw-app-eth';
|
||||
|
||||
async function getEthApp() {
|
||||
const transport = await TransportNodeHid.create();
|
||||
return new LedgerEth(transport);
|
||||
try {
|
||||
const transport = await TransportNodeHid.create();
|
||||
return new LedgerEth(transport);
|
||||
} catch (err) {
|
||||
console.log(err.message);
|
||||
if (err && err.message && err.message.includes('cannot open device with path')) {
|
||||
throw new Error(
|
||||
'Failed to connect with your Ledger. It may be in use with another application. Try plugging the device back in.'
|
||||
);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
const Ledger: WalletLib = {
|
||||
|
@ -17,9 +29,29 @@ const Ledger: WalletLib = {
|
|||
chainCode: res.chainCode
|
||||
};
|
||||
} catch (err) {
|
||||
console.log('wtf', err);
|
||||
throw new Error('Failed to connect to Ledger');
|
||||
}
|
||||
},
|
||||
|
||||
async signTransaction(tx: RawTransaction, path: string) {
|
||||
const app = await getEthApp();
|
||||
const ethTx = new EthTx({
|
||||
...tx,
|
||||
v: Buffer.from([tx.chainId]),
|
||||
r: toBuffer(0),
|
||||
s: toBuffer(0)
|
||||
});
|
||||
|
||||
const rsv = await app.signTransaction(path, ethTx.serialize().toString('hex'));
|
||||
const signedTx = new EthTx({
|
||||
...tx,
|
||||
r: addHexPrefix(rsv.r),
|
||||
s: addHexPrefix(rsv.s),
|
||||
v: addHexPrefix(rsv.v)
|
||||
});
|
||||
return {
|
||||
signedTransaction: signedTx.serialize().toString('hex')
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,6 +14,10 @@ const Trezor: WalletLib = {
|
|||
// });
|
||||
//
|
||||
// return { chainCode: 'test', publicKey: 'test' };
|
||||
},
|
||||
|
||||
async signTransaction() {
|
||||
throw new Error('Not yet implemented');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -11,6 +11,16 @@ export enum WalletTypes {
|
|||
KEEPKEY = 'keepkey'
|
||||
}
|
||||
|
||||
export interface RawTransaction {
|
||||
chainId: number;
|
||||
gasLimit: string;
|
||||
gasPrice: string;
|
||||
to: string;
|
||||
nonce: string;
|
||||
data: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
// Get Addresses Request
|
||||
export interface GetAddressesParams {
|
||||
walletType: WalletTypes;
|
||||
|
@ -33,14 +43,13 @@ export interface GetChainCodeResponse {
|
|||
|
||||
// Sign Transaction Request
|
||||
export interface SignTransactionParams {
|
||||
walletType: WalletTypes;
|
||||
transaction: RawTransaction;
|
||||
path: string;
|
||||
rawTxHex: string;
|
||||
}
|
||||
|
||||
export interface SignTransactionResponse {
|
||||
s: string;
|
||||
v: string;
|
||||
r: string;
|
||||
signedTransaction: string;
|
||||
}
|
||||
|
||||
// All Requests & Responses
|
||||
|
@ -72,4 +81,5 @@ export type EnclaveResponse<T = EnclaveMethodResponse> =
|
|||
// Wallet lib
|
||||
export interface WalletLib {
|
||||
getChainCode(dpath: string): Promise<GetChainCodeResponse>;
|
||||
signTransaction(transaction: RawTransaction, path: string): Promise<SignTransactionResponse>;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue