#[macro_export]
macro_rules! impl_v3_pool_infuser {
($struct_name:ident) => {
#[async_trait::async_trait]
impl $crate::traits::pool_infuser::PoolInfuser for $struct_name
{
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
tick_lower = ?params.tick_lower,
tick_upper = ?params.tick_upper,
amount0 = ?params.amount0,
amount1 = ?params.amount1
))]
async fn add_liquidity(
&self,
params: $crate::traits::pool_infuser::AddLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddLiquidityResult> {
let call_parameters = $crate::pool_infusers::v3::build_add_liquidity_call_parameters(
&self.pool_key,
$crate::common::type_conversions::convert_add_liquidity_params(params.clone()),
$crate::common::type_conversions::convert_add_liquidity_options(options.clone()),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Add liquidity call parameters built"
);
let method_params = $crate::common::type_conversions::convert_method_parameters(call_parameters);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
method_params,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::v3::decode_add_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
token_id = ?params.token_id,
liquidity = ?params.liquidity
))]
async fn remove_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveLiquidityResult> {
let call_parameters = $crate::pool_infusers::v3::build_remove_liquidity_call_parameters(
&self.pool_key,
$crate::common::type_conversions::convert_remove_liquidity_params(params),
$crate::common::type_conversions::convert_remove_liquidity_options(options.clone()),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Remove liquidity call parameters built"
);
let method_params = $crate::common::type_conversions::convert_method_parameters(call_parameters);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
method_params,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::v3::decode_remove_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
token_id = ?params.token_id
))]
async fn collect(
&self,
params: $crate::traits::pool_infuser::CollectParams,
options: $crate::traits::pool_infuser::CollectOptions,
) -> anyhow::Result<$crate::types::swap_results::CollectResult> {
let call_parameters = $crate::pool_infusers::v3::build_collect_call_parameters(
&self.pool_key,
&$crate::common::type_conversions::convert_collect_params(params),
&$crate::common::type_conversions::convert_collect_options(options),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Collect call parameters built"
);
let method_params = $crate::common::type_conversions::convert_method_parameters(call_parameters);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
method_params,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Collect transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Collect transaction failed"
);
return Err(anyhow::anyhow!("Collect transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::v3::decode_collect_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, _amount, _block_id), fields(
position_manager_address = ?self.position_manager_address()
))]
async fn calculate_add_liquidity_amounts(
&self,
_amount: uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
_block_id: Option<alloy::eips::BlockId>,
) -> anyhow::Result<(
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
)> {
Err(anyhow::anyhow!(
"calculate_add_liquidity_amounts not yet implemented. This requires querying pool \
state and using Position calculations."
))
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
num_positions = params.items.len()
))]
async fn add_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::AddBatchLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::v3::build_add_batch_liquidity_call_parameters(
&self.pool_key,
$crate::common::type_conversions::convert_add_batch_liquidity_params(params.clone()),
$crate::common::type_conversions::convert_add_liquidity_options(options.clone()),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
num_positions = params.items.len(),
"Add batch liquidity call parameters built"
);
let method_params = $crate::common::type_conversions::convert_method_parameters(call_parameters);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
method_params,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add batch liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let results = $crate::pool_infusers::v3::decode_add_batch_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok($crate::types::swap_results::AddBatchLiquidityResult {
results,
tx_hash: receipt.transaction_hash,
})
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
num_positions = params.items.len()
))]
async fn remove_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveBatchLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::v3::build_remove_batch_liquidity_call_parameters(
&self.pool_key,
$crate::common::type_conversions::convert_remove_batch_liquidity_params(params.clone()),
$crate::common::type_conversions::convert_remove_liquidity_options(options.clone()),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
num_positions = params.items.len(),
"Remove batch liquidity call parameters built"
);
let method_params = $crate::common::type_conversions::convert_method_parameters(call_parameters);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
method_params,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove batch liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let results = $crate::pool_infusers::v3::decode_remove_batch_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok($crate::types::swap_results::RemoveBatchLiquidityResult {
results,
tx_hash: receipt.transaction_hash,
})
}
}
};
}
#[macro_export]
macro_rules! impl_shadow_pool_infuser {
($struct_name:ident) => {
#[async_trait::async_trait]
impl $crate::traits::pool_infuser::PoolInfuser for $struct_name
{
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
tick_lower = ?params.tick_lower,
tick_upper = ?params.tick_upper,
amount0 = ?params.amount0,
amount1 = ?params.amount1
))]
async fn add_liquidity(
&self,
params: $crate::traits::pool_infuser::AddLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddLiquidityResult> {
let call_parameters = $crate::pool_infusers::shadow::build_add_liquidity_call_parameters(
&self.pool_key,
self.tick_spacing(),
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Add liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::shadow::decode_add_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
token_id = ?params.token_id,
liquidity = ?params.liquidity
))]
async fn remove_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveLiquidityResult> {
match self.claim_rewards(&[params.token_id])
.await {
Ok(claim_results) => {
if claim_results.is_empty() {
tracing::warn!("No rewards claimed");
}
for claim_result in claim_results {
for reward_amount in claim_result.reward_amounts {
tracing::info!("Position ID: {}, Token: {}, Amount: {}", claim_result.position_id, reward_amount.currency.address(), reward_amount.to_exact());
}
}
}
Err(e) => {
tracing::warn!("Failed to claim rewards: {}", e);
}
}
let call_parameters = $crate::pool_infusers::shadow::build_remove_liquidity_call_parameters(
&self.pool_key,
params,
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Remove liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::shadow::decode_remove_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, _options), fields(
position_manager_address = ?self.position_manager_address(),
token_id = ?params.token_id
))]
async fn collect(
&self,
params: $crate::traits::pool_infuser::CollectParams,
_options: $crate::traits::pool_infuser::CollectOptions,
) -> anyhow::Result<$crate::types::swap_results::CollectResult> {
use anyhow::Context;
use uniswap_sdk_core::prelude::*;
let claim_results = self.claim_rewards(&[params.token_id])
.await
.context("Failed to claim rewards")?;
let (reward_amounts, tx_hash) = if let Some(claim_result) = claim_results.first() {
if claim_result.position_id == params.token_id {
let rewards = if claim_result.reward_amounts.is_empty() {
None
} else {
Some(claim_result.reward_amounts.clone())
};
(rewards, claim_result.tx_hash)
} else {
(None, claim_result.tx_hash)
}
} else {
(None, alloy::primitives::TxHash::ZERO)
};
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::types::swap_results::CollectResult {
token_id: params.token_id,
recipient: self.sender_address(),
amount0: CurrencyAmount::from_raw_amount(currency0, BigInt::from(0u64))?,
amount1: CurrencyAmount::from_raw_amount(currency1, BigInt::from(0u64))?,
tick_upper: I24::try_from(0).unwrap_or_default(),
tick_lower: I24::try_from(0).unwrap_or_default(),
reward_amounts,
tx_hash,
};
Ok(result)
}
#[tracing::instrument(skip(self, _amount, _block_id), fields(
position_manager_address = ?self.position_manager_address()
))]
async fn calculate_add_liquidity_amounts(
&self,
_amount: uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
_block_id: Option<alloy::eips::BlockId>,
) -> anyhow::Result<(
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
)> {
Err(anyhow::anyhow!(
"calculate_add_liquidity_amounts not yet implemented. This requires querying pool \
state and using Position calculations."
))
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
num_positions = params.items.len()
))]
async fn add_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::AddBatchLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::shadow::build_add_batch_liquidity_call_parameters(
&self.pool_key,
self.tick_spacing(),
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
num_positions = params.items.len(),
"Add batch liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add batch liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let results = $crate::pool_infusers::shadow::decode_add_batch_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok($crate::types::swap_results::AddBatchLiquidityResult {
results,
tx_hash: receipt.transaction_hash,
})
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
num_positions = params.items.len()
))]
async fn remove_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveBatchLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveBatchLiquidityResult> {
match self.claim_rewards(¶ms.items.iter().map(|item| item.token_id).collect::<Vec<_>>())
.await {
Ok(claim_results) => {
if claim_results.is_empty() {
tracing::warn!("No rewards claimed");
}
for claim_result in claim_results {
for reward_amount in claim_result.reward_amounts {
tracing::info!("Position ID: {}, Token: {}, Amount: {}", claim_result.position_id, reward_amount.currency.address(), reward_amount.to_exact());
}
}
}
Err(e) => {
tracing::warn!("Failed to claim rewards: {}", e);
}
}
let call_parameters = $crate::pool_infusers::shadow::build_remove_batch_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
num_positions = params.items.len(),
"Remove batch liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove batch liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let results = $crate::pool_infusers::shadow::decode_remove_batch_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok($crate::types::swap_results::RemoveBatchLiquidityResult {
results,
tx_hash: receipt.transaction_hash,
})
}
}
};
}
#[macro_export]
macro_rules! impl_pancake_v3_pool_infuser {
($struct_name:ident) => {
#[async_trait::async_trait]
impl $crate::traits::pool_infuser::PoolInfuser for $struct_name
{
async fn calculate_add_liquidity_amounts(
&self,
_amount: uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
_block_id: Option<alloy::eips::BlockId>,
) -> anyhow::Result<(
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
)> {
Err(anyhow::anyhow!(
"calculate_add_liquidity_amounts not yet implemented. This requires querying pool \
state and using Position calculations."
))
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
tick_lower = ?params.tick_lower,
tick_upper = ?params.tick_upper,
amount0 = ?params.amount0,
amount1 = ?params.amount1
))]
async fn add_liquidity(
&self,
params: $crate::traits::pool_infuser::AddLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddLiquidityResult> {
let call_parameters = $crate::pool_infusers::pancake_v3::build_add_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Add liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::pancake_v3::decode_add_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
token_id = ?params.token_id,
liquidity = ?params.liquidity
))]
async fn remove_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveLiquidityResult> {
let call_parameters = $crate::pool_infusers::pancake_v3::build_remove_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Remove liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::pancake_v3::decode_remove_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
token_id = ?params.token_id
))]
async fn collect(
&self,
params: $crate::traits::pool_infuser::CollectParams,
options: $crate::traits::pool_infuser::CollectOptions,
) -> anyhow::Result<$crate::types::swap_results::CollectResult> {
let call_parameters = $crate::pool_infusers::pancake_v3::build_collect_call_parameters(
&self.pool_key,
¶ms,
&options,
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Collect call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Collect transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Collect transaction failed"
);
return Err(anyhow::anyhow!("Collect transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::pancake_v3::decode_collect_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
items_count = params.items.len()
))]
async fn add_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::AddBatchLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::pancake_v3::build_add_batch_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Add batch liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add batch liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let results = $crate::pool_infusers::pancake_v3::decode_add_batch_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok($crate::types::swap_results::AddBatchLiquidityResult {
results,
tx_hash: receipt.transaction_hash,
})
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
items_count = params.items.len()
))]
async fn remove_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveBatchLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::pancake_v3::build_remove_batch_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Remove batch liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove batch liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let results = $crate::pool_infusers::pancake_v3::decode_remove_batch_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok($crate::types::swap_results::RemoveBatchLiquidityResult {
results,
tx_hash: receipt.transaction_hash,
})
}
}
};
}
#[macro_export]
macro_rules! impl_slipstream_pool_infuser {
($struct_name:ident) => {
#[async_trait::async_trait]
impl $crate::traits::pool_infuser::PoolInfuser for $struct_name
{
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
tick_lower = ?params.tick_lower,
tick_upper = ?params.tick_upper,
amount0 = ?params.amount0,
amount1 = ?params.amount1
))]
async fn add_liquidity(
&self,
params: $crate::traits::pool_infuser::AddLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddLiquidityResult> {
let call_parameters = $crate::pool_infusers::slipstream::build_add_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Add liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
Some($crate::pool_infusers::slipstream::handle_slipstream_transaction_error),
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::slipstream::decode_add_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
token_id = ?params.token_id,
liquidity = ?params.liquidity
))]
async fn remove_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveLiquidityResult> {
let call_parameters = $crate::pool_infusers::slipstream::build_remove_liquidity_call_parameters(
&self.pool_key,
params,
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Remove liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
Some($crate::pool_infusers::slipstream::handle_slipstream_transaction_error),
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::slipstream::decode_remove_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
token_id = ?params.token_id
))]
async fn collect(
&self,
params: $crate::traits::pool_infuser::CollectParams,
options: $crate::traits::pool_infuser::CollectOptions,
) -> anyhow::Result<$crate::types::swap_results::CollectResult> {
let call_parameters = $crate::pool_infusers::slipstream::build_collect_call_parameters(
&self.pool_key,
¶ms,
&options,
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Collect call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
Some($crate::pool_infusers::slipstream::handle_slipstream_transaction_error),
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Collect transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Collect transaction failed"
);
return Err(anyhow::anyhow!("Collect transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::slipstream::decode_collect_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, _amount, _block_id), fields(
position_manager_address = ?self.position_manager_address()
))]
async fn calculate_add_liquidity_amounts(
&self,
_amount: uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
_block_id: Option<alloy::eips::BlockId>,
) -> anyhow::Result<(
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
)> {
Err(anyhow::anyhow!(
"calculate_add_liquidity_amounts not yet implemented. This requires querying pool \
state and using Position calculations."
))
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
num_positions = params.items.len()
))]
async fn add_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::AddBatchLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::slipstream::build_add_batch_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
num_positions = params.items.len(),
"Add batch liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add batch liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let results = $crate::pool_infusers::slipstream::decode_add_batch_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok($crate::types::swap_results::AddBatchLiquidityResult {
results,
tx_hash: receipt.transaction_hash,
})
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
num_positions = params.items.len()
))]
async fn remove_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveBatchLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::slipstream::build_remove_batch_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
num_positions = params.items.len(),
"Remove batch liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove batch liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let results = $crate::pool_infusers::slipstream::decode_remove_batch_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok($crate::types::swap_results::RemoveBatchLiquidityResult {
results,
tx_hash: receipt.transaction_hash,
})
}
}
};
}
#[macro_export]
macro_rules! impl_quickswap_pool_infuser {
($struct_name:ident) => {
#[async_trait::async_trait]
impl $crate::traits::pool_infuser::PoolInfuser for $struct_name
{
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
tick_lower = ?params.tick_lower,
tick_upper = ?params.tick_upper,
amount0 = ?params.amount0,
amount1 = ?params.amount1
))]
async fn add_liquidity(
&self,
params: $crate::traits::pool_infuser::AddLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddLiquidityResult> {
let call_parameters = $crate::pool_infusers::quickswap::build_add_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Add liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::quickswap::decode_add_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
token_id = ?params.token_id,
liquidity = ?params.liquidity
))]
async fn remove_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveLiquidityResult> {
let call_parameters = $crate::pool_infusers::quickswap::build_remove_liquidity_call_parameters(
&self.pool_key,
params,
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Remove liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::quickswap::decode_remove_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
token_id = ?params.token_id
))]
async fn collect(
&self,
params: $crate::traits::pool_infuser::CollectParams,
options: $crate::traits::pool_infuser::CollectOptions,
) -> anyhow::Result<$crate::types::swap_results::CollectResult> {
let call_parameters = $crate::pool_infusers::quickswap::build_collect_call_parameters(
&self.pool_key,
¶ms,
&options,
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Collect call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Collect transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Collect transaction failed"
);
return Err(anyhow::anyhow!("Collect transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let result = $crate::pool_infusers::quickswap::decode_collect_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok(result)
}
#[tracing::instrument(skip(self, _amount, _block_id), fields(
position_manager_address = ?self.position_manager_address()
))]
async fn calculate_add_liquidity_amounts(
&self,
_amount: uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
_block_id: Option<alloy::eips::BlockId>,
) -> anyhow::Result<(
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
)> {
Err(anyhow::anyhow!(
"calculate_add_liquidity_amounts not yet implemented. This requires querying pool \
state and using Position calculations."
))
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
num_positions = params.items.len()
))]
async fn add_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::AddBatchLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::quickswap::build_add_batch_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
num_positions = params.items.len(),
"Add batch liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add batch liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let results = $crate::pool_infusers::quickswap::decode_add_batch_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok($crate::types::swap_results::AddBatchLiquidityResult {
results,
tx_hash: receipt.transaction_hash,
})
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
num_positions = params.items.len()
))]
async fn remove_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveBatchLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::quickswap::build_remove_batch_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
num_positions = params.items.len(),
"Remove batch liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove batch liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let results = $crate::pool_infusers::quickswap::decode_remove_batch_liquidity_result(
&receipt,
self.position_manager_address(),
self.pool_address(),
currency0,
currency1,
)?;
Ok($crate::types::swap_results::RemoveBatchLiquidityResult {
results,
tx_hash: receipt.transaction_hash,
})
}
}
};
}
#[macro_export]
macro_rules! impl_v4_pool_infuser {
($struct_name:ident) => {
#[async_trait::async_trait]
impl $crate::traits::pool_infuser::PoolInfuser for $struct_name
{
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
pool_manager_address = ?self.pool_manager_address(),
pool_id = ?self.pool_id(),
tick_lower = ?params.tick_lower,
tick_upper = ?params.tick_upper,
amount0 = ?params.amount0,
amount1 = ?params.amount1
))]
async fn add_liquidity(
&self,
params: $crate::traits::pool_infuser::AddLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddLiquidityResult> {
let call_result = $crate::pool_infusers::v4::build_add_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_result.method_parameters.calldata.len(),
value = ?call_result.method_parameters.value,
amount0_max = ?call_result.amount0_max,
amount1_max = ?call_result.amount1_max,
liquidity = ?call_result.liquidity,
"Add liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_result.method_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
use alloy::primitives::aliases::U128;
use uniswap_sdk_core::prelude::{CurrencyAmount, ToBig};
let (modify_event, tx_hash) = $crate::pool_infusers::v4::decode_modify_liquidity_event_with_pool_id(
&receipt,
self.pool_manager_address(),
self.pool_id(),
)?;
Ok($crate::types::swap_results::AddLiquidityResult {
token_id: modify_event.token_id,
liquidity: U128::from(call_result.liquidity),
amount0: CurrencyAmount::from_raw_amount(
currency0,
call_result.amount0_max.to_big_int(),
)?,
amount1: CurrencyAmount::from_raw_amount(
currency1,
call_result.amount1_max.to_big_int(),
)?,
tick_upper: modify_event.tick_upper,
tick_lower: modify_event.tick_lower,
tx_hash,
})
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
pool_manager_address = ?self.pool_manager_address(),
pool_id = ?self.pool_id(),
token_id = ?params.token_id,
liquidity = ?params.liquidity
))]
async fn remove_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveLiquidityResult> {
let call_result = $crate::pool_infusers::v4::build_remove_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_result.method_parameters.calldata.len(),
value = ?call_result.method_parameters.value,
amount0_min = ?call_result.amount0_min,
amount1_min = ?call_result.amount1_min,
liquidity = ?call_result.liquidity,
"Remove liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_result.method_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove liquidity transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
use alloy::primitives::aliases::U128;
use uniswap_sdk_core::prelude::{CurrencyAmount, ToBig};
let (modify_event, tx_hash) = $crate::pool_infusers::v4::decode_modify_liquidity_event_with_pool_id(
&receipt,
self.pool_manager_address(),
self.pool_id(),
)?;
let liquidity_u256 = modify_event.liquidity_delta.unsigned_abs();
let liquidity_u128 = liquidity_u256
.to::<u128>();
Ok($crate::types::swap_results::RemoveLiquidityResult {
token_id: modify_event.token_id,
liquidity: U128::from(liquidity_u128),
amount0: CurrencyAmount::from_raw_amount(
currency0.clone(),
call_result.amount0_min.to_big_int(),
)?,
amount1: CurrencyAmount::from_raw_amount(
currency1.clone(),
call_result.amount1_min.to_big_int(),
)?,
amount0_from_liquidity: CurrencyAmount::from_raw_amount(
currency0.clone(),
call_result.amount0_min.to_big_int(),
)?,
amount1_from_liquidity: CurrencyAmount::from_raw_amount(
currency1.clone(),
call_result.amount1_min.to_big_int(),
)?,
recipient: Some(params.recipient),
tick_upper: modify_event.tick_upper,
tick_lower: modify_event.tick_lower,
tx_hash,
})
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
pool_manager_address = ?self.pool_manager_address(),
pool_id = ?self.pool_id(),
token_id = ?params.token_id
))]
async fn collect(
&self,
params: $crate::traits::pool_infuser::CollectParams,
options: $crate::traits::pool_infuser::CollectOptions,
) -> anyhow::Result<$crate::types::swap_results::CollectResult> {
let call_parameters = $crate::pool_infusers::v4::build_collect_call_parameters(
&self.pool_key,
¶ms,
&options,
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
"Collect call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Collect transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Collect transaction failed"
);
return Err(anyhow::anyhow!("Collect transaction failed"));
}
let currency0 = self.pool_key.token_a.clone();
let currency1 = self.pool_key.token_b.clone();
let (modify_event, tx_hash) = $crate::pool_infusers::v4::decode_modify_liquidity_event_with_pool_id(
&receipt,
self.pool_manager_address(),
self.pool_id(),
)?;
Ok($crate::types::swap_results::CollectResult {
token_id: params.token_id,
recipient: params.recipient,
amount0: uniswap_sdk_core::prelude::CurrencyAmount::from_raw_amount(
currency0.clone(),
uniswap_sdk_core::prelude::BigInt::from(0), )?,
amount1: uniswap_sdk_core::prelude::CurrencyAmount::from_raw_amount(
currency1.clone(),
uniswap_sdk_core::prelude::BigInt::from(0), )?,
tick_upper: modify_event.tick_upper,
tick_lower: modify_event.tick_lower,
reward_amounts: None,
tx_hash,
})
}
#[tracing::instrument(skip(self, _amount, _block_id), fields(
position_manager_address = ?self.position_manager_address()
))]
async fn calculate_add_liquidity_amounts(
&self,
_amount: uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
_block_id: Option<alloy::eips::BlockId>,
) -> anyhow::Result<(
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
uniswap_sdk_core::prelude::CurrencyAmount<uniswap_sdk_core::prelude::Currency>,
)> {
Err(anyhow::anyhow!(
"calculate_add_liquidity_amounts not yet implemented. This requires querying pool \
state and using Position calculations."
))
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
pool_manager_address = ?self.pool_manager_address(),
pool_id = ?self.pool_id(),
num_positions = params.items.len()
))]
async fn add_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::AddBatchLiquidityParams,
options: $crate::traits::pool_infuser::AddLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::AddBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::v4::build_add_batch_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
num_positions = params.items.len(),
"Add batch liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Add batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Add batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Add batch liquidity transaction failed"));
}
Ok($crate::types::swap_results::AddBatchLiquidityResult {
results: Vec::new(), tx_hash: receipt.transaction_hash,
})
}
#[tracing::instrument(skip(self, params, options), fields(
position_manager_address = ?self.position_manager_address(),
pool_manager_address = ?self.pool_manager_address(),
pool_id = ?self.pool_id(),
num_positions = params.items.len()
))]
async fn remove_batch_liquidity(
&self,
params: $crate::traits::pool_infuser::RemoveBatchLiquidityParams,
options: $crate::traits::pool_infuser::RemoveLiquidityOptions,
) -> anyhow::Result<$crate::types::swap_results::RemoveBatchLiquidityResult> {
let call_parameters = $crate::pool_infusers::v4::build_remove_batch_liquidity_call_parameters(
&self.pool_key,
params.clone(),
options.clone(),
)?;
tracing::debug!(
calldata_len = call_parameters.calldata.len(),
value = ?call_parameters.value,
num_positions = params.items.len(),
"Remove batch liquidity call parameters built"
);
let tx = $crate::pool_swappers::common::build_transaction_with_gas_prices(
&self.provider,
self.sender_address(),
self.position_manager_address(),
call_parameters,
None::<$crate::types::swap_params::GasPriceOptions>,
)
.await?;
let receipt = $crate::pool_swappers::common::send_and_wait_for_transaction(
&self.provider,
tx,
Some(std::time::Duration::from_secs(60)),
None::<fn(Box<dyn std::fmt::Display + Send + Sync>) -> anyhow::Error>,
)
.await?;
tracing::info!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
gas_used = ?receipt.gas_used,
status = ?receipt.status(),
"Remove batch liquidity transaction confirmed"
);
if !receipt.status() {
tracing::error!(
tx_hash = ?receipt.transaction_hash,
block_number = ?receipt.block_number,
"Remove batch liquidity transaction failed"
);
return Err(anyhow::anyhow!("Remove batch liquidity transaction failed"));
}
Ok($crate::types::swap_results::RemoveBatchLiquidityResult {
results: Vec::new(), tx_hash: receipt.transaction_hash,
})
}
}
};
}