Skip to content

Commit f2b5427

Browse files
authored
feat(error): Add custom error handling to improve robustness (#12)
Introduce `Error` enum for consistent error management and integrate `thiserror` for better error descriptions. Update functions to use the new error handling, replacing `anyhow::Result` with `Result<T, Error>`, and refactor tests to unwrap results for simplicity.
1 parent 47d1d97 commit f2b5427

File tree

7 files changed

+129
-94
lines changed

7 files changed

+129
-94
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ include = ["src/**/*.rs"]
1313
[dependencies]
1414
alloy = { version = "0.3", features = ["contract", "rpc-types"] }
1515
anyhow = "1"
16+
thiserror = { version = "1.0", optional = true }
1617

1718
[features]
1819
default = []
19-
std = ["alloy/std"]
20+
std = ["alloy/std", "thiserror"]
2021

2122
[dev-dependencies]
2223
alloy = { version = "0.3", features = ["transport-http"] }

src/caller.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ macro_rules! call_ephemeral_contract {
77
None => $deploy_builder,
88
};
99
match deploy_builder.call_raw().await {
10-
Err(Error::TransportError(err)) => match err {
11-
TransportError::ErrorResp(payload) => {
12-
let data: Bytes = payload.as_revert_data().unwrap();
13-
Ok(<$call_type>::abi_decode_returns(data.as_ref(), true).unwrap())
10+
Err(ContractError::TransportError(TransportError::ErrorResp(payload))) => {
11+
match payload.as_revert_data() {
12+
Some(data) => Ok(<$call_type as SolCall>::abi_decode_returns(
13+
data.as_ref(),
14+
true,
15+
)?),
16+
None => Err(Error::InvalidRevertData),
1417
}
15-
_ => panic!("should be an error response: {:?}", err),
16-
},
17-
Err(err) => Err(err),
18+
}
19+
Err(err) => Err(Error::ContractError(err)),
1820
Ok(_) => panic!("deployment should revert"),
1921
}
2022
}};

src/error.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use alloy::{contract::Error as ContractError, sol_types::Error as AbiError};
2+
3+
#[derive(Debug)]
4+
#[cfg_attr(feature = "std", derive(thiserror::Error))]
5+
pub enum Error {
6+
/// An error occurred retrieving the revert data.
7+
#[cfg_attr(feature = "std", error("Invalid revert data"))]
8+
InvalidRevertData,
9+
10+
/// An error occurred ABI encoding or decoding.
11+
#[cfg_attr(feature = "std", error("{0}"))]
12+
AbiError(AbiError),
13+
14+
/// An error occurred interacting with a contract over RPC.
15+
#[cfg_attr(feature = "std", error("{0}"))]
16+
ContractError(ContractError),
17+
}
18+
19+
impl From<AbiError> for Error {
20+
#[inline]
21+
fn from(e: AbiError) -> Self {
22+
Self::AbiError(e)
23+
}
24+
}
25+
26+
impl From<ContractError> for Error {
27+
#[inline]
28+
fn from(e: ContractError) -> Self {
29+
Self::ContractError(e)
30+
}
31+
}

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ extern crate alloc;
2020
#[allow(warnings)]
2121
pub mod bindings;
2222
pub mod caller;
23+
pub mod error;
2324
pub mod pool_lens;
2425
pub mod position_lens;
2526
pub mod storage_lens;
@@ -28,5 +29,5 @@ pub mod storage_lens;
2829
mod tests;
2930

3031
pub mod prelude {
31-
pub use super::{bindings::*, pool_lens::*, position_lens::*, storage_lens::*};
32+
pub use super::{error::Error, pool_lens::*, position_lens::*, storage_lens::*};
3233
}

