use alloy_primitives::{keccak256, Address, B256};
use alloy_sol_types::SolValue;
pub fn compute(
deployer: Address,
init_code_hash: B256,
token_a: Address,
token_b: Address,
) -> Address {
debug_assert!(token_a != token_b, "pool_address::compute requires distinct tokens");
let (token0, token1) = if token_a < token_b { (token_a, token_b) } else { (token_b, token_a) };
let salt = keccak256((token0, token1).abi_encode());
deployer.create2(salt, init_code_hash)
}
pub fn compute_with_custom_deployer(
pool_deployer: Address,
init_code_hash: B256,
custom_deployer: Address,
token_a: Address,
token_b: Address,
) -> Address {
let (token0, token1) = if token_a < token_b { (token_a, token_b) } else { (token_b, token_a) };
let salt_data = if custom_deployer == Address::ZERO {
(token0, token1).abi_encode()
} else {
(custom_deployer, token0, token1).abi_encode()
};
let salt_hash = keccak256(salt_data);
let mut input = Vec::with_capacity(1 + 20 + 32 + 32);
input.push(0xff);
input.extend_from_slice(pool_deployer.as_slice());
input.extend_from_slice(salt_hash.as_slice());
input.extend_from_slice(init_code_hash.as_slice());
Address::from_slice(&keccak256(input).as_slice()[12..])
}
#[cfg(test)]
mod tests {
use super::*;
use crate::data::AlgebraProtocolConfig;
use alloy_primitives::{address, b256};
const QUICKSWAP_POLYGON: AlgebraProtocolConfig = AlgebraProtocolConfig {
factory: address!("411b0fAcC3489691f28ad58c47006AF5E3Ab3A28"),
pool_deployer: address!("2D98E2FA9da15aa6dC9581AB097Ced7af697CB92"),
router: address!("f5b509bB0909a69B1c207E495f687a596C168E12"),
position_mgr: address!("8eF88E4c7CfbbaC1C163f7eddd4B578792201de6"),
init_code_hash: b256!("6ec6c9c8091d160c0aa74b2b14ba9c1717e95093bd3ac085cee99a49aab294a4"),
multicall: address!("cA11bde05977b3631167028862bE2a173976CA11"),
quoter: None,
farming_center: None,
};
const USDC_E: Address = address!("2791Bca1f2de4661ED88A30C99A7a9449Aa84174");
const WETH: Address = address!("7ceB23fD6bC0adD59E62ac25578270cFf1b9f619");
const USDC_E_WETH_POOL: Address = address!("55CAaBB0d2b704FD0eF8192A7E35D8837e678207");
#[test]
fn canonical_quickswap_polygon_usdce_weth_matches_pool() {
let pool = compute(
QUICKSWAP_POLYGON.pool_deployer,
QUICKSWAP_POLYGON.init_code_hash,
USDC_E,
WETH,
);
assert_eq!(pool, USDC_E_WETH_POOL);
}
#[test]
fn custom_deployer_create2_matches_blackhole_fixture() {
use alloy_primitives::{address, b256};
let pool = compute_with_custom_deployer(
address!("9B2441037E286d5Bf9456a3BE7b5273fe28DbA1e"),
b256!("eaa3eea3233916c82fe1281a51bd9cde844b7c4673c0714ca0028a57f5634752"),
address!("5D433A94A4a2aA8f9AA34D8D15692Dc2E9960584"),
address!("49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab"),
address!("b31f66aa3c1e785363f0875a1b74e27b85fd66c7"),
);
assert_eq!(pool, address!("5e128ebc09c918ddae3ca1668d4ee9527dc00d78"));
}
#[test]
fn token_order_does_not_change_result() {
let forward = compute(
QUICKSWAP_POLYGON.pool_deployer,
QUICKSWAP_POLYGON.init_code_hash,
USDC_E,
WETH,
);
let reversed = compute(
QUICKSWAP_POLYGON.pool_deployer,
QUICKSWAP_POLYGON.init_code_hash,
WETH,
USDC_E,
);
assert_eq!(forward, reversed);
assert_eq!(forward, USDC_E_WETH_POOL);
}
#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "distinct tokens")]
fn identical_tokens_panics_in_debug() {
let _ = compute(
QUICKSWAP_POLYGON.pool_deployer,
QUICKSWAP_POLYGON.init_code_hash,
USDC_E,
USDC_E,
);
}
}