Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: consolidate currency-related traits and add Currency enum #85

Merged
merged 1 commit into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "uniswap-sdk-core"
version = "2.4.0"
version = "3.0.0"
edition = "2021"
authors = ["malik <[email protected]>", "Shuhui Luo <twitter.com/aureliano_law>"]
description = "The Uniswap SDK Core in Rust provides essential functionality for interacting with the Uniswap decentralized exchange"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Add this to your Cargo.toml

```
[dependencies]
uniswap-sdk-core = "2.4.0"
uniswap-sdk-core = "3.0.0"
```

And this to your code:
Expand Down
22 changes: 18 additions & 4 deletions src/entities/base_currency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,21 @@ use alloy_primitives::ChainId;

/// A currency is any fungible financial instrument, including Ether, all ERC20 tokens, and other
/// chain-native currencies
pub trait BaseCurrency {
pub trait BaseCurrency: BaseCurrencyCore + Clone {
/// Returns the address of the currency.
#[inline]
fn address(&self) -> Address {
self.wrapped().address
}

/// Returns whether this currency is functionally equivalent to the other currency
fn equals(&self, other: &impl BaseCurrency) -> bool;
shuhuiluo marked this conversation as resolved.
Show resolved Hide resolved

/// Returns a Token that represents the wrapped equivalent of the native currency
fn wrapped(&self) -> &Token;
}

pub trait BaseCurrencyCore {
/// Returns whether the currency is native to the chain and must be wrapped (e.g. Ether)
fn is_native(&self) -> bool;

Expand All @@ -23,10 +37,10 @@ pub trait BaseCurrency {
fn name(&self) -> Option<&String>;
}

macro_rules! impl_base_currency {
macro_rules! impl_base_currency_core {
($($currency:ty),*) => {
$(
impl<const IS_NATIVE: bool, M> BaseCurrency for $currency {
impl<const IS_NATIVE: bool, M> BaseCurrencyCore for $currency {
#[inline]
fn is_native(&self) -> bool {
IS_NATIVE
Expand Down Expand Up @@ -61,4 +75,4 @@ macro_rules! impl_base_currency {
};
}

impl_base_currency!(CurrencyLike<IS_NATIVE, M>, &CurrencyLike<IS_NATIVE, M>);
impl_base_currency_core!(CurrencyLike<IS_NATIVE, M>, &CurrencyLike<IS_NATIVE, M>);
79 changes: 65 additions & 14 deletions src/entities/currency.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
use crate::prelude::*;
use alloy_primitives::ChainId;

/// Trait for representing a currency in the Uniswap Core SDK.
pub trait Currency: BaseCurrency + Clone {
/// Returns the address of the currency.
#[inline]
fn address(&self) -> Address {
self.wrapped().address
}

/// Returns whether this currency is functionally equivalent to the other currency
fn equals(&self, other: &impl Currency) -> bool;

/// Returns a Token that represents the wrapped equivalent of the native currency
fn wrapped(&self) -> &Token;
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Currency {
NativeCurrency(Ether),
Token(Token),
}

/// [`CurrencyLike`] is a generic struct representing a currency with a specific chain ID,
/// decimals, symbol, name, and additional metadata.
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct CurrencyLike<const IS_NATIVE: bool, M> {
/// The chain ID on which this currency resides
pub chain_id: alloy_primitives::ChainId,
pub chain_id: ChainId,

/// The decimals for the particular currency
pub decimals: u8,
Expand All @@ -45,6 +37,65 @@ impl<const IS_NATIVE: bool, M> Deref for CurrencyLike<IS_NATIVE, M> {
}
}

macro_rules! match_currency_method {
($method:ident, $return_type:ty) => {
#[inline]
fn $method(&self) -> $return_type {
match self {
Currency::NativeCurrency(ether) => ether.$method(),
Currency::Token(token) => token.$method(),
}
}
};
}
shuhuiluo marked this conversation as resolved.
Show resolved Hide resolved

macro_rules! impl_base_currency_core {
($($currency:ty),*) => {
$(
impl BaseCurrencyCore for $currency {
#[inline]
fn is_native(&self) -> bool {
matches!(self, Currency::NativeCurrency(_))
}

#[inline]
fn is_token(&self) -> bool {
matches!(self, Currency::Token(_))
}

match_currency_method!(chain_id, ChainId);

match_currency_method!(decimals, u8);

match_currency_method!(symbol, Option<&String>);

match_currency_method!(name, Option<&String>);
}
)*
};
}

macro_rules! impl_base_currency {
($($currency:ty),*) => {
$(
impl BaseCurrency for $currency {
#[inline]
fn equals(&self, other: &impl BaseCurrency) -> bool {
match self {
Currency::NativeCurrency(ether) => ether.equals(other),
Currency::Token(token) => token.equals(other),
}
}

match_currency_method!(wrapped, &Token);
}
)*
};
}

impl_base_currency_core!(Currency, &Currency);
impl_base_currency!(Currency, &Currency);
shuhuiluo marked this conversation as resolved.
Show resolved Hide resolved

#[cfg(test)]
mod tests {
use super::*;
Expand Down
8 changes: 4 additions & 4 deletions src/entities/ether.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use crate::prelude::*;
/// Represents the native currency of the blockchain.
pub type Ether = CurrencyLike<true, Option<Token>>;

macro_rules! impl_currency {
macro_rules! impl_base_currency {
($($ether:ty),*) => {
$(
impl Currency for $ether {
impl BaseCurrency for $ether {
#[inline]
fn equals(&self, other: &impl Currency) -> bool {
fn equals(&self, other: &impl BaseCurrency) -> bool {
other.is_native() && self.chain_id() == other.chain_id()
}

Expand All @@ -25,7 +25,7 @@ macro_rules! impl_currency {
};
}

impl_currency!(Ether, &Ether);
impl_base_currency!(Ether, &Ether);

impl Ether {
/// Creates a new instance of [`Ether`] with the specified chain ID.
Expand Down
4 changes: 2 additions & 2 deletions src/entities/fractions/currency_amount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ pub type CurrencyAmount<T> = FractionLike<CurrencyMeta<T>>;

/// Struct representing metadata about a currency
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct CurrencyMeta<T: Currency> {
pub struct CurrencyMeta<T: BaseCurrency> {
/// The currency associated with this metadata
pub currency: T,
/// The scale factor for the currency's decimal places
pub decimal_scale: BigUint,
}

impl<T: Currency> CurrencyAmount<T> {
impl<T: BaseCurrency> CurrencyAmount<T> {
/// Constructor method for creating a new currency amount
#[inline]
fn new(
Expand Down
10 changes: 5 additions & 5 deletions src/entities/fractions/price.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ pub type Price<TBase, TQuote> = FractionLike<PriceMeta<TBase, TQuote>>;
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct PriceMeta<TBase, TQuote>
where
TBase: Currency,
TQuote: Currency,
TBase: BaseCurrency,
TQuote: BaseCurrency,
{
/// The base currency for the price
pub base_currency: TBase,
Expand All @@ -23,8 +23,8 @@ where

impl<TBase, TQuote> Price<TBase, TQuote>
where
TBase: Currency,
TQuote: Currency,
TBase: BaseCurrency,
TQuote: BaseCurrency,
{
/// Constructor for creating a new [`Price`] instance
#[inline]
Expand Down Expand Up @@ -79,7 +79,7 @@ where
/// Multiply the price by another price, returning a new price.
/// The other price must have the same base currency as this price's quote currency.
#[inline]
pub fn multiply<TOtherQuote: Currency>(
pub fn multiply<TOtherQuote: BaseCurrency>(
&self,
other: &Price<TQuote, TOtherQuote>,
) -> Result<Price<TBase, TOtherQuote>, Error> {
Expand Down
2 changes: 1 addition & 1 deletion src/entities/native_currency.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::prelude::*;

/// Represents the native currency of the chain on which it resides
pub trait NativeCurrency: BaseCurrency {
pub trait NativeCurrency: BaseCurrencyCore {
#[inline]
fn is_native(&self) -> bool {
true
Expand Down
8 changes: 4 additions & 4 deletions src/entities/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ pub struct TokenMeta {
pub sell_fee_bps: Option<BigUint>,
}

macro_rules! impl_currency {
macro_rules! impl_base_currency {
($($token:ty),*) => {
$(
impl Currency for $token {
impl BaseCurrency for $token {
#[inline]
fn equals(&self, other: &impl Currency) -> bool {
fn equals(&self, other: &impl BaseCurrency) -> bool {
other.is_token() && self.chain_id == other.chain_id() && self.address == other.address()
}

Expand All @@ -32,7 +32,7 @@ macro_rules! impl_currency {
};
}

impl_currency!(Token, &Token);
impl_base_currency!(Token, &Token);

impl Token {
/// Creates a new [`Token`] with the given parameters.
Expand Down
4 changes: 2 additions & 2 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ pub use crate::{
chains::*,
constants::*,
entities::{
base_currency::BaseCurrency,
currency::{Currency, CurrencyLike},
base_currency::*,
currency::*,
ether::Ether,
fractions::{
currency_amount::CurrencyAmount,
Expand Down
2 changes: 1 addition & 1 deletion src/utils/compute_price_impact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::prelude::*;
///
/// returns: Percent
#[inline]
pub fn compute_price_impact<TBase: Currency, TQuote: Currency>(
pub fn compute_price_impact<TBase: BaseCurrency, TQuote: BaseCurrency>(
mid_price: &Price<TBase, TQuote>,
input_amount: &CurrencyAmount<TBase>,
output_amount: &CurrencyAmount<TQuote>,
Expand Down