src/pool_lens.rs

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,29 @@
55
use crate::{
66
bindings::{
77
ephemeralgetpopulatedticksinrange::{
8+
EphemeralGetPopulatedTicksInRange,
89
EphemeralGetPopulatedTicksInRange::{
910
getPopulatedTicksInRangeCall, getPopulatedTicksInRangeReturn,
10-
EphemeralGetPopulatedTicksInRangeInstance,
1111
},
1212
PoolUtils::PopulatedTick,
1313
},
14-
ephemeralpoolpositions::{
15-
EphemeralPoolPositions::EphemeralPoolPositionsInstance, PoolUtils::PositionKey,
16-
},
14+
ephemeralpoolpositions::{EphemeralPoolPositions, PoolUtils::PositionKey},
1715
ephemeralpoolslots::{
18-
EphemeralPoolSlots::{getSlotsCall, getSlotsReturn, EphemeralPoolSlotsInstance},
16+
EphemeralPoolSlots,
17+
EphemeralPoolSlots::{getSlotsCall, getSlotsReturn},
1918
PoolUtils::Slot,
2019
},
21-
ephemeralpooltickbitmap::EphemeralPoolTickBitmap::EphemeralPoolTickBitmapInstance,
22-
ephemeralpoolticks::EphemeralPoolTicks::EphemeralPoolTicksInstance,
20+
ephemeralpooltickbitmap::EphemeralPoolTickBitmap,
21+
ephemeralpoolticks::EphemeralPoolTicks,
2322
},
2423
call_ephemeral_contract,
24+
error::Error,
2525
};
2626
use alloc::vec::Vec;
2727
use alloy::{
28-
contract::Error,
28+
contract::Error as ContractError,
2929
eips::BlockId,
30-
primitives::{aliases::I24, Address, Bytes},
30+
primitives::{aliases::I24, Address},
3131
providers::Provider,
3232
sol_types::SolCall,
3333
transports::{Transport, TransportError},
@@ -54,14 +54,13 @@ pub async fn get_populated_ticks_in_range<T, P>(
5454
tick_upper: I24,
5555
provider: P,
5656
block_id: Option<BlockId>,
57-
) -> Result<(Vec<PopulatedTick>, I24)>
57+
) -> Result<(Vec<PopulatedTick>, I24), Error>
5858
where
5959
T: Transport + Clone,
6060
P: Provider<T>,
6161
{
62-
let deploy_builder = EphemeralGetPopulatedTicksInRangeInstance::deploy_builder(
63-
provider, pool, tick_lower, tick_upper,
64-
);
62+
let deploy_builder =
63+
EphemeralGetPopulatedTicksInRange::deploy_builder(provider, pool, tick_lower, tick_upper);
6564
match call_ephemeral_contract!(deploy_builder, getPopulatedTicksInRangeCall, block_id) {
6665
Ok(getPopulatedTicksInRangeReturn {
6766
populatedTicks,
@@ -73,7 +72,7 @@ where
7372
.collect(),
7473
tickSpacing,
7574
)),
76-
Err(err) => Err(err.into()),
75+
Err(err) => Err(err),
7776
}
7877
}
7978

@@ -103,15 +102,12 @@ pub async fn get_static_slots<T, P>(
103102
pool: Address,
104103
provider: P,
105104
block_id: Option<BlockId>,
106-
) -> Result<Vec<Slot>>
105+
) -> Result<Vec<Slot>, Error>
107106
where
108107
T: Transport + Clone,
109108
P: Provider<T>,
110109
{
111-
get_pool_storage!(
112-
EphemeralPoolSlotsInstance::deploy_builder(provider, pool),
113-
block_id
114-
)
110+
get_pool_storage!(EphemeralPoolSlots::deploy_builder(provider, pool), block_id)
115111
}
116112

