@@ -3255,6 +3255,86 @@ describe('SOL:', function () {
32553255 should . equal ( addSignatureSpy . firstCall . args [ 0 ] . pub , mpcV2WalletAddress ) ;
32563256 } ) ;
32573257 } ) ;
3258+
3259+ describe ( 'recoverNestedAta' , ( ) => {
3260+ let nestedAtaMpcV2Params : SolRecoveryOptions ;
3261+
3262+ before ( function ( ) {
3263+ nestedAtaMpcV2Params = {
3264+ userKey : mpcV2UserKey ,
3265+ backupKey : mpcV2BackupKey ,
3266+ bitgoKey : mpcV2CommonKeyChain ,
3267+ recoveryDestination : testData . closeATAkeys . destinationPubKey ,
3268+ walletPassphrase : testData . keys . walletPassword ,
3269+ nestedAtaAddress : 'FGuZSBhtreqSUsE86xokyjKz2i8VBtJzy6uMXXKyGHug' ,
3270+ ownerAtaAddress : 'Zfm98ZpVafydhFTYcsY6bHgubhB4cFgWFvbdEJxYhTA' ,
3271+ tokenMintAddress : 'ZBCNpuD7YMXzTHB2fhGkGi78MNsHGLRXUhRewNRm9RU' ,
3272+ } ;
3273+ } ) ;
3274+
3275+ beforeEach ( ( ) => {
3276+ mpcV2SandBox . stub ( Sol . prototype , 'broadcastTransaction' as keyof Sol ) . resolves ( {
3277+ txId : testData . SolResponses . broadcastTransactionResponse . body . result ,
3278+ } ) ;
3279+ } ) ;
3280+
3281+ it ( 'should recover nested ATA with MPCv2 keycard using MPS-derived wallet address' , async function ( ) {
3282+ const getTSSSignatureSpy = mpcV2SandBox . spy ( EDDSAMethods , 'getTSSSignature' ) ;
3283+
3284+ const result = await basecoin . recoverNestedAta ( nestedAtaMpcV2Params ) ;
3285+
3286+ result . should . not . be . empty ( ) ;
3287+ should . equal ( result . txId , testData . SolResponses . broadcastTransactionResponse . body . result ) ;
3288+ should . equal (
3289+ callBack . getCalls ( ) . find ( ( call ) => call . args [ 0 ] ?. payload ?. method === 'getLatestBlockhash' ) !== undefined ,
3290+ true
3291+ ) ;
3292+ mpcV2SandBox . assert . notCalled ( getTSSSignatureSpy ) ;
3293+ } ) ;
3294+
3295+ it ( 'should recover nested ATA with MPCv1 keycard using MPC.deriveUnhardened (regression)' , async function ( ) {
3296+ const getTSSSignatureSpy = mpcV2SandBox . spy ( EDDSAMethods , 'getTSSSignature' ) ;
3297+
3298+ const result = await basecoin . recoverNestedAta ( {
3299+ userKey : testData . closeATAkeys . userKey ,
3300+ backupKey : testData . closeATAkeys . backupKey ,
3301+ bitgoKey : testData . closeATAkeys . bitgoKey ,
3302+ recoveryDestination : testData . closeATAkeys . destinationPubKey ,
3303+ walletPassphrase : testData . closeATAkeys . walletPassword ,
3304+ nestedAtaAddress : 'FGuZSBhtreqSUsE86xokyjKz2i8VBtJzy6uMXXKyGHug' ,
3305+ ownerAtaAddress : 'Zfm98ZpVafydhFTYcsY6bHgubhB4cFgWFvbdEJxYhTA' ,
3306+ tokenMintAddress : 'ZBCNpuD7YMXzTHB2fhGkGi78MNsHGLRXUhRewNRm9RU' ,
3307+ } ) ;
3308+
3309+ result . should . not . be . empty ( ) ;
3310+ should . equal ( result . txId , testData . SolResponses . broadcastTransactionResponse . body . result ) ;
3311+ mpcV2SandBox . assert . calledOnce ( getTSSSignatureSpy ) ;
3312+ } ) ;
3313+
3314+ it ( 'should throw when MPCv2 recoverNestedAta bitgoKey does not match keycard commonKeyChain' , async function ( ) {
3315+ await basecoin
3316+ . recoverNestedAta ( { ...nestedAtaMpcV2Params , bitgoKey : mismatchedBitgoKey } )
3317+ . should . be . rejectedWith ( 'EdDSA MPCv2 recovery: commonKeyChain from keycard does not match bitgoKey' ) ;
3318+ } ) ;
3319+
3320+ it ( 'should throw when nestedAtaAddress is missing for recoverNestedAta MPCv2' , async function ( ) {
3321+ await basecoin
3322+ . recoverNestedAta ( {
3323+ ...nestedAtaMpcV2Params ,
3324+ nestedAtaAddress : undefined ,
3325+ } )
3326+ . should . be . rejectedWith ( 'invalid nestedAtaAddress' ) ;
3327+ } ) ;
3328+
3329+ it ( 'should throw when ownerAtaAddress is missing for recoverNestedAta MPCv2' , async function ( ) {
3330+ await basecoin
3331+ . recoverNestedAta ( {
3332+ ...nestedAtaMpcV2Params ,
3333+ ownerAtaAddress : undefined ,
3334+ } )
3335+ . should . be . rejectedWith ( 'invalid ownerAtaAddress' ) ;
3336+ } ) ;
3337+ } ) ;
32583338 } ) ;
32593339
32603340 describe ( 'Build Consolidation Recoveries:' , ( ) => {
0 commit comments