use alloy::{
primitives::{keccak256, Address, U256},
rpc::types::{BlockNumberOrTag, TransactionInput, TransactionRequest},
};
use tycho_common::models::blockchain::BlockTag;
pub(crate) fn arbitrary_recipient() -> Address {
let hash = keccak256(b"propeller");
Address::from_slice(&hash[..20])
}
pub(crate) fn calculate_fee(
amount: U256,
middle_amount: U256,
balance_before_in: U256,
balance_after_in: U256,
balance_recipient_before: U256,
balance_recipient_after: U256,
) -> Result<U256, String> {
Ok(
match (
balance_after_in != error_add(balance_before_in, amount)?,
balance_recipient_after != error_add(balance_recipient_before, middle_amount)?,
) {
(true, true) => {
let first_transfer_fees = error_div(
error_mul(
error_add(balance_before_in, error_sub(amount, balance_after_in)?)?,
U256::from(10_000),
)?,
amount,
)?;
let second_transfer_fees = error_div(
error_mul(
error_add(
balance_recipient_before,
error_sub(middle_amount, balance_recipient_after)?,
)?,
U256::from(10_000),
)?,
middle_amount,
)?;
if first_transfer_fees >= second_transfer_fees {
first_transfer_fees
} else {
second_transfer_fees
}
}
(true, false) => error_div(
error_mul(
error_add(balance_before_in, error_sub(amount, balance_after_in)?)?,
U256::from(10_000),
)?,
amount,
)?,
(false, true) => error_div(
error_mul(
error_add(
balance_recipient_before,
error_sub(middle_amount, balance_recipient_after)?,
)?,
U256::from(10_000),
)?,
middle_amount,
)?,
(false, false) => U256::ZERO,
},
)
}
pub(crate) fn map_block_tag(block: BlockTag) -> BlockNumberOrTag {
match block {
BlockTag::Finalized => BlockNumberOrTag::Finalized,
BlockTag::Safe => BlockNumberOrTag::Safe,
BlockTag::Latest => BlockNumberOrTag::Latest,
BlockTag::Earliest => BlockNumberOrTag::Earliest,
BlockTag::Pending => BlockNumberOrTag::Pending,
BlockTag::Number(n) => BlockNumberOrTag::Number(n),
}
}
pub(crate) fn call_request(
from: Option<Address>,
to: Address,
calldata: Vec<u8>,
) -> TransactionRequest {
let mut req = TransactionRequest::default()
.to(to)
.input(TransactionInput::both(calldata.into()));
if let Some(addr) = from {
req = req.from(addr);
}
req
}
fn error_add(a: U256, b: U256) -> Result<U256, String> {
a.checked_add(b)
.ok_or_else(|| "overflow".to_string())
}
fn error_sub(a: U256, b: U256) -> Result<U256, String> {
a.checked_sub(b)
.ok_or_else(|| "overflow".to_string())
}
fn error_div(a: U256, b: U256) -> Result<U256, String> {
a.checked_div(b)
.ok_or_else(|| "overflow".to_string())
}
fn error_mul(a: U256, b: U256) -> Result<U256, String> {
a.checked_mul(b)
.ok_or_else(|| "overflow".to_string())
}
#[cfg(test)]
mod tests {
use alloy::rpc::types::BlockNumberOrTag;
use tycho_common::models::blockchain::BlockTag;
use super::map_block_tag;
#[test]
fn test_map_block_tag() {
assert_eq!(map_block_tag(BlockTag::Finalized), BlockNumberOrTag::Finalized);
assert_eq!(map_block_tag(BlockTag::Safe), BlockNumberOrTag::Safe);
assert_eq!(map_block_tag(BlockTag::Latest), BlockNumberOrTag::Latest);
assert_eq!(map_block_tag(BlockTag::Earliest), BlockNumberOrTag::Earliest);
assert_eq!(map_block_tag(BlockTag::Pending), BlockNumberOrTag::Pending);
assert_eq!(map_block_tag(BlockTag::Number(123)), BlockNumberOrTag::Number(123));
}
}