@@ -7,10 +7,11 @@ import nock from 'nock';
77import * as secp256k1 from 'secp256k1' ;
88import * as should from 'should' ;
99import { Polygon , Tpolygon , TransactionBuilder , TransferBuilder } from '../../src' ;
10+ import { AbstractEthLikeNewCoins , UnsignedSweepTxMPCv2 , OfflineVaultTxInfo , optionalDeps } from '@bitgo/abstract-eth' ;
1011import { getBuilder } from '../getBuilder' ;
1112import * as mockData from '../fixtures/polygon' ;
12- import { OfflineVaultTxInfo , optionalDeps } from '@bitgo/abstract-eth' ;
1313import * as sjcl from '@bitgo/sjcl' ;
14+ import assert from 'assert' ;
1415
1516nock . enableNetConnect ( ) ;
1617
@@ -756,53 +757,6 @@ describe('Polygon', function () {
756757 recovery . should . have . property ( 'tx' ) ;
757758 } ) ;
758759
759- it ( 'should construct an unsigned sweep tx with TSS' , async function ( ) {
760- const backupKeyAddress = '0xe7406dc43d13f698fb41a345c7783d39a4c2d191' ;
761- nock ( baseUrl )
762- . get ( '/api' )
763- . query ( mockData . getTxListRequest ( backupKeyAddress ) )
764- . reply ( 200 , mockData . getTxListResponse ) ;
765- nock ( baseUrl )
766- . get ( '/api' )
767- . query ( mockData . getBalanceRequest ( backupKeyAddress ) )
768- . reply ( 200 , mockData . getBalanceResponse ) ;
769-
770- const basecoin = bitgo . coin ( 'tpolygon' ) as Polygon ;
771-
772- const userKey = '03f8606a595917de4cf2244e27b7fba172505469392ad385d2dd2b3588a6bb878c' ;
773- const backupKey = '03f8606a595917de4cf2244e27b7fba172505469392ad385d2dd2b3588a6bb878c' ;
774-
775- const recoveryParams = {
776- userKey : userKey ,
777- backupKey : backupKey ,
778- walletContractAddress : '0xe7406dc43d13f698fb41a345c7783d39a4c2d191' ,
779- recoveryDestination : '0xac05da78464520aa7c9d4c19bd7a440b111b3054' ,
780- walletPassphrase : TestBitGo . V2 . TEST_RECOVERY_PASSCODE ,
781- isTss : true ,
782- gasPrice : 20000000000 ,
783- gasLimit : 500000 ,
784- replayProtectionOptions : {
785- chain : 80002 ,
786- hardfork : 'london' ,
787- } ,
788- } ;
789-
790- const transaction = ( await basecoin . recover ( recoveryParams ) ) as OfflineVaultTxInfo ;
791- should . exist ( transaction ) ;
792- transaction . should . have . property ( 'tx' ) ;
793- transaction . should . have . property ( 'expireTime' ) ;
794- transaction . should . have . property ( 'gasLimit' ) ;
795- transaction . gasLimit . should . equal ( '500000' ) ;
796- transaction . should . have . property ( 'gasPrice' ) ;
797- transaction . gasPrice . should . equal ( '20000000000' ) ;
798- transaction . should . have . property ( 'recipient' ) ;
799- const recipient = ( transaction as any ) . recipient as Recipient ;
800- recipient . should . have . property ( 'address' ) ;
801- recipient . address . should . equal ( '0xac05da78464520aa7c9d4c19bd7a440b111b3054' ) ;
802- recipient . should . have . property ( 'amount' ) ;
803- recipient . amount . should . equal ( '9989999999999999928' ) ;
804- } ) ;
805-
806760 it ( 'should be able to second sign' , async function ( ) {
807761 const walletContractAddress = TestBitGo . V2 . TEST_ETH_WALLET_FIRST_ADDRESS as string ;
808762 const backupKeyAddress = '0x4f2c4830cc37f2785c646f89ded8a919219fa0e9' ;
@@ -1212,4 +1166,153 @@ describe('Polygon', function () {
12121166 transaction . halfSigned ?. should . have . property ( 'recipients' ) ;
12131167 } ) ;
12141168 } ) ;
1169+
1170+ describe ( 'Non-BitGo Recovery for Hot Wallets (MPCv2)' , function ( ) {
1171+ const baseUrl = 'https://api-amoy.polygonscan.com' ;
1172+
1173+ it ( 'should build a recovery transaction for MPCv2 kind of hot wallets' , async function ( ) {
1174+ nock ( baseUrl )
1175+ . get ( '/api' )
1176+ . query ( mockData . getTxListRequest ( mockData . getNonBitGoRecoveryForHotWalletsMPCv2 ( ) . bitgoFeeAddress ) )
1177+ . reply ( 200 , mockData . getTxListResponse ) ;
1178+
1179+ nock ( baseUrl )
1180+ . get ( '/api' )
1181+ . query ( mockData . getBalanceRequest ( mockData . getNonBitGoRecoveryForHotWalletsMPCv2 ( ) . bitgoFeeAddress ) )
1182+ . reply ( 200 , mockData . getBalanceResponse ) ;
1183+
1184+ nock ( baseUrl )
1185+ . get ( '/api' )
1186+ . query ( mockData . getBalanceRequest ( mockData . getNonBitGoRecoveryForHotWalletsMPCv2 ( ) . walletContractAddress ) )
1187+ . reply ( 200 , mockData . getBalanceResponse ) ;
1188+
1189+ const params = mockData . getNonBitGoRecoveryForHotWalletsMPCv2 ( ) ;
1190+
1191+ const transaction = await ( basecoin as AbstractEthLikeNewCoins ) . recover ( {
1192+ userKey : params . userKey ,
1193+ backupKey : params . backupKey ,
1194+ walletPassphrase : params . walletPassphrase ,
1195+ walletContractAddress : params . walletContractAddress ,
1196+ bitgoFeeAddress : params . bitgoFeeAddress ,
1197+ recoveryDestination : params . recoveryDestination ,
1198+ eip1559 : { maxFeePerGas : 20000000000 , maxPriorityFeePerGas : 10000000000 } ,
1199+ gasLimit : 500000 ,
1200+ isTss : true ,
1201+ bitgoDestinationAddress : params . bitgoDestinationAddress ,
1202+ replayProtectionOptions : { chain : 80002 , hardfork : 'london' } ,
1203+ intendedChain : params . intendedChain ,
1204+ } ) ;
1205+ should . exist ( transaction ) ;
1206+ transaction . should . have . property ( 'tx' ) ;
1207+ } ) ;
1208+ it ( 'should throw an error for invalid user key' , async function ( ) {
1209+ const params = mockData . getInvalidNonBitGoRecoveryParams ( ) ;
1210+
1211+ await assert . rejects (
1212+ async ( ) => {
1213+ await ( basecoin as AbstractEthLikeNewCoins ) . recover ( {
1214+ userKey : params . userKey ,
1215+ backupKey : params . backupKey ,
1216+ walletPassphrase : params . walletPassphrase ,
1217+ walletContractAddress : params . walletContractAddress ,
1218+ bitgoFeeAddress : params . bitgoFeeAddress ,
1219+ recoveryDestination : params . recoveryDestination ,
1220+ eip1559 : { maxFeePerGas : 20000000000 , maxPriorityFeePerGas : 10000000000 } ,
1221+ gasLimit : 500000 ,
1222+ bitgoDestinationAddress : params . bitgoDestinationAddress ,
1223+ intendedChain : params . intendedChain ,
1224+ } ) ;
1225+ } ,
1226+ Error ,
1227+ 'user key is invalid'
1228+ ) ;
1229+ } ) ;
1230+ } ) ;
1231+
1232+ describe ( 'Build Unsigned Sweep for Self-Custody Cold Wallets (MPCv2)' , function ( ) {
1233+ const baseUrl = 'https://api-amoy.polygonscan.com' ;
1234+
1235+ it ( 'should generate an unsigned sweep without derivation seed' , async function ( ) {
1236+ nock ( baseUrl )
1237+ . get ( '/api' )
1238+ . query ( mockData . getTxListRequest ( mockData . getBuildUnsignedSweepForSelfCustodyColdWalletsMPCv2 ( ) . address ) )
1239+ . reply ( 200 , mockData . getTxListResponse ) ;
1240+
1241+ nock ( baseUrl )
1242+ . get ( '/api' )
1243+ . query ( mockData . getBalanceRequest ( mockData . getBuildUnsignedSweepForSelfCustodyColdWalletsMPCv2 ( ) . address ) )
1244+ . reply ( 200 , mockData . getBalanceResponse ) ;
1245+
1246+ nock ( baseUrl )
1247+ . get ( '/api' )
1248+ . query (
1249+ mockData . getBalanceRequest (
1250+ mockData . getBuildUnsignedSweepForSelfCustodyColdWalletsMPCv2 ( ) . walletContractAddress
1251+ )
1252+ )
1253+ . reply ( 200 , mockData . getBalanceResponse ) ;
1254+
1255+ const params = mockData . getBuildUnsignedSweepForSelfCustodyColdWalletsMPCv2 ( ) ;
1256+ const sweepResult = await ( basecoin as AbstractEthLikeNewCoins ) . recover ( {
1257+ userKey : params . commonKeyChain ,
1258+ backupKey : params . commonKeyChain ,
1259+ recoveryDestination : params . recoveryDestination ,
1260+ gasLimit : 200000 ,
1261+ eip1559 : { maxFeePerGas : 20000000000 , maxPriorityFeePerGas : 10000000000 } ,
1262+ walletContractAddress : params . walletContractAddress ,
1263+ isTss : true ,
1264+ replayProtectionOptions : {
1265+ chain : '137' ,
1266+ hardfork : 'london' ,
1267+ } ,
1268+ } ) ;
1269+
1270+ should . exist ( sweepResult ) ;
1271+ const output = sweepResult as UnsignedSweepTxMPCv2 ;
1272+ output . should . have . property ( 'txRequests' ) ;
1273+ output . txRequests . should . have . length ( 1 ) ;
1274+ output . txRequests [ 0 ] . should . have . property ( 'transactions' ) ;
1275+ output . txRequests [ 0 ] . transactions . should . have . length ( 1 ) ;
1276+ output . txRequests [ 0 ] . should . have . property ( 'walletCoin' ) ;
1277+ output . txRequests [ 0 ] . transactions [ 0 ] . should . have . property ( 'unsignedTx' ) ;
1278+ output . txRequests [ 0 ] . transactions [ 0 ] . unsignedTx . should . have . property ( 'serializedTxHex' ) ;
1279+ output . txRequests [ 0 ] . transactions [ 0 ] . unsignedTx . should . have . property ( 'signableHex' ) ;
1280+ output . txRequests [ 0 ] . transactions [ 0 ] . unsignedTx . should . have . property ( 'derivationPath' ) ;
1281+ output . txRequests [ 0 ] . transactions [ 0 ] . unsignedTx . should . have . property ( 'feeInfo' ) ;
1282+ output . txRequests [ 0 ] . transactions [ 0 ] . unsignedTx . should . have . property ( 'parsedTx' ) ;
1283+ const parsedTx = output . txRequests [ 0 ] . transactions [ 0 ] . unsignedTx . parsedTx as { spendAmount : string } ;
1284+ parsedTx . should . have . property ( 'spendAmount' ) ;
1285+ ( output . txRequests [ 0 ] . transactions [ 0 ] . unsignedTx . parsedTx as { outputs : any [ ] } ) . should . have . property ( 'outputs' ) ;
1286+ } ) ;
1287+
1288+ it ( 'should throw an error for invalid address' , async function ( ) {
1289+ const params = mockData . getBuildUnsignedSweepForSelfCustodyColdWalletsMPCv2 ( ) ;
1290+ params . recoveryDestination = 'invalidAddress' ;
1291+
1292+ params . userKey =
1293+ '0234eb39b22fed523ece7c78da29ba1f1de5b64a6e48013e0914de793bc1df0570e779de04758732734d97e54b782c8b336283811af6a2c57bd81438798e1c2446' ;
1294+ params . backupKey =
1295+ '0234eb39b22fed523ece7c78da29ba1f1de5b64a6e48013e0914de793bc1df0570e779de04758732734d97e54b782c8b336283811af6a2c57bd81438798e1c2446' ;
1296+
1297+ await assert . rejects (
1298+ async ( ) => {
1299+ await ( basecoin as AbstractEthLikeNewCoins ) . recover ( {
1300+ recoveryDestination : params . recoveryDestination ,
1301+ gasLimit : 2000 ,
1302+ eip1559 : { maxFeePerGas : 200 , maxPriorityFeePerGas : 10000 } ,
1303+ userKey : params . userKey ,
1304+ backupKey : params . backupKey ,
1305+ walletContractAddress : params . walletContractAddress ,
1306+ isTss : true ,
1307+ replayProtectionOptions : {
1308+ chain : '137' ,
1309+ hardfork : 'london' ,
1310+ } ,
1311+ } ) ;
1312+ } ,
1313+ Error ,
1314+ 'Error: invalid address'
1315+ ) ;
1316+ } ) ;
1317+ } ) ;
12151318} ) ;
0 commit comments