#![cfg(feature = "serde")]
use {
base64::{engine::general_purpose::STANDARD, Engine},
solana_address::Address,
solana_nullable::MaybeNull,
solana_program_option::COption,
solana_zk_sdk_pod::encryption::elgamal::PodElGamalPubkey,
spl_token_2022_interface::{extension::confidential_transfer, instruction},
std::str::FromStr,
};
#[test]
fn serde_instruction_coption_pubkey() {
let inst = instruction::TokenInstruction::InitializeMint2 {
decimals: 0,
mint_authority: Address::from_str("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM").unwrap(),
freeze_authority: COption::Some(
Address::from_str("8opHzTAnfzRpPEx21XtnrVTX28YQuCpAjcn1PczScKh").unwrap(),
),
};
let serialized = serde_json::to_string(&inst).unwrap();
assert_eq!(&serialized, "{\"initializeMint2\":{\"decimals\":0,\"mintAuthority\":\"4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM\",\"freezeAuthority\":\"8opHzTAnfzRpPEx21XtnrVTX28YQuCpAjcn1PczScKh\"}}");
serde_json::from_str::<instruction::TokenInstruction>(&serialized).unwrap();
}
#[test]
fn serde_instruction_coption_pubkey_with_none() {
let inst = instruction::TokenInstruction::InitializeMintCloseAuthority {
close_authority: COption::None,
};
let serialized = serde_json::to_string(&inst).unwrap();
assert_eq!(
&serialized,
"{\"initializeMintCloseAuthority\":{\"closeAuthority\":null}}"
);
serde_json::from_str::<instruction::TokenInstruction>(&serialized).unwrap();
}
#[test]
fn serde_instruction_coption_u64() {
let inst = instruction::TokenInstruction::UnwrapLamports {
amount: COption::Some(1),
};
let serialized = serde_json::to_string(&inst).unwrap();
assert_eq!(&serialized, "{\"unwrapLamports\":{\"amount\":1}}");
serde_json::from_str::<instruction::TokenInstruction>(&serialized).unwrap();
}
#[test]
fn serde_instruction_coption_u64_with_none() {
let inst = instruction::TokenInstruction::UnwrapLamports {
amount: COption::None,
};
let serialized = serde_json::to_string(&inst).unwrap();
assert_eq!(&serialized, "{\"unwrapLamports\":{\"amount\":null}}");
serde_json::from_str::<instruction::TokenInstruction>(&serialized).unwrap();
}
#[test]
fn serde_instruction_batch() {
let create_account_instr_data = instruction::TokenInstruction::InitializeAccount {}.pack();
let mint_to_instr_data = instruction::TokenInstruction::MintTo { amount: 100 }.pack();
let transfer_instr_data = instruction::TokenInstruction::TransferChecked {
amount: 500,
decimals: 9,
}
.pack();
let mut batch_data = Vec::new();
batch_data.push(4);
batch_data.push(create_account_instr_data.len() as u8);
batch_data.extend_from_slice(&create_account_instr_data);
batch_data.push(3);
batch_data.push(mint_to_instr_data.len() as u8);
batch_data.extend_from_slice(&mint_to_instr_data);
batch_data.push(4);
batch_data.push(transfer_instr_data.len() as u8);
batch_data.extend_from_slice(&transfer_instr_data);
let batch_instr = instruction::TokenInstruction::Batch { data: batch_data };
let serialized = serde_json::to_string(&batch_instr).unwrap();
assert_eq!(
&serialized,
"{\"batch\":{\"data\":[{\"accountCount\":4,\"dataLength\":1,\"instruction\":\"initializeAccount\"},{\"accountCount\":3,\"dataLength\":9,\"instruction\":{\"mintTo\":{\"amount\":100}}},{\"accountCount\":4,\"dataLength\":10,\"instruction\":{\"transferChecked\":{\"amount\":500,\"decimals\":9}}}]}}"
);
serde_json::from_str::<instruction::TokenInstruction>(&serialized).unwrap();
}
#[test]
fn serde_instruction_optional_nonzero_pubkeys_podbool() {
let authority_option: Option<Address> =
Some(Address::from_str("4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM").unwrap());
let authority: MaybeNull<Address> = authority_option.try_into().unwrap();
let pubkey_string = STANDARD.encode([
162, 23, 108, 36, 130, 143, 18, 219, 196, 134, 242, 145, 179, 49, 229, 193, 74, 64, 3, 158,
68, 235, 124, 88, 247, 144, 164, 254, 228, 12, 173, 85,
]);
let elgamal_pubkey_pod_option = Some(PodElGamalPubkey::from_str(&pubkey_string).unwrap());
let auditor_elgamal_pubkey: MaybeNull<PodElGamalPubkey> =
elgamal_pubkey_pod_option.try_into().unwrap();
let inst = confidential_transfer::instruction::InitializeMintData {
authority,
auto_approve_new_accounts: false.into(),
auditor_elgamal_pubkey,
};
let serialized = serde_json::to_string(&inst).unwrap();
let serialized_expected = &"{\"authority\":\"4uQeVj5tqViQh7yWWGStvkEG1Zmhx6uasJtWCJziofM\",\"autoApproveNewAccounts\":false,\"auditorElgamalPubkey\":\"ohdsJIKPEtvEhvKRszHlwUpAA55E63xY95Ck/uQMrVU=\"}";
assert_eq!(&serialized, serialized_expected);
let deserialized =
serde_json::from_str::<confidential_transfer::instruction::InitializeMintData>(&serialized)
.unwrap();
assert_eq!(inst, deserialized);
}
#[test]
fn serde_instruction_optional_nonzero_pubkeys_podbool_with_none() {
let authority: MaybeNull<Address> = None.try_into().unwrap();
let auditor_elgamal_pubkey: MaybeNull<PodElGamalPubkey> =
MaybeNull::<PodElGamalPubkey>::default();
let inst = confidential_transfer::instruction::InitializeMintData {
authority,
auto_approve_new_accounts: false.into(),
auditor_elgamal_pubkey,
};
let serialized = serde_json::to_string(&inst).unwrap();
let serialized_expected =
&"{\"authority\":null,\"autoApproveNewAccounts\":false,\"auditorElgamalPubkey\":null}";
assert_eq!(&serialized, serialized_expected);
let deserialized =
serde_json::from_str::<confidential_transfer::instruction::InitializeMintData>(
serialized_expected,
)
.unwrap();
assert_eq!(inst, deserialized);
}
#[test]
fn serde_instruction_decryptable_balance_podu64() {
let ciphertext_string = STANDARD.encode([
56, 22, 102, 48, 112, 106, 58, 25, 25, 244, 194, 217, 73, 137, 73, 38, 24, 26, 36, 25, 235,
234, 68, 181, 11, 82, 170, 163, 89, 205, 113, 160, 55, 16, 35, 151,
]);
let decryptable_zero_balance = FromStr::from_str(&ciphertext_string).unwrap();
let inst = confidential_transfer::instruction::ConfigureAccountInstructionData {
decryptable_zero_balance,
maximum_pending_balance_credit_counter: 1099.into(),
proof_instruction_offset: 100,
};
let serialized = serde_json::to_string(&inst).unwrap();
let serialized_expected = &"{\"decryptableZeroBalance\":\"OBZmMHBqOhkZ9MLZSYlJJhgaJBnr6kS1C1Kqo1nNcaA3ECOX\",\"maximumPendingBalanceCreditCounter\":1099,\"proofInstructionOffset\":100}";
assert_eq!(&serialized, serialized_expected);
let deserialized = serde_json::from_str::<
confidential_transfer::instruction::ConfigureAccountInstructionData,
>(serialized_expected)
.unwrap();
assert_eq!(inst, deserialized);
}
#[test]
fn serde_instruction_elgamal_pubkey() {
use spl_token_2022_interface::extension::confidential_transfer_fee::instruction::InitializeConfidentialTransferFeeConfigData;
let pubkey_string = STANDARD.encode([
162, 23, 108, 36, 130, 143, 18, 219, 196, 134, 242, 145, 179, 49, 229, 193, 74, 64, 3, 158,
68, 235, 124, 88, 247, 144, 164, 254, 228, 12, 173, 85,
]);
let withdraw_withheld_authority_elgamal_pubkey = FromStr::from_str(&pubkey_string).unwrap();
let inst = InitializeConfidentialTransferFeeConfigData {
authority: MaybeNull::<Address>::default(),
withdraw_withheld_authority_elgamal_pubkey,
};
let serialized = serde_json::to_string(&inst).unwrap();
let serialized_expected = "{\"authority\":null,\"withdrawWithheldAuthorityElgamalPubkey\":\"ohdsJIKPEtvEhvKRszHlwUpAA55E63xY95Ck/uQMrVU=\"}";
assert_eq!(&serialized, serialized_expected);
let deserialized =
serde_json::from_str::<InitializeConfidentialTransferFeeConfigData>(serialized_expected)
.unwrap();
assert_eq!(inst, deserialized);
}
#[test]
fn serde_instruction_basis_points() {
use spl_token_2022_interface::extension::interest_bearing_mint::instruction::InitializeInstructionData;
let inst = InitializeInstructionData {
rate_authority: MaybeNull::<Address>::default(),
rate: 127.into(),
};
let serialized = serde_json::to_string(&inst).unwrap();
let serialized_expected = "{\"rateAuthority\":null,\"rate\":127}";
assert_eq!(&serialized, serialized_expected);
serde_json::from_str::<InitializeInstructionData>(serialized_expected).unwrap();
}