@@ -42,6 +42,7 @@ import { getDerivationPath } from '@bitgo/sdk-lib-mpc';
4242import { bip32 } from '@bitgo/secp256k1' ;
4343import {
4444 BaseCoin as StaticsBaseCoin ,
45+ CoinFeature ,
4546 CoinMap ,
4647 coins ,
4748 EthereumNetwork as EthLikeNetwork ,
@@ -50,12 +51,13 @@ import {
5051import type * as EthLikeCommon from '@ethereumjs/common' ;
5152import type * as EthLikeTxLib from '@ethereumjs/tx' ;
5253import { FeeMarketEIP1559Transaction , Transaction as LegacyTransaction } from '@ethereumjs/tx' ;
54+ import { RLP } from '@ethereumjs/rlp' ;
5355import { SignTypedDataVersion , TypedDataUtils , TypedMessage } from '@metamask/eth-sig-util' ;
5456import { BigNumber } from 'bignumber.js' ;
5557import BN from 'bn.js' ;
5658import { randomBytes } from 'crypto' ;
5759import debugLib from 'debug' ;
58- import { addHexPrefix , stripHexPrefix } from 'ethereumjs-util' ;
60+ import { addHexPrefix , bufArrToArr , stripHexPrefix } from 'ethereumjs-util' ;
5961import Keccak from 'keccak' ;
6062import _ from 'lodash' ;
6163import secp256k1 from 'secp256k1' ;
@@ -482,8 +484,8 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
482484 replayProtectionOptions ?: ReplayProtectionOptions
483485 ) : EthLikeCommon . default {
484486 // if eip1559 params are specified, default to london hardfork, otherwise,
485- // default to tangerine whistle to avoid replay protection issues
486- const defaultHardfork = ! ! eip1559 ? 'london' : optionalDeps . EthCommon . Hardfork . TangerineWhistle ;
487+ // default to petersburg to avoid replay protection issues
488+ const defaultHardfork = ! ! eip1559 ? 'london' : optionalDeps . EthCommon . Hardfork . Petersburg ;
487489 const ethLikeCommon = AbstractEthLikeNewCoins . getCustomChainCommon ( replayProtectionOptions ?. chain as number ) ;
488490 ethLikeCommon . setHardfork ( replayProtectionOptions ?. hardfork ?? defaultHardfork ) ;
489491 return ethLikeCommon ;
@@ -1109,6 +1111,15 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
11091111 if ( params . recoveryDestination === undefined || ! this . isValidAddress ( params . recoveryDestination ) ) {
11101112 throw new Error ( 'invalid recoveryDestination' ) ;
11111113 }
1114+
1115+ if ( ! this . staticsCoin ?. features . includes ( CoinFeature . EIP1559 ) ) {
1116+ if ( params . eip1559 ) {
1117+ throw new Error ( 'Invalid fee params. EIP1559 not supported' ) ;
1118+ }
1119+ if ( params . replayProtectionOptions ?. hardfork === 'london' ) {
1120+ throw new Error ( 'Invalid replayProtection options. Cannot use the hardfork "london" for this chain' ) ;
1121+ }
1122+ }
11121123 }
11131124
11141125 /**
@@ -2034,7 +2045,6 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
20342045 let lastScanIndex = 0 ;
20352046
20362047 for ( let i = 0 ; i < req . length ; i ++ ) {
2037- const MPC = new Ecdsa ( ) ;
20382048 const transaction = req [ i ] ?. txRequest ?. transactions ?. [ 0 ] ?. unsignedTx as unknown as UnsignedTransactionTss ;
20392049 if ( ! req [ i ] . ovc || ! req [ i ] . ovc [ 0 ] . ecdsaSignature ) {
20402050 throw new Error ( 'Missing signature(s)' ) ;
@@ -2056,9 +2066,6 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
20562066 s : shares [ 2 ] ,
20572067 y : shares [ 3 ] ,
20582068 } as unknown as ECDSAMethodTypes . Signature ;
2059- const signatureHex = Buffer . from ( signature . toString ( ) , 'hex' ) ;
2060- const txBuilder = this . getTransactionBuilder ( getCommon ( this . getNetwork ( ) as EthLikeNetwork ) ) ;
2061- txBuilder . from ( transaction . serializedTxHex as string ) ;
20622069
20632070 if ( ! transaction . coinSpecific ?. commonKeyChain ) {
20642071 throw new Error ( `Missing common keychain for transaction at index ${ i } ` ) ;
@@ -2071,29 +2078,23 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
20712078 throw new Error ( `Missing common key chain for transaction at index ${ i } ` ) ;
20722079 }
20732080
2074- const derivationPath = transaction . derivationPath ?? 'm/0' ;
2075- const derivedCommonKeyChain = MPC . deriveUnhardened ( String ( commonKeyChain ) , String ( derivationPath ) ) ;
2076- const derivedPublicKey = new KeyPairLib ( { pub : derivedCommonKeyChain . slice ( 0 , 66 ) } ) ;
2077- txBuilder . addSignature ( { pub : derivedPublicKey . getKeys ( ) . pub } , signatureHex ) ;
20782081 const ethCommmon = AbstractEthLikeNewCoins . getEthLikeCommon (
20792082 transaction . eip1559 ,
20802083 transaction . replayProtectionOptions
20812084 ) ;
2082- let unsignedTx ;
2085+ let unsignedTx : EthLikeTxLib . FeeMarketEIP1559Transaction | EthLikeTxLib . Transaction ;
20832086 if ( transaction . eip1559 ) {
2084- unsignedTx = await FeeMarketEIP1559Transaction . fromSerializedTx (
2085- Buffer . from ( transaction . serializedTxHex , 'hex' )
2086- ) ;
2087+ unsignedTx = FeeMarketEIP1559Transaction . fromSerializedTx ( Buffer . from ( transaction . serializedTxHex , 'hex' ) ) ;
20872088 } else {
2088- unsignedTx = await LegacyTransaction . fromSerializedTx ( Buffer . from ( transaction . serializedTxHex , 'hex' ) ) ;
2089+ unsignedTx = LegacyTransaction . fromSerializedTx ( Buffer . from ( transaction . serializedTxHex , 'hex' ) ) ;
20892090 }
20902091 const signedTx = this . getSignedTxFromSignature ( ethCommmon , unsignedTx , finalSignature ) ;
20912092 broadcastableTransactions . push ( {
20922093 serializedTx : addHexPrefix ( signedTx . serialize ( ) . toString ( 'hex' ) ) ,
20932094 } ) ;
20942095
2095- if ( i === req . length - 1 && transaction . coinSpecific ! . lastScanIndex ) {
2096- lastScanIndex = transaction . coinSpecific ! . lastScanIndex as number ;
2096+ if ( i === req . length - 1 && transaction . coinSpecific ? .lastScanIndex ) {
2097+ lastScanIndex = transaction . coinSpecific ? .lastScanIndex as number ;
20972098 }
20982099 }
20992100
@@ -2112,11 +2113,7 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
21122113 if ( ! _ . isUndefined ( params . derivationSeed ) && typeof params . derivationSeed !== 'string' ) {
21132114 throw new Error ( 'invalid derivationSeed' ) ;
21142115 }
2115- if (
2116- _ . isUndefined ( params . bitgoDestinationAddress ) ||
2117- typeof params . bitgoDestinationAddress !== 'string' ||
2118- ! this . isValidAddress ( params . bitgoDestinationAddress )
2119- ) {
2116+ if ( _ . isUndefined ( params . recoveryDestination ) || ! this . isValidAddress ( params . recoveryDestination ) ) {
21202117 throw new Error ( 'missing or invalid destinationAddress' ) ;
21212118 }
21222119 }
@@ -2125,17 +2122,19 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
21252122 * Helper function for recover()
21262123 * This transforms the unsigned transaction information into a format the BitGo offline vault expects
21272124 * @param {UnformattedTxInfo } txInfo - tx info
2128- * @param {EthLikeTxLib.Transaction | EthLikeTxLib. FeeMarketEIP1559Transaction } ethTx - the ethereumjs tx object
2125+ * @param {LegacyTransaction | FeeMarketEIP1559Transaction } ethTx - the ethereumjs tx object
21292126 * @param {string } derivationPath - the derivationPath
21302127 * @param {number } nonce - the nonce of the backup key address
21312128 * @param {Buffer } gasPrice - gas price for the tx
21322129 * @param {number } gasLimit - gas limit for the tx
21332130 * @param {EIP1559 } eip1559 - eip1559 params
2131+ * @param replayProtectionOptions
2132+ * @param commonKeyChain
21342133 * @returns {Promise<OfflineVaultTxInfo> }
21352134 */
21362135 private buildTxRequestForOfflineVaultMPCv2 (
21372136 txInfo : UnformattedTxInfo ,
2138- ethTx : EthLikeTxLib . Transaction | EthLikeTxLib . FeeMarketEIP1559Transaction ,
2137+ ethTx : LegacyTransaction | FeeMarketEIP1559Transaction ,
21392138 derivationPath : string ,
21402139 nonce : number ,
21412140 gasPrice : Buffer ,
@@ -2154,7 +2153,10 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
21542153
21552154 const unsignedTx : UnsignedTransactionTss = {
21562155 serializedTxHex : ethTx . serialize ( ) . toString ( 'hex' ) ,
2157- signableHex : ethTx . getMessageToSign ( false ) . toString ( 'hex' ) ,
2156+ signableHex :
2157+ ethTx instanceof FeeMarketEIP1559Transaction
2158+ ? ethTx . getMessageToSign ( false ) . toString ( 'hex' )
2159+ : Buffer . from ( RLP . encode ( bufArrToArr ( ethTx . getMessageToSign ( false ) ) ) ) . toString ( 'hex' ) ,
21582160 derivationPath : derivationPath ,
21592161 feeInfo : {
21602162 fee : fee ,
@@ -2194,8 +2196,8 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
21942196 }
21952197
21962198 private async buildTssRecoveryTxn ( baseAddress : string , gasPrice : any , gasLimit : any , params : RecoverOptions ) {
2197- const nonce = await this . getAddressNonce ( baseAddress , params . apiKey ) ;
21982199 const txAmount = await this . validateBalanceAndGetTxAmount ( baseAddress , gasPrice , gasLimit , params . apiKey ) ;
2200+ const nonce = await this . getAddressNonce ( baseAddress , params . apiKey ) ;
21992201 const recipients = [
22002202 {
22012203 address : params . recoveryDestination ,
0 commit comments