diff --git a/src/background/controller/provider/rpcFlow.ts b/src/background/controller/provider/rpcFlow.ts index 74dae649a2b..fb4c4cdb93c 100644 --- a/src/background/controller/provider/rpcFlow.ts +++ b/src/background/controller/provider/rpcFlow.ts @@ -318,7 +318,6 @@ const flowContext = flow flow.requestedApproval = false; // only unlock notification if current flow is an approval flow notificationService.unLock(); - keyringService.resetResend(); } return gnosisController.watchMessage({ address: safeMessage.safeAddress, @@ -385,7 +384,6 @@ export default (request: ProviderRequest) => { flow.requestedApproval = false; // only unlock notification if current flow is an approval flow notificationService.unLock(); - keyringService.resetResend(); } }); }; diff --git a/src/background/controller/wallet.ts b/src/background/controller/wallet.ts index b8f789732ab..72cc5594d06 100644 --- a/src/background/controller/wallet.ts +++ b/src/background/controller/wallet.ts @@ -2630,15 +2630,6 @@ export class WalletController extends BaseController { return null; }; - resendWalletConnect = (account: Account) => { - const keyringType = KEYRING_CLASS.WALLETCONNECT; - const keyring: WalletConnectKeyring = this._getKeyringByType(keyringType); - if (keyring) { - return keyring.resend(account); - } - return null; - }; - getWalletConnectSessionStatus = (address: string, brandName: string) => { const keyringType = brandName === KEYRING_CLASS.Coinbase diff --git a/src/background/service/keyring/eth-bitbox02-keyring/eth-bitbox02-keyring.ts b/src/background/service/keyring/eth-bitbox02-keyring/eth-bitbox02-keyring.ts index e9d52fe1fb1..b19dcc8221d 100644 --- a/src/background/service/keyring/eth-bitbox02-keyring/eth-bitbox02-keyring.ts +++ b/src/background/service/keyring/eth-bitbox02-keyring/eth-bitbox02-keyring.ts @@ -11,7 +11,6 @@ import { AccessListEIP2930Transaction, } from '@ethereumjs/tx'; import { EVENTS } from '@/constant'; -import { SignHelper } from '../helper'; import { BitBox02BridgeInterface } from './bitbox02-bridge-interface'; const hdPathString = "m/44'/60'/0'/0"; @@ -28,9 +27,6 @@ class BitBox02Keyring extends EventEmitter { unlockedAccount = 0; paths = {}; hdPath = ''; - signHelper = new SignHelper({ - errorEventName: EVENTS.COMMON_HARDWARE.REJECTED, - }); bridge!: BitBox02BridgeInterface; @@ -66,10 +62,6 @@ class BitBox02Keyring extends EventEmitter { return Promise.resolve(); } - resend() { - this.signHelper.resend(); - } - async init() { await this.bridge.init(this.hdPath); } @@ -178,53 +170,51 @@ class BitBox02Keyring extends EventEmitter { // tx is an instance of the ethereumjs-transaction class. async signTransaction(address, tx: TypedTransaction) { - return this.signHelper.invoke(async () => { - await this.init(); - - let result; - const txData: JsonTx = { - to: tx.to!.toString(), - value: `0x${tx.value.toString('hex')}`, - data: this._normalize(tx.data), - nonce: `0x${tx.nonce.toString('hex')}`, - gasLimit: `0x${tx.gasLimit.toString('hex')}`, - }; + await this.init(); - if (tx instanceof FeeMarketEIP1559Transaction) { - result = await this.bridge.ethSign1559Transaction( - this._pathFromAddress(address), - tx.toJSON() - ); - txData.type = '0x02'; - txData.maxPriorityFeePerGas = `0x${tx.maxPriorityFeePerGas.toString( - 'hex' - )}`; - txData.maxFeePerGas = `0x${tx.maxFeePerGas.toString('hex')}`; - } else if ( - tx instanceof Transaction || - tx instanceof AccessListEIP2930Transaction - ) { - result = await this.bridge.ethSignTransaction( - tx.common.chainIdBN().toNumber(), - this._pathFromAddress(address), - tx.toJSON() - ); - txData.gasPrice = `0x${tx.gasPrice.toString('hex')}`; - } - txData.chainId = `0x${tx.common.chainIdBN().toString('hex')}`; - txData.r = result.r; - txData.s = result.s; - txData.v = result.v; - const signedTx = TransactionFactory.fromTxData(txData); - const addressSignedWith = ethUtil.toChecksumAddress( - signedTx.getSenderAddress().toString() + let result; + const txData: JsonTx = { + to: tx.to!.toString(), + value: `0x${tx.value.toString('hex')}`, + data: this._normalize(tx.data), + nonce: `0x${tx.nonce.toString('hex')}`, + gasLimit: `0x${tx.gasLimit.toString('hex')}`, + }; + + if (tx instanceof FeeMarketEIP1559Transaction) { + result = await this.bridge.ethSign1559Transaction( + this._pathFromAddress(address), + tx.toJSON() ); - const correctAddress = ethUtil.toChecksumAddress(address); - if (addressSignedWith !== correctAddress) { - throw new Error('signature doesnt match the right address'); - } - return signedTx; - }); + txData.type = '0x02'; + txData.maxPriorityFeePerGas = `0x${tx.maxPriorityFeePerGas.toString( + 'hex' + )}`; + txData.maxFeePerGas = `0x${tx.maxFeePerGas.toString('hex')}`; + } else if ( + tx instanceof Transaction || + tx instanceof AccessListEIP2930Transaction + ) { + result = await this.bridge.ethSignTransaction( + tx.common.chainIdBN().toNumber(), + this._pathFromAddress(address), + tx.toJSON() + ); + txData.gasPrice = `0x${tx.gasPrice.toString('hex')}`; + } + txData.chainId = `0x${tx.common.chainIdBN().toString('hex')}`; + txData.r = result.r; + txData.s = result.s; + txData.v = result.v; + const signedTx = TransactionFactory.fromTxData(txData); + const addressSignedWith = ethUtil.toChecksumAddress( + signedTx.getSenderAddress().toString() + ); + const correctAddress = ethUtil.toChecksumAddress(address); + if (addressSignedWith !== correctAddress) { + throw new Error('signature doesnt match the right address'); + } + return signedTx; } signMessage(withAccount: string, data: string): Promise { @@ -232,23 +222,21 @@ class BitBox02Keyring extends EventEmitter { } async signPersonalMessage(withAccount, message) { - return this.signHelper.invoke(async () => { - await this.init(); + await this.init(); - const result = await this.bridge.ethSignMessage( - 1, - this._pathFromAddress(withAccount), - message - ); - const sig = Buffer.concat([ - Buffer.from(result.r), - Buffer.from(result.s), - Buffer.from(result.v), - ]); - - const sigHex = `0x${sig.toString('hex')}`; - return sigHex; - }); + const result = await this.bridge.ethSignMessage( + 1, + this._pathFromAddress(withAccount), + message + ); + const sig = Buffer.concat([ + Buffer.from(result.r), + Buffer.from(result.s), + Buffer.from(result.v), + ]); + + const sigHex = `0x${sig.toString('hex')}`; + return sigHex; } async signTypedData(withAccount, data, options: any = {}) { @@ -257,32 +245,30 @@ class BitBox02Keyring extends EventEmitter { `Only version 4 of typed data signing is supported. Provided version: ${options.version}` ); } - return this.signHelper.invoke(async () => { - await this.init(); - const result = await this.bridge.ethSignTypedMessage( - data.domain.chainId || 1, - this._pathFromAddress(withAccount), - data - ); - const sig = Buffer.concat([ - Buffer.from(result.r), - Buffer.from(result.s), - Buffer.from(result.v), - ]); - const sigHex = `0x${sig.toString('hex')}`; - const addressSignedWith = sigUtil.recoverTypedSignature({ - data, - signature: sigHex, - version: options.version, - }); - if ( - ethUtil.toChecksumAddress(addressSignedWith) !== - ethUtil.toChecksumAddress(withAccount) - ) { - throw new Error('The signature doesnt match the right address'); - } - return sigHex; + await this.init(); + const result = await this.bridge.ethSignTypedMessage( + data.domain.chainId || 1, + this._pathFromAddress(withAccount), + data + ); + const sig = Buffer.concat([ + Buffer.from(result.r), + Buffer.from(result.s), + Buffer.from(result.v), + ]); + const sigHex = `0x${sig.toString('hex')}`; + const addressSignedWith = sigUtil.recoverTypedSignature({ + data, + signature: sigHex, + version: options.version, }); + if ( + ethUtil.toChecksumAddress(addressSignedWith) !== + ethUtil.toChecksumAddress(withAccount) + ) { + throw new Error('The signature doesnt match the right address'); + } + return sigHex; } exportAccount(): Promise { diff --git a/src/background/service/keyring/eth-imkey-keyring/eth-imkey-keyring.ts b/src/background/service/keyring/eth-imkey-keyring/eth-imkey-keyring.ts index 30629355bc6..4a5c0e2b19e 100644 --- a/src/background/service/keyring/eth-imkey-keyring/eth-imkey-keyring.ts +++ b/src/background/service/keyring/eth-imkey-keyring/eth-imkey-keyring.ts @@ -1,7 +1,6 @@ import EventEmitter from 'events'; import * as ethUtil from 'ethereumjs-util'; import { FeeMarketEIP1559Transaction, Transaction } from '@ethereumjs/tx'; -import { SignHelper } from '../helper'; import { EVENTS } from '@/constant'; import { is1559Tx } from '@/utils/transaction'; import { bytesToHex } from 'web3-utils'; @@ -64,10 +63,6 @@ export class EthImKeyKeyring extends EventEmitter { bridge!: ImKeyBridgeInterface; - signHelper = new SignHelper({ - errorEventName: EVENTS.COMMON_HARDWARE.REJECTED, - }); - hasHIDPermission = false; constructor( @@ -120,14 +115,6 @@ export class EthImKeyKeyring extends EventEmitter { return this.bridge.invokeApp(method, params); }; - resend() { - this.signHelper.resend(); - } - - resetResend() { - this.signHelper.resetResend(); - } - async unlock() { return await this.bridge.unlock(); } @@ -254,73 +241,71 @@ export class EthImKeyKeyring extends EventEmitter { } // tx is an instance of the ethereumjs-transaction class. - signTransaction(address: string, transaction) { - return this.signHelper.invoke(async () => { - await this.unlock(); - const checksummedAddress = ethUtil.toChecksumAddress(address); - const accountDetail = this.accountDetails[checksummedAddress]; - - const txChainId = getChainId(transaction.common); - const dataHex = transaction.data.toString('hex'); - - const txJSON = transaction.toJSON(); - const is1559 = is1559Tx(txJSON); - - const txData = is1559 - ? { - data: dataHex === '' ? '' : `0x${dataHex}`, - gasLimit: convertToBigint(transaction.gasLimit), - type: convertToBigint(transaction.type.toString()), - accessList: transaction.accessList, - maxFeePerGas: convertToBigint(transaction.maxFeePerGas), - maxPriorityFeePerGas: convertToBigint( - transaction.maxPriorityFeePerGas - ), - nonce: convertToBigint(transaction.nonce), - to: transaction.to!.toString(), - value: convertToBigint(transaction.value), - chainId: txChainId, - path: accountDetail.hdPath, - } - : { - to: transaction.to!.toString(), - value: convertToBigint(transaction.value), - data: dataHex === '' ? '' : `0x${dataHex}`, - nonce: convertToBigint(transaction.nonce), - gasLimit: convertToBigint(transaction.gasLimit), - gasPrice: - typeof (transaction as Transaction).gasPrice !== 'undefined' - ? convertToBigint((transaction as Transaction).gasPrice) - : convertToBigint( - (transaction as FeeMarketEIP1559Transaction).maxFeePerGas - ), - chainId: txChainId, - path: accountDetail.hdPath, - }; - - const { signature, txHash } = await this.invokeApp('signTransaction', [ - txData, - ]); - let decoded; - - if (is1559) { - decoded = ethUtil.rlp.decode('0x' + signature.substring(4), true); - - txJSON.r = bytesToHex(decoded.data[10]); - txJSON.s = bytesToHex(decoded.data[11]); - txJSON.v = bytesToHex(decoded.data[9]); - txJSON.hash = txHash; - return FeeMarketEIP1559Transaction.fromTxData(txJSON); - } else { - decoded = ethUtil.rlp.decode(signature, true); - - txJSON.r = bytesToHex(decoded.data[7]); - txJSON.s = bytesToHex(decoded.data[8]); - txJSON.v = bytesToHex(decoded.data[6]); - txJSON.hash = txHash; - return Transaction.fromTxData(txJSON); - } - }); + async signTransaction(address: string, transaction) { + await this.unlock(); + const checksummedAddress = ethUtil.toChecksumAddress(address); + const accountDetail = this.accountDetails[checksummedAddress]; + + const txChainId = getChainId(transaction.common); + const dataHex = transaction.data.toString('hex'); + + const txJSON = transaction.toJSON(); + const is1559 = is1559Tx(txJSON); + + const txData = is1559 + ? { + data: dataHex === '' ? '' : `0x${dataHex}`, + gasLimit: convertToBigint(transaction.gasLimit), + type: convertToBigint(transaction.type.toString()), + accessList: transaction.accessList, + maxFeePerGas: convertToBigint(transaction.maxFeePerGas), + maxPriorityFeePerGas: convertToBigint( + transaction.maxPriorityFeePerGas + ), + nonce: convertToBigint(transaction.nonce), + to: transaction.to!.toString(), + value: convertToBigint(transaction.value), + chainId: txChainId, + path: accountDetail.hdPath, + } + : { + to: transaction.to!.toString(), + value: convertToBigint(transaction.value), + data: dataHex === '' ? '' : `0x${dataHex}`, + nonce: convertToBigint(transaction.nonce), + gasLimit: convertToBigint(transaction.gasLimit), + gasPrice: + typeof (transaction as Transaction).gasPrice !== 'undefined' + ? convertToBigint((transaction as Transaction).gasPrice) + : convertToBigint( + (transaction as FeeMarketEIP1559Transaction).maxFeePerGas + ), + chainId: txChainId, + path: accountDetail.hdPath, + }; + + const { signature, txHash } = await this.invokeApp('signTransaction', [ + txData, + ]); + let decoded; + + if (is1559) { + decoded = ethUtil.rlp.decode('0x' + signature.substring(4), true); + + txJSON.r = bytesToHex(decoded.data[10]); + txJSON.s = bytesToHex(decoded.data[11]); + txJSON.v = bytesToHex(decoded.data[9]); + txJSON.hash = txHash; + return FeeMarketEIP1559Transaction.fromTxData(txJSON); + } else { + decoded = ethUtil.rlp.decode(signature, true); + + txJSON.r = bytesToHex(decoded.data[7]); + txJSON.s = bytesToHex(decoded.data[8]); + txJSON.v = bytesToHex(decoded.data[6]); + txJSON.hash = txHash; + return Transaction.fromTxData(txJSON); + } } signMessage(withAccount: string, data: string) { @@ -328,43 +313,39 @@ export class EthImKeyKeyring extends EventEmitter { } // For personal_sign, we need to prefix the message: - signPersonalMessage(address: string, message: string) { - return this.signHelper.invoke(async () => { - await this.unlock(); - const checksummedAddress = ethUtil.toChecksumAddress(address); - const accountDetail = this.accountDetails[checksummedAddress]; - - const res = await this.invokeApp('signMessage', [ - accountDetail.hdPath, - message, - checksummedAddress, - true, - ]); - return res?.signature; - }); + async signPersonalMessage(address: string, message: string) { + await this.unlock(); + const checksummedAddress = ethUtil.toChecksumAddress(address); + const accountDetail = this.accountDetails[checksummedAddress]; + + const res = await this.invokeApp('signMessage', [ + accountDetail.hdPath, + message, + checksummedAddress, + true, + ]); + return res?.signature; } async signTypedData(address, data, opts) { - return this.signHelper.invoke(async () => { - await this.unlock(); - const checksummedAddress = ethUtil.toChecksumAddress(address); - const accountDetail = this.accountDetails[checksummedAddress]; - const isV4 = opts.version === 'V4'; - - if (opts.version !== 'V4' && opts.version !== 'V3') { - throw new Error('ImKey only supports V3 and V4 of typed data'); - } + await this.unlock(); + const checksummedAddress = ethUtil.toChecksumAddress(address); + const accountDetail = this.accountDetails[checksummedAddress]; + const isV4 = opts.version === 'V4'; - const eip712HashHexWithoutSha3 = signHashHex(data, isV4); + if (opts.version !== 'V4' && opts.version !== 'V3') { + throw new Error('ImKey only supports V3 and V4 of typed data'); + } - const res = await this.invokeApp('signMessage', [ - accountDetail.hdPath, - eip712HashHexWithoutSha3, - checksummedAddress, - false, - ]); - return res?.signature; - }); + const eip712HashHexWithoutSha3 = signHashHex(data, isV4); + + const res = await this.invokeApp('signMessage', [ + accountDetail.hdPath, + eip712HashHexWithoutSha3, + checksummedAddress, + false, + ]); + return res?.signature; } exportAccount(): Promise { diff --git a/src/background/service/keyring/eth-lattice-keyring/eth-lattice-keyring.ts b/src/background/service/keyring/eth-lattice-keyring/eth-lattice-keyring.ts index c8be8efae92..9f7a0ed8d5b 100644 --- a/src/background/service/keyring/eth-lattice-keyring/eth-lattice-keyring.ts +++ b/src/background/service/keyring/eth-lattice-keyring/eth-lattice-keyring.ts @@ -1,6 +1,6 @@ /* eslint-disable */ import OldLatticeKeyring from '@rabby-wallet/eth-lattice-keyring'; -import { SignHelper, LedgerHDPathType } from '../helper'; +import { LedgerHDPathType } from '../helper'; import { EVENTS } from '@/constant'; import { isSameAddress } from '@/background/utils'; @@ -29,9 +29,6 @@ class LatticeKeyring extends OldLatticeKeyring { appName = 'Rabby'; static type = keyringType; type = keyringType; - signHelper = new SignHelper({ - errorEventName: EVENTS.COMMON_HARDWARE.REJECTED, - }); async _getCreds() { if (!isManifestV3) { @@ -77,32 +74,6 @@ class LatticeKeyring extends OldLatticeKeyring { } } - resend() { - this.signHelper.resend(); - } - - resetResend() { - this.signHelper.resetResend(); - } - - async signTransaction(address, tx) { - return this.signHelper.invoke(async () => { - return super.signTransaction(address, tx); - }); - } - - async signMessage(address, msg) { - return this.signHelper.invoke(async () => { - return super.signMessage(address, msg); - }); - } - - async signTypedData(address, msg, opts) { - return this.signHelper.invoke(async () => { - return super.signTypedData(address, msg, opts); - }); - } - async getCurrentAccounts() { const addrs = await this.getAccounts(); const hdPath = this.hdPath; diff --git a/src/background/service/keyring/eth-ledger-keyring.ts b/src/background/service/keyring/eth-ledger-keyring.ts index c7d4b178e3c..e5eb0483732 100644 --- a/src/background/service/keyring/eth-ledger-keyring.ts +++ b/src/background/service/keyring/eth-ledger-keyring.ts @@ -10,7 +10,7 @@ import { } from '@ethereumjs/tx'; import { EVENTS } from 'consts'; import { isSameAddress } from '@/background/utils'; -import { SignHelper, LedgerHDPathType } from './helper'; +import { LedgerHDPathType } from './helper'; const type = 'Ledger Hardware'; @@ -55,10 +55,6 @@ class LedgerBridgeKeyring { hasHIDPermission: null | boolean; usedHDPathTypeList: Record = {}; - signHelper = new SignHelper({ - errorEventName: EVENTS.LEDGER.REJECTED, - }); - constructor(opts = {}) { this.accountDetails = {}; this.page = 0; @@ -236,71 +232,65 @@ class LedgerBridgeKeyring { delete this.paths[checksummedAddress]; } - resend() { - this.signHelper.resend(); - } - // tx is an instance of the ethereumjs-transaction class. signTransaction(address, tx) { - return this.signHelper.invoke(async () => { - // make sure the previous transaction is cleaned up - - // transactions built with older versions of ethereumjs-tx have a - // getChainId method that newer versions do not. Older versions are mutable - // while newer versions default to being immutable. Expected shape and type - // of data for v, r and s differ (Buffer (old) vs BN (new)) - if (typeof tx.getChainId === 'function') { - // In this version of ethereumjs-tx we must add the chainId in hex format - // to the initial v value. The chainId must be included in the serialized - // transaction which is only communicated to ethereumjs-tx in this - // value. In newer versions the chainId is communicated via the 'Common' - // object. - tx.v = ethUtil.bufferToHex(tx.getChainId()); - tx.r = '0x00'; - tx.s = '0x00'; - - const rawTxHex = tx.serialize().toString('hex'); - - return this._signTransaction(address, rawTxHex, (payload) => { - tx.v = Buffer.from(payload.v, 'hex'); - tx.r = Buffer.from(payload.r, 'hex'); - tx.s = Buffer.from(payload.s, 'hex'); - return tx; - }); - } - // For transactions created by newer versions of @ethereumjs/tx - // Note: https://github.com/ethereumjs/ethereumjs-monorepo/issues/1188 - // It is not strictly necessary to do this additional setting of the v - // value. We should be able to get the correct v value in serialization - // if the above issue is resolved. Until then this must be set before - // calling .serialize(). Note we are creating a temporarily mutable object - // forfeiting the benefit of immutability until this happens. We do still - // return a Transaction that is frozen if the originally provided - // transaction was also frozen. - const messageToSign = tx.getMessageToSign(false); - const rawTxHex = Buffer.isBuffer(messageToSign) - ? messageToSign.toString('hex') - : ethUtil.rlp.encode(messageToSign).toString('hex'); + // make sure the previous transaction is cleaned up + + // transactions built with older versions of ethereumjs-tx have a + // getChainId method that newer versions do not. Older versions are mutable + // while newer versions default to being immutable. Expected shape and type + // of data for v, r and s differ (Buffer (old) vs BN (new)) + if (typeof tx.getChainId === 'function') { + // In this version of ethereumjs-tx we must add the chainId in hex format + // to the initial v value. The chainId must be included in the serialized + // transaction which is only communicated to ethereumjs-tx in this + // value. In newer versions the chainId is communicated via the 'Common' + // object. + tx.v = ethUtil.bufferToHex(tx.getChainId()); + tx.r = '0x00'; + tx.s = '0x00'; + + const rawTxHex = tx.serialize().toString('hex'); + return this._signTransaction(address, rawTxHex, (payload) => { - // Because tx will be immutable, first get a plain javascript object that - // represents the transaction. Using txData here as it aligns with the - // nomenclature of ethereumjs/tx. - const txData = tx.toJSON(); - // The fromTxData utility expects v,r and s to be hex prefixed - txData.v = ethUtil.addHexPrefix(payload.v); - txData.r = ethUtil.addHexPrefix(payload.r); - txData.s = ethUtil.addHexPrefix(payload.s); - // Adopt the 'common' option from the original transaction and set the - // returned object to be frozen if the original is frozen. - if (is1559Tx(txData)) { - return FeeMarketEIP1559Transaction.fromTxData(txData); - } else { - return TransactionFactory.fromTxData(txData, { - common: tx.common, - freeze: Object.isFrozen(tx), - }); - } + tx.v = Buffer.from(payload.v, 'hex'); + tx.r = Buffer.from(payload.r, 'hex'); + tx.s = Buffer.from(payload.s, 'hex'); + return tx; }); + } + // For transactions created by newer versions of @ethereumjs/tx + // Note: https://github.com/ethereumjs/ethereumjs-monorepo/issues/1188 + // It is not strictly necessary to do this additional setting of the v + // value. We should be able to get the correct v value in serialization + // if the above issue is resolved. Until then this must be set before + // calling .serialize(). Note we are creating a temporarily mutable object + // forfeiting the benefit of immutability until this happens. We do still + // return a Transaction that is frozen if the originally provided + // transaction was also frozen. + const messageToSign = tx.getMessageToSign(false); + const rawTxHex = Buffer.isBuffer(messageToSign) + ? messageToSign.toString('hex') + : ethUtil.rlp.encode(messageToSign).toString('hex'); + return this._signTransaction(address, rawTxHex, (payload) => { + // Because tx will be immutable, first get a plain javascript object that + // represents the transaction. Using txData here as it aligns with the + // nomenclature of ethereumjs/tx. + const txData = tx.toJSON(); + // The fromTxData utility expects v,r and s to be hex prefixed + txData.v = ethUtil.addHexPrefix(payload.v); + txData.r = ethUtil.addHexPrefix(payload.r); + txData.s = ethUtil.addHexPrefix(payload.s); + // Adopt the 'common' option from the original transaction and set the + // returned object to be frozen if the original is frozen. + if (is1559Tx(txData)) { + return FeeMarketEIP1559Transaction.fromTxData(txData); + } else { + return TransactionFactory.fromTxData(txData, { + common: tx.common, + freeze: Object.isFrozen(tx), + }); + } }); } @@ -329,39 +319,37 @@ class LedgerBridgeKeyring { // For personal_sign, we need to prefix the message: async signPersonalMessage(withAccount, message) { - return this.signHelper.invoke(async () => { - try { - await this.makeApp(true); - const hdPath = await this.unlockAccountByAddress(withAccount); - const res = await this.app!.signPersonalMessage( - hdPath, - ethUtil.stripHexPrefix(message) - ); - // let v: string | number = res.v - 27; - let v = res.v.toString(16); - if (v.length < 2) { - v = `0${v}`; - } - const signature = `0x${res.r}${res.s}${v}`; - const addressSignedWith = sigUtil.recoverPersonalSignature({ - data: message, - sig: signature, - }); - if ( - ethUtil.toChecksumAddress(addressSignedWith) !== - ethUtil.toChecksumAddress(withAccount) - ) { - throw new Error( - "Ledger: The signature doesn't match the right address" - ); - } - return signature; - } catch (e: any) { + try { + await this.makeApp(true); + const hdPath = await this.unlockAccountByAddress(withAccount); + const res = await this.app!.signPersonalMessage( + hdPath, + ethUtil.stripHexPrefix(message) + ); + // let v: string | number = res.v - 27; + let v = res.v.toString(16); + if (v.length < 2) { + v = `0${v}`; + } + const signature = `0x${res.r}${res.s}${v}`; + const addressSignedWith = sigUtil.recoverPersonalSignature({ + data: message, + sig: signature, + }); + if ( + ethUtil.toChecksumAddress(addressSignedWith) !== + ethUtil.toChecksumAddress(withAccount) + ) { throw new Error( - e.toString() || 'Ledger: Unknown error while signing message' + "Ledger: The signature doesn't match the right address" ); } - }); + return signature; + } catch (e: any) { + throw new Error( + e.toString() || 'Ledger: Unknown error while signing message' + ); + } } async unlockAccountByAddress(address) { @@ -385,82 +373,78 @@ class LedgerBridgeKeyring { } async signTypedData(withAccount, data, options: any = {}) { - return this.signHelper.invoke(async () => { - const isV4 = options.version === 'V4'; - if (!isV4) { - throw new Error( - 'Ledger: Only version 4 of typed data signing is supported' - ); - } - - const hdPath = await this.unlockAccountByAddress(withAccount); - try { - await this.makeApp(true); + const isV4 = options.version === 'V4'; + if (!isV4) { + throw new Error( + 'Ledger: Only version 4 of typed data signing is supported' + ); + } - let res: { - v: number; - s: string; - r: string; - }; + const hdPath = await this.unlockAccountByAddress(withAccount); + try { + await this.makeApp(true); - // https://github.com/LedgerHQ/ledger-live/blob/5bae039273beeeb02d8640d778fd7bf5f7fd3776/libs/coin-evm/src/hw-signMessage.ts#L68C7-L79C10 - try { - res = await this.app!.signEIP712Message(hdPath, data); - } catch (e) { - const shouldFallbackOnHashedMethod = - 'statusText' in e && e.statusText === 'INS_NOT_SUPPORTED'; - if (!shouldFallbackOnHashedMethod) throw e; - - const { - domain, - types, - primaryType, - message, - } = sigUtil.TypedDataUtils.sanitizeData(data); - const domainSeparatorHex = sigUtil.TypedDataUtils.hashStruct( - 'EIP712Domain', - domain, - types, - isV4 - ).toString('hex'); - const hashStructMessageHex = sigUtil.TypedDataUtils.hashStruct( - primaryType as string, - message, - types, - isV4 - ).toString('hex'); - - res = await this.app!.signEIP712HashedMessage( - hdPath, - domainSeparatorHex, - hashStructMessageHex - ); - } + let res: { + v: number; + s: string; + r: string; + }; - let v = res.v.toString(16); - if (v.length < 2) { - v = `0${v}`; - } - const signature = `0x${res.r}${res.s}${v}`; - const addressSignedWith = sigUtil.recoverTypedSignature_v4({ - data, - sig: signature, - }); - if ( - ethUtil.toChecksumAddress(addressSignedWith) !== - ethUtil.toChecksumAddress(withAccount) - ) { - throw new Error( - 'Ledger: The signature doesnt match the right address' - ); - } - return signature; - } catch (e: any) { - throw new Error( - e.toString() || 'Ledger: Unknown error while signing message' + // https://github.com/LedgerHQ/ledger-live/blob/5bae039273beeeb02d8640d778fd7bf5f7fd3776/libs/coin-evm/src/hw-signMessage.ts#L68C7-L79C10 + try { + res = await this.app!.signEIP712Message(hdPath, data); + } catch (e) { + const shouldFallbackOnHashedMethod = + 'statusText' in e && e.statusText === 'INS_NOT_SUPPORTED'; + if (!shouldFallbackOnHashedMethod) throw e; + + const { + domain, + types, + primaryType, + message, + } = sigUtil.TypedDataUtils.sanitizeData(data); + const domainSeparatorHex = sigUtil.TypedDataUtils.hashStruct( + 'EIP712Domain', + domain, + types, + isV4 + ).toString('hex'); + const hashStructMessageHex = sigUtil.TypedDataUtils.hashStruct( + primaryType as string, + message, + types, + isV4 + ).toString('hex'); + + res = await this.app!.signEIP712HashedMessage( + hdPath, + domainSeparatorHex, + hashStructMessageHex ); } - }); + + let v = res.v.toString(16); + if (v.length < 2) { + v = `0${v}`; + } + const signature = `0x${res.r}${res.s}${v}`; + const addressSignedWith = sigUtil.recoverTypedSignature_v4({ + data, + sig: signature, + }); + if ( + ethUtil.toChecksumAddress(addressSignedWith) !== + ethUtil.toChecksumAddress(withAccount) + ) { + throw new Error('Ledger: The signature doesnt match the right address'); + } + return signature; + } catch (e: any) { + throw new Error( + e.toString() || 'Ledger: Unknown error while signing message' + ); + } } exportAccount() { diff --git a/src/background/service/keyring/eth-onekey-keyring/eth-onekey-keyring.ts b/src/background/service/keyring/eth-onekey-keyring/eth-onekey-keyring.ts index c5442c4528e..1021016a061 100644 --- a/src/background/service/keyring/eth-onekey-keyring/eth-onekey-keyring.ts +++ b/src/background/service/keyring/eth-onekey-keyring/eth-onekey-keyring.ts @@ -4,7 +4,6 @@ import * as sigUtil from 'eth-sig-util'; import { TransactionFactory } from '@ethereumjs/tx'; import HDKey from 'hdkey'; import { isSameAddress } from '@/background/utils'; -import { SignHelper } from '../helper'; import { EVENTS } from '@/constant'; import type { EVMTransaction, EVMTransactionEIP1559 } from '@onekeyfe/hd-core'; import { OneKeyBridgeInterface } from './onekey-bridge-interface'; @@ -80,10 +79,6 @@ class OneKeyKeyring extends EventEmitter { bridge!: OneKeyBridgeInterface; - signHelper = new SignHelper({ - errorEventName: EVENTS.COMMON_HARDWARE.REJECTED, - }); - constructor( opts: any & { bridge: OneKeyBridgeInterface; @@ -145,14 +140,6 @@ class OneKeyKeyring extends EventEmitter { this.hdk = new HDKey(); } - resend() { - this.signHelper.resend(); - } - - resetResend() { - this.signHelper.resetResend(); - } - unlock(): Promise { // if (this.isUnlocked()) { // return Promise.resolve('already unlocked'); @@ -357,68 +344,66 @@ class OneKeyKeyring extends EventEmitter { // tx is an instance of the ethereumjs-transaction class. signTransaction(address: string, tx): Promise { - return this.signHelper.invoke(async () => { - return new Promise((resolve, reject) => { - this.unlock() - .then((status) => { - setTimeout( - (_) => { - if (isOldStyleEthereumjsTx(tx)) { - // In this version of ethereumjs-tx we must add the chainId in hex format - // to the initial v value. The chainId must be included in the serialized - // transaction which is only communicated to ethereumjs-tx in this - // value. In newer versions the chainId is communicated via the 'Common' - // object. - this._signTransaction( - address, - tx.getChainId(), - tx, - (payload) => { - tx.v = Buffer.from(payload.v, 'hex'); - tx.r = Buffer.from(payload.r, 'hex'); - tx.s = Buffer.from(payload.s, 'hex'); - return tx; - } - ) - .then(resolve) - .catch(reject); - } else { - this._signTransaction( - address, - Number(tx.common.chainId()), - tx, - (payload) => { - // Because tx will be immutable, first get a plain javascript object that - // represents the transaction. Using txData here as it aligns with the - // nomenclature of ethereumjs/tx. - const txData = tx.toJSON(); - // The fromTxData utility expects a type to support transactions with a type other than 0 - txData.type = tx.type; - // The fromTxData utility expects v,r and s to be hex prefixed - txData.v = ethUtil.addHexPrefix(payload.v); - txData.r = ethUtil.addHexPrefix(payload.r); - txData.s = ethUtil.addHexPrefix(payload.s); - // Adopt the 'common' option from the original transaction and set the - // returned object to be frozen if the original is frozen. - return TransactionFactory.fromTxData(txData, { - common: tx.common, - freeze: Object.isFrozen(tx), - }); - } - ) - .then(resolve) - .catch(reject); - } - // This is necessary to avoid popup collision - // between the unlock & sign trezor popups - }, - status === 'just unlocked' ? DELAY_BETWEEN_POPUPS : 0 - ); - }) - .catch((e) => { - reject(new Error((e && e.toString()) || 'Unknown error')); - }); - }); + return new Promise((resolve, reject) => { + this.unlock() + .then((status) => { + setTimeout( + (_) => { + if (isOldStyleEthereumjsTx(tx)) { + // In this version of ethereumjs-tx we must add the chainId in hex format + // to the initial v value. The chainId must be included in the serialized + // transaction which is only communicated to ethereumjs-tx in this + // value. In newer versions the chainId is communicated via the 'Common' + // object. + this._signTransaction( + address, + tx.getChainId(), + tx, + (payload) => { + tx.v = Buffer.from(payload.v, 'hex'); + tx.r = Buffer.from(payload.r, 'hex'); + tx.s = Buffer.from(payload.s, 'hex'); + return tx; + } + ) + .then(resolve) + .catch(reject); + } else { + this._signTransaction( + address, + Number(tx.common.chainId()), + tx, + (payload) => { + // Because tx will be immutable, first get a plain javascript object that + // represents the transaction. Using txData here as it aligns with the + // nomenclature of ethereumjs/tx. + const txData = tx.toJSON(); + // The fromTxData utility expects a type to support transactions with a type other than 0 + txData.type = tx.type; + // The fromTxData utility expects v,r and s to be hex prefixed + txData.v = ethUtil.addHexPrefix(payload.v); + txData.r = ethUtil.addHexPrefix(payload.r); + txData.s = ethUtil.addHexPrefix(payload.s); + // Adopt the 'common' option from the original transaction and set the + // returned object to be frozen if the original is frozen. + return TransactionFactory.fromTxData(txData, { + common: tx.common, + freeze: Object.isFrozen(tx), + }); + } + ) + .then(resolve) + .catch(reject); + } + // This is necessary to avoid popup collision + // between the unlock & sign trezor popups + }, + status === 'just unlocked' ? DELAY_BETWEEN_POPUPS : 0 + ); + }) + .catch((e) => { + reject(new Error((e && e.toString()) || 'Unknown error')); + }); }); } @@ -479,54 +464,52 @@ class OneKeyKeyring extends EventEmitter { // For personal_sign, we need to prefix the message: signPersonalMessage(withAccount: string, message: string): Promise { - return this.signHelper.invoke(async () => { - return new Promise((resolve, reject) => { - this.unlock() - .then((status) => { - setTimeout( - (_) => { - this.bridge - .evmSignMessage(this.connectId!, this.deviceId!, { - path: this._pathFromAddress(withAccount), - messageHex: ethUtil.stripHexPrefix(message), - passphraseState: this.passphraseState, - }) - .then((response) => { - if (response.success) { - if ( - response.payload.address !== - ethUtil.toChecksumAddress(withAccount) - ) { - reject( - new Error('signature doesnt match the right address') - ); - } - const signature = `0x${response.payload.signature}`; - resolve(signature); - } else { + return new Promise((resolve, reject) => { + this.unlock() + .then((status) => { + setTimeout( + (_) => { + this.bridge + .evmSignMessage(this.connectId!, this.deviceId!, { + path: this._pathFromAddress(withAccount), + messageHex: ethUtil.stripHexPrefix(message), + passphraseState: this.passphraseState, + }) + .then((response) => { + if (response.success) { + if ( + response.payload.address !== + ethUtil.toChecksumAddress(withAccount) + ) { reject( - new Error( - (response.payload && response.payload.error) || - 'Unknown error' - ) + new Error('signature doesnt match the right address') ); } - }) - .catch((e) => { - console.log('Error while trying to sign a message ', e); - reject(new Error((e && e.toString()) || 'Unknown error')); - }); - // This is necessary to avoid popup collision - // between the unlock & sign trezor popups - }, - status === 'just unlocked' ? DELAY_BETWEEN_POPUPS : 0 - ); - }) - .catch((e) => { - console.log('Error while trying to sign a message ', e); - reject(new Error((e && e.toString()) || 'Unknown error')); - }); - }); + const signature = `0x${response.payload.signature}`; + resolve(signature); + } else { + reject( + new Error( + (response.payload && response.payload.error) || + 'Unknown error' + ) + ); + } + }) + .catch((e) => { + console.log('Error while trying to sign a message ', e); + reject(new Error((e && e.toString()) || 'Unknown error')); + }); + // This is necessary to avoid popup collision + // between the unlock & sign trezor popups + }, + status === 'just unlocked' ? DELAY_BETWEEN_POPUPS : 0 + ); + }) + .catch((e) => { + console.log('Error while trying to sign a message ', e); + reject(new Error((e && e.toString()) || 'Unknown error')); + }); }); } @@ -545,9 +528,7 @@ class OneKeyKeyring extends EventEmitter { signTypedData_v1(address, typedData, opts = {}) { // Waiting on trezor to enable this - return this.signHelper.invoke(async () => { - throw new Error('Not supported on this device'); - }); + throw new Error('Not supported on this device'); } // personal_signTypedData, signs data along with the schema @@ -556,107 +537,103 @@ class OneKeyKeyring extends EventEmitter { typedData, opts: { version?: 'V3' | 'V4' } = {} ) { - return this.signHelper.invoke(async () => { - return new Promise((resolve, reject) => { - const isV4 = opts.version === 'V4'; - const { - domain, - types, - primaryType, - message, - } = sigUtil.TypedDataUtils.sanitizeData(typedData); - const domainSeparatorHex = sigUtil.TypedDataUtils.hashStruct( - 'EIP712Domain', - domain, - types, - isV4 - ).toString('hex'); - const hashStructMessageHex = sigUtil.TypedDataUtils.hashStruct( - primaryType as string, - message, - types, - isV4 - ).toString('hex'); - this.unlock() - .then((status) => { - setTimeout( - (_) => { - try { - this.bridge - .evmSignTypedData(this.connectId!, this.deviceId!, { - path: this._pathFromAddress(address), - data: typedData, - passphraseState: this.passphraseState, - metamaskV4Compat: isV4, - domainHash: domainSeparatorHex, - messageHash: hashStructMessageHex, - chainId: domain.chainId - ? Number(domain.chainId) - : undefined, - }) - .then((response) => { - if (response.success) { - if ( - response.payload.address !== - ethUtil.toChecksumAddress(address) - ) { - reject( - new Error( - 'signature doesnt match the right address' - ) - ); - } - const signature = `0x${response.payload.signature}`; - resolve(signature); - } else { - let code = - (response.payload && response.payload.code) || ''; - const message = - (response.payload && response.payload.error) || ''; - let errorMsg = - (response.payload && response.payload.error) || - 'Unknown error'; - - let errorUrl = ''; - if (message.includes('EIP712Domain')) { - code = 'EIP712_DOMAIN_NOT_SUPPORT'; - } else if (message.includes('EIP712')) { - code = 'EIP712_BLIND_SIGN_DISABLED'; - errorUrl = - 'https://help.onekey.so/hc/zh-cn/articles/4406637762959'; - } - if (code === 'Failure_UnexpectedMessage') { - code = 'EIP712_FIRMWARE_NOT_SUPPORT'; - errorMsg = 'Not supported on this device'; - } - - const error = new Error( - JSON.stringify({ - code, - errorMsg, - }) + return new Promise((resolve, reject) => { + const isV4 = opts.version === 'V4'; + const { + domain, + types, + primaryType, + message, + } = sigUtil.TypedDataUtils.sanitizeData(typedData); + const domainSeparatorHex = sigUtil.TypedDataUtils.hashStruct( + 'EIP712Domain', + domain, + types, + isV4 + ).toString('hex'); + const hashStructMessageHex = sigUtil.TypedDataUtils.hashStruct( + primaryType as string, + message, + types, + isV4 + ).toString('hex'); + this.unlock() + .then((status) => { + setTimeout( + (_) => { + try { + this.bridge + .evmSignTypedData(this.connectId!, this.deviceId!, { + path: this._pathFromAddress(address), + data: typedData, + passphraseState: this.passphraseState, + metamaskV4Compat: isV4, + domainHash: domainSeparatorHex, + messageHash: hashStructMessageHex, + chainId: domain.chainId + ? Number(domain.chainId) + : undefined, + }) + .then((response) => { + if (response.success) { + if ( + response.payload.address !== + ethUtil.toChecksumAddress(address) + ) { + reject( + new Error('signature doesnt match the right address') ); - reject(error); } - }) - .catch((e) => { - console.log('Error while trying to sign a message ', e); - reject(new Error((e && e.toString()) || 'Unknown error')); - }); - } catch (e) { - reject(new Error((e && e.toString()) || 'Unknown error')); - } - // This is necessary to avoid popup collision - // between the unlock & sign trezor popups - }, - status === 'just unlocked' ? DELAY_BETWEEN_POPUPS : 0 - ); - }) - .catch((e) => { - console.log('Error while trying to sign a message ', e); - reject(new Error((e && e.toString()) || 'Unknown error')); - }); - }); + const signature = `0x${response.payload.signature}`; + resolve(signature); + } else { + let code = + (response.payload && response.payload.code) || ''; + const message = + (response.payload && response.payload.error) || ''; + let errorMsg = + (response.payload && response.payload.error) || + 'Unknown error'; + + let errorUrl = ''; + if (message.includes('EIP712Domain')) { + code = 'EIP712_DOMAIN_NOT_SUPPORT'; + } else if (message.includes('EIP712')) { + code = 'EIP712_BLIND_SIGN_DISABLED'; + errorUrl = + 'https://help.onekey.so/hc/zh-cn/articles/4406637762959'; + } + if (code === 'Failure_UnexpectedMessage') { + code = 'EIP712_FIRMWARE_NOT_SUPPORT'; + errorMsg = 'Not supported on this device'; + } + + const error = new Error( + JSON.stringify({ + code, + errorMsg, + }) + ); + reject(error); + } + }) + .catch((e) => { + console.log('Error while trying to sign a message ', e); + reject(new Error((e && e.toString()) || 'Unknown error')); + }); + } catch (e) { + reject(new Error((e && e.toString()) || 'Unknown error')); + } + // This is necessary to avoid popup collision + // between the unlock & sign trezor popups + }, + status === 'just unlocked' ? DELAY_BETWEEN_POPUPS : 0 + ); + }) + .catch((e) => { + console.log('Error while trying to sign a message ', e); + reject(new Error((e && e.toString()) || 'Unknown error')); + }); }); } diff --git a/src/background/service/keyring/eth-trezor-keyring/eth-trezor-keyring.ts b/src/background/service/keyring/eth-trezor-keyring/eth-trezor-keyring.ts deleted file mode 100644 index b59ac28384a..00000000000 --- a/src/background/service/keyring/eth-trezor-keyring/eth-trezor-keyring.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { SignHelper } from '../helper'; -import { EVENTS } from '@/constant'; -import OldTrezorKeyring from '@rabby-wallet/eth-trezor-keyring'; - -const keyringType = 'Trezor Hardware'; - -class TrezorKeyring extends OldTrezorKeyring { - static type = keyringType; - signHelper = new SignHelper({ - errorEventName: EVENTS.COMMON_HARDWARE.REJECTED, - }); - - resend() { - this.signHelper.resend(); - } - - resetResend() { - this.signHelper.resetResend(); - } - - signTransaction(address, tx) { - return this.signHelper.invoke(async () => { - return super.signTransaction(address, tx); - }); - } - - signPersonalMessage(withAccount, message) { - return this.signHelper.invoke(async () => { - return super.signPersonalMessage(withAccount, message); - }); - } - - async signTypedData(address, data, { version }): Promise { - return this.signHelper.invoke(async () => { - return super.signTypedData(address, data, { version }); - }); - } -} - -export default TrezorKeyring; diff --git a/src/background/service/keyring/helper.ts b/src/background/service/keyring/helper.ts index 158d062fdc7..266e056b7d8 100644 --- a/src/background/service/keyring/helper.ts +++ b/src/background/service/keyring/helper.ts @@ -1,34 +1,3 @@ -import { EVENTS } from '@/constant'; -import eventBus from '@/eventBus'; -import * as Sentry from '@sentry/browser'; - -export const throwError = (error, method = EVENTS.COMMON_HARDWARE.REJECTED) => { - eventBus.emit(EVENTS.broadcastToUI, { - method, - params: error, - }); -}; -export class SignHelper { - signFn: any; - errorEventName: string; - - constructor(options: { errorEventName: string }) { - this.errorEventName = options.errorEventName; - } - - resend() { - return this.signFn?.(); - } - - resetResend() { - this.signFn = undefined; - } - - async invoke(fn: () => Promise) { - return fn(); - } -} - export enum LedgerHDPathType { LedgerLive = 'LedgerLive', Legacy = 'Legacy', diff --git a/src/background/service/keyring/index.ts b/src/background/service/keyring/index.ts index 365d9b88ea1..112c9a6f82a 100644 --- a/src/background/service/keyring/index.ts +++ b/src/background/service/keyring/index.ts @@ -18,7 +18,7 @@ import BitBox02Keyring from './eth-bitbox02-keyring/eth-bitbox02-keyring'; import LedgerBridgeKeyring from './eth-ledger-keyring'; import { WalletConnectKeyring } from '@rabby-wallet/eth-walletconnect-keyring'; import CoinbaseKeyring from '@rabby-wallet/eth-coinbase-keyring'; -import TrezorKeyring from './eth-trezor-keyring/eth-trezor-keyring'; +import TrezorKeyring from '@rabby-wallet/eth-trezor-keyring'; import OnekeyKeyring from './eth-onekey-keyring/eth-onekey-keyring'; import LatticeKeyring from './eth-lattice-keyring/eth-lattice-keyring'; import KeystoneKeyring from './eth-keystone-keyring'; @@ -1048,12 +1048,6 @@ export class KeyringService extends EventEmitter { return addrs.map(normalizeAddress); } - resetResend() { - this.keyrings.forEach((keyring) => { - keyring?.resetResend?.(); - }); - } - /** * Get Keyring For Account * diff --git a/src/ui/views/Approval/components/WatchAddressWaiting/index.tsx b/src/ui/views/Approval/components/WatchAddressWaiting/index.tsx index 64e72c2a471..564885f7af8 100644 --- a/src/ui/views/Approval/components/WatchAddressWaiting/index.tsx +++ b/src/ui/views/Approval/components/WatchAddressWaiting/index.tsx @@ -102,12 +102,11 @@ const WatchAddressWaiting = ({ params }: { params: ApprovalParams }) => { const account = params.isGnosis ? params.account! : (await wallet.syncGetCurrentAccount())!; - // await wallet.killWalletConnectConnector(account.address, account.brandName); - // await initWalletConnect(); - setConnectStatus(WALLETCONNECT_STATUS_MAP.PENDING); + setConnectStatus(WALLETCONNECT_STATUS_MAP.WAITING); setConnectError(null); - wallet.resendWalletConnect(account); + wallet.resendSign(); message.success(t('page.signFooterBar.walletConnect.requestSuccessToast')); + emitSignComponentAmounted(); }; const handleRefreshQrCode = () => {