Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 252 additions & 1 deletion solana/crates/kolme-solana-bridge/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use kolme_solana_bridge_client::{
transfer_payload, TokenProgram, INITIALIZE_IX, REGULAR_IX, SIGNED_IX
};

use crate::{SignedIxError, TOKEN_HOLDER_SEED};
use crate::{SignedIxError, InitIxError, TOKEN_HOLDER_SEED};

const KEYS_LEN: usize = 5;
const PROCESSOR_KEY: usize = 0;
Expand Down Expand Up @@ -551,3 +551,254 @@ fn secp256k1_is_normalized() {
// assert!(Secp256k1Signature(sig.to_bytes().into()).is_normalized());
// }
}

fn setup_program_with_sender() -> (Program, Keypair) {
let mut p = Program::new();
let sender = Keypair::new();
p.svm.airdrop(&sender.pubkey(), 1_000_000_000).unwrap();
p.init_default(&sender).unwrap();
(p, sender)
}

#[test]
fn invalid_payload_rejected() {
let (mut p, sender) = setup_program_with_sender();

let payload = Payload {
id: 0,
program_id: TOKEN.to_bytes(),
accounts: vec![],
instruction_data: vec![255, 255],
signer: None,
};

let (data, metas) = p.make_signed_msg(&payload, &[EXECUTOR1_KEY, EXECUTOR3_KEY]);

let result = p.signed(&sender, &data, &metas);
assert!(result.is_err(), "Expected error due to invalid payload");
}

#[test]
fn zero_amount_transfer() {
let (mut p, sender) = setup_program_with_sender();

let sender_ata = p.make_ata(&sender);
p.mint(&sender_ata, 1_000_000_000);

let data = RegularMsgIxData {
keys: vec![],
transfer_amounts: vec![0],
};

let result = p.regular(&sender, &data, &[p.token]);
assert!(result.is_ok());

let sender_ata_data: SplAccount = get_spl_account(&p.svm, &sender_ata).unwrap();
assert_eq!(sender_ata_data.amount, 1_000_000_000);
}

#[test]
fn duplicate_executor_signatures_rejected() {
let (mut p, sender) = setup_program_with_sender();

let receiver = Keypair::new();
let payload = p.transfer_payload(0, receiver.pubkey(), 1000);
let (data, metas) = p.make_signed_msg(&payload, &[EXECUTOR1_KEY, EXECUTOR1_KEY]);

let result = p.signed(&sender, &data, &metas).unwrap_err();
assert_eq!(
result.err,
TransactionError::InstructionError(
0,
InstructionError::Custom(SignedIxError::DuplicateExecutorKey as u32)
)
);
}

#[test]
fn large_token_amount_transfer() {
let (mut p, sender) = setup_program_with_sender();

let sender_ata = p.make_ata(&sender);
let max_amount = u64::MAX / 2;
p.mint(&sender_ata, max_amount);

let data = RegularMsgIxData {
keys: vec![],
transfer_amounts: vec![max_amount],
};
p.regular(&sender, &data, &[p.token]).unwrap();

let holder_acc = token_holder_acc(&p.token, &sender.pubkey());
let holder_ata = spl_client::address::get_associated_token_address(&holder_acc, &p.token);
let holder_ata_data: SplAccount = get_spl_account(&p.svm, &holder_ata).unwrap();
assert_eq!(holder_ata_data.amount, max_amount);
}

#[test]
fn insufficient_token_balance_rejected() {
let (mut p, sender) = setup_program_with_sender();

let sender_ata = p.make_ata(&sender);
let mint_amount = 1_000_000_000;
p.mint(&sender_ata, mint_amount);

let data = RegularMsgIxData {
keys: vec![],
transfer_amounts: vec![mint_amount + 1],
};

let result = p.regular(&sender, &data, &[p.token]).unwrap_err();
assert_eq!(
result.err,
TransactionError::InstructionError(0, InstructionError::Custom(1))
);
}

