@@ -549,6 +549,121 @@ fn test_usdc_integration_mock_token() {
549549 assert_eq ! ( updated_vault. released_amount, claimable) ;
550550}
551551
552+ #[ test]
553+ fn test_irrevocable_vault_security ( ) {
554+ let env = Env :: default ( ) ;
555+ let contract_id = env. register ( VestingContract , ( ) ) ;
556+ let client = VestingContractClient :: new ( & env, & contract_id) ;
557+
558+ // Create addresses for testing
559+ let admin = Address :: generate ( & env) ;
560+ let vault_owner = Address :: generate ( & env) ;
561+ let unauthorized_user = Address :: generate ( & env) ;
562+
563+ // Initialize contract with admin
564+ let initial_supply = 1000000i128 ;
565+ client. initialize ( & admin, & initial_supply) ;
566+
567+ // Create a vault
568+ env. as_contract ( & contract_id, || {
569+ env. current_contract_address ( ) . set ( & admin) ;
570+ } ) ;
571+
572+ let vault_amount = 1000i128 ;
573+ let vault_id = client. create_vault_full ( & vault_owner, & vault_amount, & 100u64 , & 200u64 ) ;
574+
575+ // Verify vault is initially revocable
576+ assert_eq ! ( client. is_vault_irrevocable( & vault_id) , false ) ;
577+
578+ // Test: Unauthorized user cannot mark vault as irrevocable
579+ env. as_contract ( & contract_id, || {
580+ env. current_contract_address ( ) . set ( & unauthorized_user) ;
581+ } ) ;
582+
583+ let result = std:: panic:: catch_unwind ( || {
584+ client. mark_irrevocable ( & vault_id) ;
585+ } ) ;
586+ assert ! ( result. is_err( ) ) ;
587+
588+ // Test: Admin can mark vault as irrevocable
589+ env. as_contract ( & contract_id, || {
590+ env. current_contract_address ( ) . set ( & admin) ;
591+ } ) ;
592+
593+ client. mark_irrevocable ( & vault_id) ;
594+
595+ // Verify vault is now irrevocable
596+ assert_eq ! ( client. is_vault_irrevocable( & vault_id) , true ) ;
597+
598+ // Test: Cannot mark already irrevocable vault
599+ let result = std:: panic:: catch_unwind ( || {
600+ client. mark_irrevocable ( & vault_id) ;
601+ } ) ;
602+ assert ! ( result. is_err( ) ) ;
603+
604+ // Test: Admin cannot revoke tokens from irrevocable vault (full revocation)
605+ let result = std:: panic:: catch_unwind ( || {
606+ client. revoke_tokens ( & vault_id) ;
607+ } ) ;
608+ assert ! ( result. is_err( ) ) ;
609+
610+ // Test: Admin cannot revoke partial tokens from irrevocable vault
611+ let result = std:: panic:: catch_unwind ( || {
612+ client. revoke_partial ( & vault_id, & 100i128 ) ;
613+ } ) ;
614+ assert ! ( result. is_err( ) ) ;
615+
616+ // Verify the vault state remains unchanged
617+ let vault = client. get_vault ( & vault_id) ;
618+ assert_eq ! ( vault. released_amount, 0 ) ;
619+ assert_eq ! ( vault. total_amount, vault_amount) ;
620+ assert_eq ! ( vault. is_irrevocable, true ) ;
621+ }
622+
623+ #[ test]
624+ fn test_irrevocable_vault_with_claims ( ) {
625+ let env = Env :: default ( ) ;
626+ let contract_id = env. register ( VestingContract , ( ) ) ;
627+ let client = VestingContractClient :: new ( & env, & contract_id) ;
628+
629+ // Create addresses for testing
630+ let admin = Address :: generate ( & env) ;
631+ let vault_owner = Address :: generate ( & env) ;
632+
633+ // Initialize contract with admin
634+ let initial_supply = 1000000i128 ;
635+ client. initialize ( & admin, & initial_supply) ;
636+
637+ // Create a vault
638+ env. as_contract ( & contract_id, || {
639+ env. current_contract_address ( ) . set ( & admin) ;
640+ } ) ;
641+
642+ let vault_amount = 1000i128 ;
643+ let vault_id = client. create_vault_full ( & vault_owner, & vault_amount, & 100u64 , & 200u64 ) ;
644+
645+ // Mark vault as irrevocable
646+ client. mark_irrevocable ( & vault_id) ;
647+
648+ // Beneficiary can still claim tokens from irrevocable vault
649+ env. ledger ( ) . set_timestamp ( 150 ) ; // Halfway through vesting period
650+
651+ let claimable_amount = vault_amount / 2 ; // 500 tokens should be claimable
652+ let claimed = client. claim_tokens ( & vault_id, & claimable_amount) ;
653+ assert_eq ! ( claimed, claimable_amount) ;
654+
655+ // Verify vault state after claim
656+ let vault = client. get_vault ( & vault_id) ;
657+ assert_eq ! ( vault. released_amount, claimable_amount) ;
658+ assert_eq ! ( vault. is_irrevocable, true ) ;
659+
660+ // Admin still cannot revoke even after claims
661+ let result = std:: panic:: catch_unwind ( || {
662+ client. revoke_partial ( & vault_id, & 100i128 ) ;
663+ } ) ;
664+ assert ! ( result. is_err( ) ) ;
665+ }
666+
552667// -------------------------------------------------------------------------
553668// Additional beneficiary-transfer tests added for coverage
554669// -------------------------------------------------------------------------
0 commit comments