Skip to content

Instantly share code, notes, and snippets.

@hoffmabc
Last active January 27, 2025 14:24
Show Gist options
  • Save hoffmabc/a87c20bf98d87bff984a5bf643a408cf to your computer and use it in GitHub Desktop.
Save hoffmabc/a87c20bf98d87bff984a5bf643a408cf to your computer and use it in GitHub Desktop.
pub fn prepare_settlement_batch(accounts: &[AccountInfo], params: &SettlementBatchParams, raw_params_data: &[u8]) -> Result<(), ProgramError> {
validate_account(accounts, 0, true, true, Some(AccountType::Program), None)?;
if ProgramState::get_settlement_hash(&accounts[0])? != EMPTY_HASH {
return Err(ProgramError::Custom(ERROR_SETTLEMENT_IN_PROGRESS));
}
ProgramState::clear_events(&accounts[0])?;
let mut running_netting_total: i64 = 0;
for token_settlements in &params.settlements {
validate_account(accounts, token_settlements.account_index, false, false, Some(AccountType::Token), Some(0))?;
let decrement_sum: u64 = verify_decrements(&accounts, token_settlements.account_index, &token_settlements.decrements)?;
let increment_sum: u64 = verify_increments(&accounts, token_settlements.account_index, &token_settlements.increments)? + token_settlements.fee_amount;
running_netting_total += increment_sum as i64 - decrement_sum as i64;
}
if running_netting_total != 0 {
msg!("Netting failed {}", running_netting_total);
return Err(ProgramError::Custom(ERROR_NETTING));
}
if ProgramState::get_events_count(&accounts[0])? == 0 {
ProgramState::set_settlement_hash(&accounts[0], hash(raw_params_data))
} else {
Ok(())
}
}
pub fn validate_account(accounts: &[AccountInfo], index: u8, is_signer: bool, is_writable: bool, account_type: Option<AccountType>, related_account_index: Option<u8>) -> Result<(), ProgramError> {
if index as usize >= accounts.len() {
return Err(ProgramError::Custom(ERROR_INVALID_ACCOUNT_INDEX));
}
let account = &accounts[index as usize];
if account.is_signer != is_signer || account.is_writable != is_writable {
return Err(ProgramError::Custom(ERROR_INVALID_ACCOUNT_FLAGS));
}
if let Some(account_type) = account_type {
if get_type(account)? != account_type {
return Err(ProgramError::Custom(ERROR_INVALID_ACCOUNT_TYPE));
}
if let Some(related_account_index) = related_account_index{
let related_key = match account_type {
AccountType::Program => ProgramState::get_withdraw_account_key(&account),
AccountType::Withdraw => WithdrawState::get_program_state_account_key(&account),
AccountType::Token => TokenState::get_program_state_account_key(&account),
AccountType::RuneReceiver => RuneReceiverState::get_program_state_account_key(&account),
_ => Err(ProgramError::Custom(ERROR_INVALID_ACCOUNT_TYPE))
}?;
if related_key != *accounts[related_account_index as usize].key {
return Err(ProgramError::Custom(ERROR_STATE_ACCOUNT_MISMATCH));
}
}
} else {
if !account.data_is_empty() {
return Err(ProgramError::Custom(ERROR_ALREADY_INITIALIZED))
}
}
Ok(())
}
pub fn validate_bitcoin_address(address: &str, network_type: &NetworkType, strict: bool) -> Result<(), ProgramError> {
let network_unchecked_address = Address::from_str(address)
.map_err(|_| ProgramError::Custom(ERROR_INVALID_ADDRESS))?;
if strict || *network_type == NetworkType::Bitcoin {
network_unchecked_address
.require_network(map_network_type(network_type))
.map_err(|_| ProgramError::Custom(ERROR_INVALID_ADDRESS_NETWORK))?;
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment