/// Integration test: resolve() calls update_stats() via CPI when the resolver /// has a registered entry in the Resolver Registry. mod common; use common::*; use anchor_lang::InstructionData; use anchor_lang::ToAccountMetas; use anchor_lang::solana_program::{instruction::Instruction, system_program}; use descro_ext_resolvers::{ResolverType, ResolverEntry}; use anchor_lang::AccountDeserialize; use litesvm::LiteSVM; use solana_keypair::Keypair; use solana_signer::Signer; fn setup_both_programs() -> (LiteSVM, Keypair, Keypair, Keypair) { let mut svm = LiteSVM::new(); let escrow_bytes = include_bytes!("../../../target/deploy/descro.so"); svm.add_program(descro::id(), escrow_bytes).unwrap(); let registry_bytes = include_bytes!("../../../target/deploy/descro_ext_resolvers.so"); svm.add_program(descro_ext_resolvers::id(), registry_bytes).unwrap(); let seller = Keypair::new(); let buyer = Keypair::new(); let resolver = Keypair::new(); svm.airdrop(&seller.pubkey(), 10_000_000_000).unwrap(); svm.airdrop(&buyer.pubkey(), 10_000_000_000).unwrap(); svm.airdrop(&resolver.pubkey(), 5_000_000_000).unwrap(); (svm, seller, buyer, resolver) } fn ix_register_resolver(authority: &Pubkey) -> Instruction { let entry = resolver_entry_pda(authority); Instruction::new_with_bytes( descro_ext_resolvers::id(), &descro_ext_resolvers::instruction::RegisterResolver { resolver_type: ResolverType::CentralAuthority, name: "Test Resolver".to_string(), description: "Integration test resolver".to_string(), fee_bps: 100, fee_recipient: *authority, metadata_uri: "ipfs://test".to_string(), } .data(), descro_ext_resolvers::accounts::RegisterResolver { authority: *authority, resolver_entry: entry, system_program: system_program::ID, } .to_account_metas(None), ) } fn read_resolver_entry(svm: &LiteSVM, authority: &Pubkey) -> ResolverEntry { let pda = resolver_entry_pda(authority); let account = svm.get_account(&pda).expect("resolver entry not found"); ResolverEntry::try_deserialize(&mut account.data.as_slice()).unwrap() } #[test] fn resolve_updates_stats_when_resolver_registered() { let (mut svm, seller, buyer, resolver) = setup_both_programs(); // Register the resolver in the Registry send(&mut svm, ix_register_resolver(&resolver.pubkey()), &resolver); // Full escrow flow send( &mut svm, ix_create_escrow( &seller.pubkey(), &buyer.pubkey(), AMOUNT, Some(resolver.pubkey()), ESCROW_ID, ), &seller, ); send(&mut svm, ix_deposit(&buyer.pubkey(), &seller.pubkey(), ESCROW_ID), &buyer); send(&mut svm, ix_dispute(&buyer.pubkey(), &seller.pubkey(), ESCROW_ID), &buyer); // Resolve with registry program provided send( &mut svm, ix_resolve( &resolver.pubkey(), &seller.pubkey(), &seller.pubkey(), ESCROW_ID, EscrowWinner::Seller, descro_ext_resolvers::id(), // pass registry program → triggers CPI ), &resolver, ); let entry = read_resolver_entry(&svm, &resolver.pubkey()); assert_eq!(entry.total_resolved, 1); assert_eq!(entry.ruled_for_seller, 1); assert_eq!(entry.ruled_for_buyer, 0); } #[test] fn resolve_skips_stats_when_resolver_not_registered() { let (mut svm, seller, buyer, resolver) = setup_both_programs(); // Do NOT register resolver — entry does not exist send( &mut svm, ix_create_escrow( &seller.pubkey(), &buyer.pubkey(), AMOUNT, Some(resolver.pubkey()), ESCROW_ID, ), &seller, ); send(&mut svm, ix_deposit(&buyer.pubkey(), &seller.pubkey(), ESCROW_ID), &buyer); send(&mut svm, ix_dispute(&buyer.pubkey(), &seller.pubkey(), ESCROW_ID), &buyer); // Resolve without passing registry program — CPI skipped send( &mut svm, ix_resolve( &resolver.pubkey(), &seller.pubkey(), &seller.pubkey(), ESCROW_ID, EscrowWinner::Seller, system_program::ID, // no registry → CPI skipped ), &resolver, ); // Escrow closed, resolver entry still absent assert!(svm.get_account(&escrow_pda(&seller.pubkey(), ESCROW_ID)).is_none()); assert!(svm.get_account(&resolver_entry_pda(&resolver.pubkey())).is_none()); } #[test] fn resolve_buyer_wins_increments_ruled_for_buyer() { let (mut svm, seller, buyer, resolver) = setup_both_programs(); send(&mut svm, ix_register_resolver(&resolver.pubkey()), &resolver); send( &mut svm, ix_create_escrow( &seller.pubkey(), &buyer.pubkey(), AMOUNT, Some(resolver.pubkey()), ESCROW_ID, ), &seller, ); send(&mut svm, ix_deposit(&buyer.pubkey(), &seller.pubkey(), ESCROW_ID), &buyer); send(&mut svm, ix_dispute(&buyer.pubkey(), &seller.pubkey(), ESCROW_ID), &buyer); send( &mut svm, ix_resolve( &resolver.pubkey(), &buyer.pubkey(), &seller.pubkey(), ESCROW_ID, EscrowWinner::Buyer, descro_ext_resolvers::id(), ), &resolver, ); let entry = read_resolver_entry(&svm, &resolver.pubkey()); assert_eq!(entry.total_resolved, 1); assert_eq!(entry.ruled_for_buyer, 1); assert_eq!(entry.ruled_for_seller, 0); }