Skip to content

Commit

Permalink
feat: refactor and add Multicall trait (#98)
Browse files Browse the repository at this point in the history
* feat: refactor and add `Multicall` trait

Refactor `encode_multicall` and `decode_multicall` to be more generic and implement the `Multicall` trait for various types. This improves the flexibility and reusability of multicall encoding and decoding operations.

* Replace asserts with error handling in pool.rs

Converted assert! macro usage to return errors in the `current_liquidity` and `amount_specified_remaining` methods. This improves the code by providing more informative error handling and avoids potential panics. Additionally, updated the `uniswap_v3_math` dependency to version 0.5.2 in Cargo.toml.
  • Loading branch information
shuhuiluo authored Oct 23, 2024
1 parent 175286f commit 53f94f4
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 18 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "uniswap-v3-sdk"
version = "2.2.0"
version = "2.3.0"
edition = "2021"
authors = ["Shuhui Luo <twitter.com/aureliano_law>"]
description = "Uniswap V3 SDK for Rust"
Expand Down Expand Up @@ -43,7 +43,7 @@ alloy-signer-local = "0.5"
criterion = "0.5.1"
dotenv = "0.15.0"
tokio = { version = "1.40", features = ["full"] }
uniswap_v3_math = "0.5.1"
uniswap_v3_math = "0.5.2"

[[bench]]
name = "bit_math"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ It is feature-complete with unit tests matching the TypeScript SDK.
Add the following to your `Cargo.toml` file:

```toml
uniswap-v3-sdk = { version = "2.2.0", features = ["extensions", "std"] }
uniswap-v3-sdk = { version = "2.3.0", features = ["extensions", "std"] }
```

### Usage
Expand Down
8 changes: 6 additions & 2 deletions src/entities/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,9 @@ impl<TP: Clone + TickDataProvider> Pool<TP> {
input_amount: &CurrencyAmount<impl BaseCurrency>,
sqrt_price_limit_x96: Option<U160>,
) -> Result<(CurrencyAmount<&Token>, Self), Error> {
assert!(self.involves_token(&input_amount.currency), "TOKEN");
if !self.involves_token(&input_amount.currency) {
return Err(Error::InvalidToken);
}

let zero_for_one = input_amount.currency.equals(&self.token0);

Expand Down Expand Up @@ -324,7 +326,9 @@ impl<TP: Clone + TickDataProvider> Pool<TP> {
output_amount: &CurrencyAmount<impl BaseCurrency>,
sqrt_price_limit_x96: Option<U160>,
) -> Result<(CurrencyAmount<&Token>, Self), Error> {
assert!(self.involves_token(&output_amount.currency), "TOKEN");
if !self.involves_token(&output_amount.currency) {
return Err(Error::InvalidToken);
}

let zero_for_one = output_amount.currency.equals(&self.token1);

Expand Down
58 changes: 45 additions & 13 deletions src/multicall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use alloy_sol_types::{Error, SolCall};

#[inline]
#[must_use]
pub fn encode_multicall(data: Vec<Bytes>) -> Bytes {
pub fn encode_multicall<B: Into<Bytes>>(data: Vec<B>) -> Bytes {
let data: Vec<Bytes> = data.into_iter().map(Into::into).collect();
if data.len() == 1 {
data[0].clone()
} else {
Expand All @@ -13,10 +14,41 @@ pub fn encode_multicall(data: Vec<Bytes>) -> Bytes {
}

#[inline]
pub fn decode_multicall(encoded: &Bytes) -> Result<Vec<Bytes>, Error> {
IMulticall::multicallCall::abi_decode(encoded.as_ref(), true).map(|decoded| decoded.data)
pub fn decode_multicall<B, E>(encoded: E) -> Result<Vec<B>, Error>
where
E: AsRef<[u8]>,
B: From<Bytes>,
{
IMulticall::multicallCall::abi_decode(encoded.as_ref(), true)
.map(|decoded| decoded.data.into_iter().map(Into::into).collect())
}

pub trait Multicall: Sized {
fn encode_multicall(self) -> Bytes;

fn decode_multicall<E: AsRef<[u8]>>(encoded: E) -> Result<Self, Error>;
}

macro_rules! impl_multicall {
($($t:ty),*) => {
$(
impl Multicall for $t {
#[inline]
fn encode_multicall(self) -> Bytes {
encode_multicall(self)
}

#[inline]
fn decode_multicall<E: AsRef<[u8]>>(encoded: E) -> Result<Self, Error> {
decode_multicall(encoded)
}
}
)*
};
}

impl_multicall!(Vec<Bytes>, Vec<Vec<u8>>);

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -27,15 +59,15 @@ mod tests {

#[test]
fn test_string_array_len_1() {
let calldata = encode_multicall(vec![vec![0x01].into()]);
let calldata = vec![vec![0x01]].encode_multicall();
assert_eq!(calldata, vec![0x01]);
}

#[test]
fn test_string_array_len_2() {
let calldata = encode_multicall(vec![
hex!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").into(),
hex!("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb").into(),
hex!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
hex!("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
]);
assert_eq!(
calldata.to_vec(),
Expand All @@ -49,18 +81,18 @@ mod tests {

#[test]
fn test_string_array_len_2() {
let calldatas = vec![
hex!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").into(),
hex!("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb").into(),
let calldata_list = vec![
hex!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
hex!("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
];
let multicall = encode_multicall(calldatas.clone());
let encoded = encode_multicall(calldata_list.clone());
assert_eq!(
multicall.to_vec(),
encoded.to_vec(),
hex!("ac9650d800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000000000000000000000000000000000000000000000000000000000020bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
);

let decoded_calldata = decode_multicall(&multicall).unwrap();
assert_eq!(decoded_calldata, calldatas);
let decoded_calldata: Vec<Vec<u8>> = Multicall::decode_multicall(encoded).unwrap();
assert_eq!(decoded_calldata, calldata_list);
}
}
}

0 comments on commit 53f94f4

Please sign in to comment.