117113
/// Get the storage slots in the `ticks` mapping between `tick_lower` and `tick_upper`.
@@ -134,13 +130,13 @@ pub async fn get_ticks_slots<T, P>(
134130
tick_upper: I24,
135131
provider: P,
136132
block_id: Option<BlockId>,
137-
) -> Result<Vec<Slot>>
133+
) -> Result<Vec<Slot>, Error>
138134
where
139135
T: Transport + Clone,
140136
P: Provider<T>,
141137
{
142138
get_pool_storage!(
143-
EphemeralPoolTicksInstance::deploy_builder(provider, pool, tick_lower, tick_upper),
139+
EphemeralPoolTicks::deploy_builder(provider, pool, tick_lower, tick_upper),
144140
block_id
145141
)
146142
}
@@ -160,13 +156,13 @@ pub async fn get_tick_bitmap_slots<T, P>(
160156
pool: Address,
161157
provider: P,
162158
block_id: Option<BlockId>,
163-
) -> Result<Vec<Slot>>
159+
) -> Result<Vec<Slot>, Error>
164160
where
165161
T: Transport + Clone,
166162
P: Provider<T>,
167163
{
168164
get_pool_storage!(
169-
EphemeralPoolTickBitmapInstance::deploy_builder(provider, pool),
165+
EphemeralPoolTickBitmap::deploy_builder(provider, pool),
170166
block_id
171167
)
172168
}
@@ -188,13 +184,13 @@ pub async fn get_positions_slots<T, P>(
188184
positions: Vec<PositionKey>,
189185
provider: P,
190186
block_id: Option<BlockId>,
191-
) -> Result<Vec<Slot>>
187+
) -> Result<Vec<Slot>, Error>
192188
where
193189
T: Transport + Clone,
194190
P: Provider<T>,
195191
{
196192
get_pool_storage!(
197-
EphemeralPoolPositionsInstance::deploy_builder(provider, pool, positions),
193+
EphemeralPoolPositions::deploy_builder(provider, pool, positions),
198194
block_id
199195
)
200196
}
@@ -203,28 +199,35 @@ where
203199
mod tests {
204200
use super::*;
205201
use crate::{
206-
bindings::iuniswapv3pool::IUniswapV3Pool::{IUniswapV3PoolInstance, Mint},
202+
bindings::iuniswapv3pool::{IUniswapV3Pool, IUniswapV3Pool::Mint},
207203
tests::*,
208204
};
209205
use alloy::{primitives::address, rpc::types::Filter, sol_types::SolEvent};
210-
use anyhow::Result;
211206
use futures::future::join_all;
212207

213208
const POOL_ADDRESS: Address = address!("88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640");
209+
214210
#[tokio::test]
215-
async fn test_get_populated_ticks_in_range() -> Result<()> {
211+
async fn test_get_populated_ticks_in_range() {
216212
let provider = PROVIDER.clone();
217-
let pool = IUniswapV3PoolInstance::new(POOL_ADDRESS, provider.clone());
218-
let tick_current = pool.slot0().block(BLOCK_NUMBER).call().await?.tick;
219-
let tick_spacing = pool.tickSpacing().block(BLOCK_NUMBER).call().await?._0;
213+
let pool = IUniswapV3Pool::new(POOL_ADDRESS, provider.clone());
214+
let tick_current = pool.slot0().block(BLOCK_NUMBER).call().await.unwrap().tick;
215+
let tick_spacing = pool
216+
.tickSpacing()
217+
.block(BLOCK_NUMBER)
218+
.call()
219+
.await
220+
.unwrap()
221+
._0;
220222
let (ticks, _) = get_populated_ticks_in_range(
221223
POOL_ADDRESS,
222224
tick_current,
223225
tick_current + (tick_spacing << 8),
224226
provider,
225227
Some(BLOCK_NUMBER),
226228
)
227-
.await?;
229+
.await
230+
.unwrap();
228231
assert!(!ticks.is_empty());
229232
// let mut multicall = Multicall::new(client.clone(), None).await?;
230233
// multicall.add_calls(
@@ -254,7 +257,6 @@ mod tests {
254257
// assert_eq!(liquidity_gross, _liquidity_gross);
255258
// assert_eq!(liquidity_net, _liquidity_net);
256259
// }
257-
Ok(())
258260
}
259261

260262
async fn verify_slots<T, P>(slots: Vec<Slot>, provider: P)
@@ -287,7 +289,7 @@ mod tests {
287289
#[tokio::test]
288290
async fn test_get_ticks_slots() {
289291
let provider = PROVIDER.clone();
290-
let pool = IUniswapV3PoolInstance::new(POOL_ADDRESS, provider.clone());
292+
let pool = IUniswapV3Pool::new(POOL_ADDRESS, provider.clone());
291293
let tick_current = pool.slot0().block(BLOCK_NUMBER).call().await.unwrap().tick;
292294
let slots = get_ticks_slots(
293295
POOL_ADDRESS,
@@ -311,14 +313,14 @@ mod tests {
311313
}
312314

313315
#[tokio::test]
314-
async fn test_get_positions_slots() -> Result<()> {
316+
async fn test_get_positions_slots() {
315317
let provider = PROVIDER.clone();
316318
// create a filter to get the mint events
317319
let filter = Filter::new()
318320
.from_block(BLOCK_NUMBER.as_u64().unwrap() - 10000)
319321
.to_block(BLOCK_NUMBER.as_u64().unwrap())
320322
.event_signature(<Mint as SolEvent>::SIGNATURE_HASH);
321-
let logs = provider.get_logs(&filter).await?;
323+
let logs = provider.get_logs(&filter).await.unwrap();
322324
// decode the logs into position keys
323325
let positions: Vec<_> = logs
324326
.iter()
@@ -343,8 +345,8 @@ mod tests {
343345
provider.clone(),
344346
Some(BLOCK_NUMBER),
345347
)
346-
.await?;
348+
.await
349+
.unwrap();
347350
verify_slots(slots, provider).await;
348-
Ok(())
349351
}
350352
}

0 commit comments

Comments
 (0)