#[test]
fn transfer_to_uninitialized_ata() {
let mut p = Program::new();
let sender = Keypair::new();
let receiver = Keypair::new();
p.svm.airdrop(&sender.pubkey(), 1_000_000_000).unwrap();
p.init_default(&sender).unwrap();

let sender_ata = p.make_ata(&sender);
let mint_amount = 1_000_000_000;
p.mint(&sender_ata, mint_amount);

let receiver_ata =
spl_client::address::get_associated_token_address(&receiver.pubkey(), &p.token);
let payload = p.transfer_payload(0, receiver_ata, mint_amount / 2);
let (data, metas) = p.make_signed_msg(&payload, &[EXECUTOR1_KEY, EXECUTOR3_KEY]);

let result = p.signed(&sender, &data, &metas).unwrap_err();
assert_eq!(
result.err,
TransactionError::InstructionError(0, InstructionError::InvalidAccountData)
);
}

#[test]
fn multiple_token_transfers_in_one_instruction() {
let (mut p, sender) = setup_program_with_sender();

let token_1 = p.token;
let token_2 = CreateMint::new(&mut p.svm, &p.token_owner).send().unwrap();

let sender_ata_1 = p.make_ata(&sender);
let sender_ata_2 = CreateAssociatedTokenAccount::new(&mut p.svm, &sender, &token_2)
.send()
.unwrap();

let mint_amount = 1_000_000_000;
p.mint(&sender_ata_1, mint_amount);
MintTo::new(
&mut p.svm,
&p.token_owner,
&token_2,
&sender_ata_2,
mint_amount,
)
.send()
.unwrap();

let data = RegularMsgIxData {
keys: vec![],
transfer_amounts: vec![mint_amount / 2, mint_amount / 4],
};
p.regular(&sender, &data, &[token_1, token_2]).unwrap();

let holder_ata_1 = spl_client::address::get_associated_token_address(
&token_holder_acc(&token_1, &sender.pubkey()),
&token_1,
);
let holder_ata_2 = spl_client::address::get_associated_token_address(
&token_holder_acc(&token_2, &sender.pubkey()),
&token_2,
);

let holder_ata_1_data: SplAccount = get_spl_account(&p.svm, &holder_ata_1).unwrap();
let holder_ata_2_data: SplAccount = get_spl_account(&p.svm, &holder_ata_2).unwrap();

assert_eq!(holder_ata_1_data.amount, mint_amount / 2);
assert_eq!(holder_ata_2_data.amount, mint_amount / 4);
}

#[test]
fn tampered_payload_rejected() {
let (mut p, sender) = setup_program_with_sender();

let receiver = Keypair::new();
let payload = p.transfer_payload(0, receiver.pubkey(), 1000);
let (mut data, metas) = p.make_signed_msg(&payload, &[EXECUTOR1_KEY, EXECUTOR3_KEY]);

let tampered_payload = base64::engine::general_purpose::STANDARD.encode("tampered");
data.payload = tampered_payload;

let result = p.signed(&sender, &data, &metas);
assert!(result.is_err(), "Expected error due to tampered payload");
}

#[test]
fn invalid_needed_executors_rejected() {
let mut p = Program::new();
let sender = Keypair::new();
p.svm.airdrop(&sender.pubkey(), 1_000_000_000).unwrap();

let mut executors = Vec::with_capacity(KEYS_LEN - 1);
for i in 1..KEYS_LEN {
executors.push(Secp256k1PubkeyCompressed(
p.keys[i]
.verifying_key()
.to_sec1_bytes()
.deref()
.try_into()
.unwrap(),
));
}

let data = InitializeIxData {
needed_executors: (KEYS_LEN) as u8,
processor: Secp256k1PubkeyCompressed(
p.keys[PROCESSOR_KEY]
.verifying_key()
.to_sec1_bytes()
.deref()
.try_into()
.unwrap(),
),
executors,
};

let result = p.init(&sender, &data).unwrap_err();
assert_eq!(
result.err,
TransactionError::InstructionError(
0,
InstructionError::Custom(InitIxError::InsufficientExecutors as u32)
)
);

let data_zero = InitializeIxData {
needed_executors: 0,
processor: Secp256k1PubkeyCompressed(
p.keys[PROCESSOR_KEY]
.verifying_key()
.to_sec1_bytes()
.deref()
.try_into()
.unwrap(),
),
executors: vec![],
};

let result_zero = p.init(&sender, &data_zero).unwrap_err();
assert_eq!(
result_zero.err,
TransactionError::InstructionError(
0,
InstructionError::Custom(InitIxError::NoExecutorsProvided as u32)
)
);
}
Loading