@@ -178,33 +178,20 @@ describe('WalletRecoverToken codec tests', function () {
178178 }
179179 } ) ;
180180
181- it ( 'should recover tokens without optional recipient (uses default) ' , async function ( ) {
181+ it ( 'should reject request without required recipient field ' , async function ( ) {
182182 const requestBody = {
183183 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
184184 walletPassphrase : 'test_passphrase' ,
185185 } ;
186186
187- const mockWallet = {
188- recoverToken : sinon . stub ( ) . resolves ( mockRecoverTokenResponse ) ,
189- } ;
190-
191- const walletsGetStub = sinon . stub ( ) . resolves ( mockWallet ) ;
192- const mockWallets = { get : walletsGetStub } ;
193- const mockCoin = { wallets : sinon . stub ( ) . returns ( mockWallets ) } ;
194- sinon . stub ( BitGo . prototype , 'coin' ) . returns ( mockCoin as any ) ;
195-
196187 const result = await agent
197188 . post ( `/api/v2/${ coin } /wallet/${ walletId } /recovertoken` )
198189 . set ( 'Authorization' , 'Bearer test_access_token_12345' )
199190 . set ( 'Content-Type' , 'application/json' )
200191 . send ( requestBody ) ;
201192
202- assert . strictEqual ( result . status , 200 ) ;
203- const decodedResponse = assertDecode ( RecoverTokenResponse , result . body ) ;
204- assert . strictEqual (
205- decodedResponse . halfSigned . tokenContractAddress ,
206- mockRecoverTokenResponse . halfSigned . tokenContractAddress
207- ) ;
193+ // Should fail validation because recipient is required
194+ assert . ok ( result . status >= 400 ) ;
208195 } ) ;
209196
210197 // ==========================================
@@ -215,6 +202,7 @@ describe('WalletRecoverToken codec tests', function () {
215202 it ( 'should handle wallet not found error' , async function ( ) {
216203 const requestBody = {
217204 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
205+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
218206 walletPassphrase : 'test_passphrase' ,
219207 } ;
220208
@@ -236,6 +224,7 @@ describe('WalletRecoverToken codec tests', function () {
236224 it ( 'should handle recoverToken failure' , async function ( ) {
237225 const requestBody = {
238226 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
227+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
239228 walletPassphrase : 'wrong_passphrase' ,
240229 } ;
241230
@@ -261,6 +250,7 @@ describe('WalletRecoverToken codec tests', function () {
261250 it ( 'should handle unsupported coin error' , async function ( ) {
262251 const requestBody = {
263252 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
253+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
264254 walletPassphrase : 'test_passphrase' ,
265255 } ;
266256
@@ -279,6 +269,7 @@ describe('WalletRecoverToken codec tests', function () {
279269 it ( 'should handle invalid token contract address error' , async function ( ) {
280270 const requestBody = {
281271 tokenContractAddress : 'invalid_address' ,
272+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
282273 walletPassphrase : 'test_passphrase' ,
283274 } ;
284275
@@ -304,6 +295,7 @@ describe('WalletRecoverToken codec tests', function () {
304295 it ( 'should handle no tokens to recover error' , async function ( ) {
305296 const requestBody = {
306297 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
298+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
307299 walletPassphrase : 'test_passphrase' ,
308300 } ;
309301
@@ -329,6 +321,7 @@ describe('WalletRecoverToken codec tests', function () {
329321 it ( 'should handle insufficient funds for gas error' , async function ( ) {
330322 const requestBody = {
331323 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
324+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
332325 walletPassphrase : 'test_passphrase' ,
333326 } ;
334327
@@ -354,6 +347,7 @@ describe('WalletRecoverToken codec tests', function () {
354347 it ( 'should handle coin() method error' , async function ( ) {
355348 const requestBody = {
356349 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
350+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
357351 walletPassphrase : 'test_passphrase' ,
358352 } ;
359353
@@ -374,6 +368,7 @@ describe('WalletRecoverToken codec tests', function () {
374368 it ( 'should reject request with invalid tokenContractAddress type' , async function ( ) {
375369 const requestBody = {
376370 tokenContractAddress : 123 , // number instead of string
371+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
377372 walletPassphrase : 'test_passphrase' ,
378373 } ;
379374
@@ -388,6 +383,7 @@ describe('WalletRecoverToken codec tests', function () {
388383
389384 it ( 'should reject request with invalid recipient type' , async function ( ) {
390385 const requestBody = {
386+ tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
391387 recipient : 123 , // number instead of string
392388 walletPassphrase : 'test_passphrase' ,
393389 } ;
@@ -404,6 +400,7 @@ describe('WalletRecoverToken codec tests', function () {
404400 it ( 'should reject request with invalid broadcast type' , async function ( ) {
405401 const requestBody = {
406402 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
403+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
407404 broadcast : 'true' , // string instead of boolean
408405 walletPassphrase : 'test_passphrase' ,
409406 } ;
@@ -420,6 +417,7 @@ describe('WalletRecoverToken codec tests', function () {
420417 it ( 'should reject request with invalid walletPassphrase type' , async function ( ) {
421418 const requestBody = {
422419 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
420+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
423421 walletPassphrase : 123 , // number instead of string
424422 } ;
425423
@@ -435,6 +433,7 @@ describe('WalletRecoverToken codec tests', function () {
435433 it ( 'should reject request with invalid prv type' , async function ( ) {
436434 const requestBody = {
437435 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
436+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
438437 prv : 123 , // number instead of string
439438 } ;
440439
@@ -456,13 +455,46 @@ describe('WalletRecoverToken codec tests', function () {
456455
457456 assert . ok ( result . status >= 400 ) ;
458457 } ) ;
458+
459+ it ( 'should reject request with missing tokenContractAddress' , async function ( ) {
460+ const requestBody = {
461+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
462+ walletPassphrase : 'test_passphrase' ,
463+ } ;
464+
465+ const result = await agent
466+ . post ( `/api/v2/${ coin } /wallet/${ walletId } /recovertoken` )
467+ . set ( 'Authorization' , 'Bearer test_access_token_12345' )
468+ . set ( 'Content-Type' , 'application/json' )
469+ . send ( requestBody ) ;
470+
471+ // Should fail validation because tokenContractAddress is required
472+ assert . ok ( result . status >= 400 ) ;
473+ } ) ;
474+
475+ it ( 'should reject request with missing recipient' , async function ( ) {
476+ const requestBody = {
477+ tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
478+ walletPassphrase : 'test_passphrase' ,
479+ } ;
480+
481+ const result = await agent
482+ . post ( `/api/v2/${ coin } /wallet/${ walletId } /recovertoken` )
483+ . set ( 'Authorization' , 'Bearer test_access_token_12345' )
484+ . set ( 'Content-Type' , 'application/json' )
485+ . send ( requestBody ) ;
486+
487+ // Should fail validation because recipient is required
488+ assert . ok ( result . status >= 400 ) ;
489+ } ) ;
459490 } ) ;
460491
461492 describe ( 'Edge Cases' , function ( ) {
462493 it ( 'should handle very long wallet ID' , async function ( ) {
463494 const veryLongWalletId = 'a' . repeat ( 1000 ) ;
464495 const requestBody = {
465496 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
497+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
466498 walletPassphrase : 'test_passphrase' ,
467499 } ;
468500
@@ -484,6 +516,7 @@ describe('WalletRecoverToken codec tests', function () {
484516 const specialCharWalletId = '../../../etc/passwd' ;
485517 const requestBody = {
486518 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
519+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
487520 walletPassphrase : 'test_passphrase' ,
488521 } ;
489522
@@ -504,6 +537,7 @@ describe('WalletRecoverToken codec tests', function () {
504537 it ( 'should handle both walletPassphrase and prv provided' , async function ( ) {
505538 const requestBody = {
506539 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
540+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
507541 walletPassphrase : 'test_passphrase' ,
508542 prv : 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2' ,
509543 } ;
@@ -554,6 +588,7 @@ describe('WalletRecoverToken codec tests', function () {
554588 it ( 'should handle invalid Ethereum address format' , async function ( ) {
555589 const requestBody = {
556590 tokenContractAddress : '0xinvalid' ,
591+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
557592 walletPassphrase : 'test_passphrase' ,
558593 } ;
559594
@@ -579,6 +614,7 @@ describe('WalletRecoverToken codec tests', function () {
579614 it ( 'should handle checksum address validation' , async function ( ) {
580615 const requestBody = {
581616 tokenContractAddress : '0x1234567890ABCDEF1234567890ABCDEF12345678' , // Mixed case (checksum)
617+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
582618 walletPassphrase : 'test_passphrase' ,
583619 } ;
584620
@@ -606,6 +642,7 @@ describe('WalletRecoverToken codec tests', function () {
606642 it ( 'should reject response with missing required field' , async function ( ) {
607643 const requestBody = {
608644 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
645+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
609646 walletPassphrase : 'test_passphrase' ,
610647 } ;
611648
@@ -644,6 +681,7 @@ describe('WalletRecoverToken codec tests', function () {
644681 it ( 'should reject response with wrong type in field' , async function ( ) {
645682 const requestBody = {
646683 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
684+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
647685 walletPassphrase : 'test_passphrase' ,
648686 } ;
649687
@@ -743,64 +781,76 @@ describe('WalletRecoverToken codec tests', function () {
743781 } ) ;
744782
745783 describe ( 'RecoverTokenBody' , function ( ) {
746- it ( 'should validate empty body (all fields optional )' , function ( ) {
747- const validBody = { } ;
784+ it ( 'should reject empty body (required fields missing )' , function ( ) {
785+ const invalidBody = { } ;
748786
749- const decoded = assertDecode ( t . type ( RecoverTokenBody ) , validBody ) ;
750- assert . strictEqual ( decoded . tokenContractAddress , undefined ) ;
751- assert . strictEqual ( decoded . recipient , undefined ) ;
752- assert . strictEqual ( decoded . broadcast , undefined ) ;
753- assert . strictEqual ( decoded . walletPassphrase , undefined ) ;
754- assert . strictEqual ( decoded . prv , undefined ) ;
787+ // Should fail because tokenContractAddress and recipient are required
788+ assert . throws ( ( ) => {
789+ assertDecode ( t . type ( RecoverTokenBody ) , invalidBody ) ;
790+ } ) ;
755791 } ) ;
756792
757- it ( 'should validate body with tokenContractAddress ' , function ( ) {
793+ it ( 'should validate body with required fields only ' , function ( ) {
758794 const validBody = {
759795 tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
796+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
760797 } ;
761798
762799 const decoded = assertDecode ( t . type ( RecoverTokenBody ) , validBody ) ;
763800 assert . strictEqual ( decoded . tokenContractAddress , validBody . tokenContractAddress ) ;
764- assert . strictEqual ( decoded . recipient , undefined ) ;
801+ assert . strictEqual ( decoded . recipient , validBody . recipient ) ;
765802 assert . strictEqual ( decoded . broadcast , undefined ) ;
766803 assert . strictEqual ( decoded . walletPassphrase , undefined ) ;
767804 assert . strictEqual ( decoded . prv , undefined ) ;
768805 } ) ;
769806
770- it ( 'should validate body with recipient' , function ( ) {
771- const validBody = {
807+ it ( 'should reject body with only recipient (tokenContractAddress missing) ' , function ( ) {
808+ const invalidBody = {
772809 recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
773810 } ;
774811
775- const decoded = assertDecode ( t . type ( RecoverTokenBody ) , validBody ) ;
776- assert . strictEqual ( decoded . recipient , validBody . recipient ) ;
777- assert . strictEqual ( decoded . tokenContractAddress , undefined ) ;
812+ // Should fail because tokenContractAddress is required
813+ assert . throws ( ( ) => {
814+ assertDecode ( t . type ( RecoverTokenBody ) , invalidBody ) ;
815+ } ) ;
778816 } ) ;
779817
780818 it ( 'should validate body with broadcast' , function ( ) {
781819 const validBody = {
820+ tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
821+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
782822 broadcast : true ,
783823 } ;
784824
785825 const decoded = assertDecode ( t . type ( RecoverTokenBody ) , validBody ) ;
826+ assert . strictEqual ( decoded . tokenContractAddress , validBody . tokenContractAddress ) ;
827+ assert . strictEqual ( decoded . recipient , validBody . recipient ) ;
786828 assert . strictEqual ( decoded . broadcast , validBody . broadcast ) ;
787829 } ) ;
788830
789831 it ( 'should validate body with walletPassphrase' , function ( ) {
790832 const validBody = {
833+ tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
834+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
791835 walletPassphrase : 'mySecurePassphrase' ,
792836 } ;
793837
794838 const decoded = assertDecode ( t . type ( RecoverTokenBody ) , validBody ) ;
839+ assert . strictEqual ( decoded . tokenContractAddress , validBody . tokenContractAddress ) ;
840+ assert . strictEqual ( decoded . recipient , validBody . recipient ) ;
795841 assert . strictEqual ( decoded . walletPassphrase , validBody . walletPassphrase ) ;
796842 } ) ;
797843
798844 it ( 'should validate body with prv' , function ( ) {
799845 const validBody = {
846+ tokenContractAddress : '0x1234567890123456789012345678901234567890' ,
847+ recipient : '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd' ,
800848 prv : 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2' ,
801849 } ;
802850
803851 const decoded = assertDecode ( t . type ( RecoverTokenBody ) , validBody ) ;
852+ assert . strictEqual ( decoded . tokenContractAddress , validBody . tokenContractAddress ) ;
853+ assert . strictEqual ( decoded . recipient , validBody . recipient ) ;
804854 assert . strictEqual ( decoded . prv , validBody . prv ) ;
805855 } ) ;
806856
0 commit comments