Files
descro/programs/descro/tests/common/mod.rs
2026-05-26 21:33:32 +02:00

316 lines
10 KiB
Rust

#![allow(dead_code, unused_imports)]
pub use anchor_lang::prelude::Pubkey;
pub use descro::{EscrowState, Winner as EscrowWinner};
use {
anchor_lang::{
solana_program::{instruction::Instruction, system_program},
AccountDeserialize, InstructionData, ToAccountMetas,
},
descro::{EscrowAccount, Winner},
litesvm::LiteSVM,
solana_keypair::Keypair,
solana_message::{Message, VersionedMessage},
solana_signer::Signer,
solana_transaction::versioned::VersionedTransaction,
};
pub const AMOUNT: u64 = 1_000_000_000;
pub const ESCROW_ID: u64 = 1;
pub fn setup() -> (LiteSVM, Keypair, Keypair, Keypair) {
let program_id = descro::id();
let mut svm = LiteSVM::new();
let bytes = include_bytes!("../../../../target/deploy/descro.so");
svm.add_program(program_id, 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(), 1_000_000_000).unwrap();
(svm, seller, buyer, resolver)
}
pub fn escrow_pda(seller: &Pubkey, escrow_id: u64) -> Pubkey {
Pubkey::find_program_address(
&[b"escrow", seller.as_ref(), &escrow_id.to_le_bytes()],
&descro::id(),
)
.0
}
pub fn vault_pda(escrow: &Pubkey) -> Pubkey {
Pubkey::find_program_address(&[b"vault", escrow.as_ref()], &descro::id()).0
}
pub fn escrow_authority_pda() -> Pubkey {
Pubkey::find_program_address(&[b"escrow_authority"], &descro::id()).0
}
pub fn resolver_entry_pda(resolver_authority: &Pubkey) -> Pubkey {
Pubkey::find_program_address(
&[b"resolver", resolver_authority.as_ref()],
&descro_ext_resolvers::id(),
)
.0
}
pub fn send(svm: &mut LiteSVM, ix: Instruction, payer: &Keypair) {
let blockhash = svm.latest_blockhash();
let msg = Message::new_with_blockhash(&[ix], Some(&payer.pubkey()), &blockhash);
let tx = VersionedTransaction::try_new(VersionedMessage::Legacy(msg), &[payer]).unwrap();
svm.send_transaction(tx).expect("transaction failed");
}
pub fn try_send(svm: &mut LiteSVM, ix: Instruction, payer: &Keypair) -> bool {
let blockhash = svm.latest_blockhash();
let msg = Message::new_with_blockhash(&[ix], Some(&payer.pubkey()), &blockhash);
let Ok(tx) = VersionedTransaction::try_new(VersionedMessage::Legacy(msg), &[payer]) else {
return false;
};
svm.send_transaction(tx).is_ok()
}
pub fn ix_create_escrow(
seller: &Pubkey,
buyer: &Pubkey,
amount: u64,
dispute_resolver: Option<Pubkey>,
escrow_id: u64,
) -> Instruction {
// Default: derive the resolver_entry PDA from the resolver (won't exist → empty account → policy check skipped)
let dummy = Pubkey::new_from_array([1u8; 32]);
let (resolver, resolver_entry) = match dispute_resolver {
Some(r) => (r, resolver_entry_pda(&r)),
None => (dummy, dummy),
};
ix_create_escrow_with_resolver(seller, buyer, amount, dispute_resolver, escrow_id, &resolver, &resolver_entry)
}
pub fn ix_create_escrow_with_resolver(
seller: &Pubkey,
buyer: &Pubkey,
amount: u64,
dispute_resolver: Option<Pubkey>,
escrow_id: u64,
resolver: &Pubkey,
resolver_entry: &Pubkey,
) -> Instruction {
let escrow = escrow_pda(seller, escrow_id);
let vault = vault_pda(&escrow);
Instruction::new_with_bytes(
descro::id(),
&descro::instruction::CreateEscrow {
amount,
dispute_resolver,
escrow_id,
}
.data(),
descro::accounts::CreateEscrow {
seller: *seller,
buyer: *buyer,
resolver: *resolver,
escrow_account: escrow,
vault,
resolver_entry: *resolver_entry,
system_program: system_program::ID,
}
.to_account_metas(None),
)
}
pub fn ix_deposit(buyer: &Pubkey, seller: &Pubkey, escrow_id: u64) -> Instruction {
let escrow = escrow_pda(seller, escrow_id);
let vault = vault_pda(&escrow);
Instruction::new_with_bytes(
descro::id(),
&descro::instruction::Deposit {}.data(),
descro::accounts::Deposit {
buyer: *buyer,
escrow_account: escrow,
vault,
system_program: system_program::ID,
}
.to_account_metas(None),
)
}
pub fn ix_complete(buyer: &Pubkey, seller: &Pubkey, escrow_id: u64) -> Instruction {
let escrow = escrow_pda(seller, escrow_id);
let vault = vault_pda(&escrow);
Instruction::new_with_bytes(
descro::id(),
&descro::instruction::Complete {}.data(),
descro::accounts::Complete {
buyer: *buyer,
seller: *seller,
escrow_account: escrow,
vault,
system_program: system_program::ID,
}
.to_account_metas(None),
)
}
pub fn ix_dispute(initiator: &Pubkey, seller: &Pubkey, escrow_id: u64) -> Instruction {
let escrow = escrow_pda(seller, escrow_id);
Instruction::new_with_bytes(
descro::id(),
&descro::instruction::Dispute {}.data(),
descro::accounts::Dispute {
initiator: *initiator,
escrow_account: escrow,
}
.to_account_metas(None),
)
}
/// Builds a resolve instruction. Pass the actual registry program ID when testing with a
/// registered resolver; for unregistered resolvers pass `system_program::ID` as
/// `registry_program` (the handler skips the CPI if resolver_entry has no data).
pub fn ix_resolve(
resolver: &Pubkey,
winner_pubkey: &Pubkey,
seller: &Pubkey,
escrow_id: u64,
winner: Winner,
registry_program: Pubkey,
) -> Instruction {
let escrow = escrow_pda(seller, escrow_id);
let vault = vault_pda(&escrow);
let resolver_entry = resolver_entry_pda(resolver);
let escrow_authority = escrow_authority_pda();
Instruction::new_with_bytes(
descro::id(),
&descro::instruction::Resolve { winner }.data(),
descro::accounts::Resolve {
resolver: *resolver,
winner: *winner_pubkey,
seller: *seller,
escrow_account: escrow,
vault,
resolver_entry,
escrow_authority,
registry_program,
system_program: system_program::ID,
}
.to_account_metas(None),
)
}
pub fn ix_cancel(canceller: &Pubkey, buyer: &Pubkey, seller: &Pubkey, escrow_id: u64) -> Instruction {
let escrow = escrow_pda(seller, escrow_id);
let vault = vault_pda(&escrow);
Instruction::new_with_bytes(
descro::id(),
&descro::instruction::Cancel {}.data(),
descro::accounts::Cancel {
canceller: *canceller,
buyer: *buyer,
escrow_account: escrow,
vault,
system_program: system_program::ID,
}
.to_account_metas(None),
)
}
pub fn ix_buyer_create_escrow(
buyer: &Pubkey,
seller: &Pubkey,
amount: u64,
dispute_resolver: Option<Pubkey>,
escrow_id: u64,
) -> Instruction {
let escrow = escrow_pda(seller, escrow_id);
let vault = vault_pda(&escrow);
Instruction::new_with_bytes(
descro::id(),
&descro::instruction::BuyerCreateEscrow {
amount,
dispute_resolver,
escrow_id,
}
.data(),
descro::accounts::BuyerCreateEscrow {
buyer: *buyer,
seller: *seller,
escrow_account: escrow,
vault,
system_program: system_program::ID,
}
.to_account_metas(None),
)
}
pub fn ix_seller_confirm(seller: &Pubkey, resolver: &Pubkey, resolver_entry: &Pubkey, escrow_id: u64) -> Instruction {
let escrow = escrow_pda(seller, escrow_id);
Instruction::new_with_bytes(
descro::id(),
&descro::instruction::SellerConfirm {}.data(),
descro::accounts::SellerConfirm {
seller: *seller,
resolver: *resolver,
escrow_account: escrow,
resolver_entry: *resolver_entry,
}
.to_account_metas(None),
)
}
pub fn read_escrow(svm: &LiteSVM, seller: &Pubkey, escrow_id: u64) -> EscrowAccount {
let escrow = escrow_pda(seller, escrow_id);
let account = svm.get_account(&escrow).expect("escrow account not found");
EscrowAccount::try_deserialize(&mut account.data.as_slice()).unwrap()
}
/// Send a transaction signed by multiple keypairs. `payer` is the fee payer and must be first.
pub fn send_multi(svm: &mut LiteSVM, ix: Instruction, payer: &Keypair, extra: &[&Keypair]) {
let blockhash = svm.latest_blockhash();
let msg = Message::new_with_blockhash(&[ix], Some(&payer.pubkey()), &blockhash);
let mut signers: Vec<&Keypair> = vec![payer];
signers.extend_from_slice(extra);
let tx = VersionedTransaction::try_new(VersionedMessage::Legacy(msg), &signers).unwrap();
svm.send_transaction(tx).expect("multi-signer transaction failed");
}
pub fn try_send_multi(svm: &mut LiteSVM, ix: Instruction, payer: &Keypair, extra: &[&Keypair]) -> bool {
let blockhash = svm.latest_blockhash();
let msg = Message::new_with_blockhash(&[ix], Some(&payer.pubkey()), &blockhash);
let mut signers: Vec<&Keypair> = vec![payer];
signers.extend_from_slice(extra);
let Ok(tx) = VersionedTransaction::try_new(VersionedMessage::Legacy(msg), &signers) else {
return false;
};
svm.send_transaction(tx).is_ok()
}
pub fn ix_emergency_resolve(
buyer: &Pubkey,
seller: &Pubkey,
winner_pubkey: &Pubkey,
escrow_id: u64,
winner: Winner,
) -> Instruction {
let escrow = escrow_pda(seller, escrow_id);
let vault = vault_pda(&escrow);
Instruction::new_with_bytes(
descro::id(),
&descro::instruction::EmergencyResolve { winner }.data(),
descro::accounts::EmergencyResolve {
buyer: *buyer,
seller: *seller,
winner: *winner_pubkey,
escrow_account: escrow,
vault,
system_program: system_program::ID,
}
.to_account_metas(None),
)
}