Skip to content

Commit

Permalink
Merge pull request #11 from shuhuiluo/oop-the-rust-way
Browse files Browse the repository at this point in the history
impl, refactor and test fractions and currencies
  • Loading branch information
malik672 authored Dec 25, 2023
2 parents 02284bd + a1dfa52 commit 9e66f21
Show file tree
Hide file tree
Showing 14 changed files with 1,144 additions and 329 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Rust

on:
push:
branches:
- master
pull_request:

env:
CARGO_TERM_COLOR: always

jobs:
build:
name: Rust Tests
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- name: Cache Cargo registry
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Build
run: cargo build --verbose

- name: Run tests
run: cargo test --verbose
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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-rust"
version = "0.1.1"
version = "0.2.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
47 changes: 23 additions & 24 deletions src/entities/base_currency.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,28 @@
use super::{currency::CurrencyTrait, token::Token};

/// A currency is any fungible financial instrument, including Ether, all ERC20 tokens, and other chain-native currencies
#[derive(Clone, PartialEq)]
pub struct BaseCurrency {
pub chain_id: u32,
pub decimals: u32,
pub name: Option<String>,
pub symbol: Option<String>,
pub is_native: bool,
}
pub trait BaseCurrency: Clone {
/// The chain ID on which this currency resides
fn chain_id(&self) -> u32;

/// The decimals used in representing currency amounts
fn decimals(&self) -> u32;

/// The symbol of the currency, i.e. a short textual non-unique identifier
fn symbol(&self) -> Option<String>;

impl BaseCurrency {
pub fn new(chain_id: u32, decimals: u32, name: Option<String>, symbol: Option<String>) -> Self {
assert!(chain_id > 0, "CHAIN_ID");
assert!(decimals < 255, "DECIMALS");
/// The name of the currency, i.e. a descriptive textual non-unique identifier
fn name(&self) -> Option<String>;

Self {
chain_id,
decimals,
name,
symbol,
is_native: Self::is_native(),
}
}
/// Returns whether this currency is functionally equivalent to the other currency
///
/// # Arguments
///
/// * `other`: the other currency
///
fn equals(&self, other: &impl CurrencyTrait) -> bool;

/// Returns whether the currency is native to the chain and must be wrapped (e.g. Ether)
pub fn is_native() -> bool {
true
}
/// Return the wrapped version of this currency that can be used with the Uniswap contracts.
/// Currencies must implement this to be used in Uniswap
fn wrapped(&self) -> Token;
}
71 changes: 69 additions & 2 deletions src/entities/currency.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,74 @@
use super::{native_currency::NativeCurrency, token::Token};
use super::{base_currency::BaseCurrency, ether::Ether, token::Token};

#[derive(Clone, PartialEq)]
pub enum Currency {
NativeCurrency(NativeCurrency),
NativeCurrency(Ether),
Token(Token),
}

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

fn address(&self) -> String;
}

impl CurrencyTrait for Currency {
fn is_native(&self) -> bool {
match self {
Currency::NativeCurrency(_) => true,
Currency::Token(_) => false,
}
}

fn address(&self) -> String {
match self {
Currency::NativeCurrency(native_currency) => native_currency.address(),
Currency::Token(token) => token.address(),
}
}
}

impl BaseCurrency for Currency {
fn chain_id(&self) -> u32 {
match self {
Currency::NativeCurrency(native_currency) => native_currency.chain_id(),
Currency::Token(token) => token.chain_id(),
}
}

fn decimals(&self) -> u32 {
match self {
Currency::NativeCurrency(native_currency) => native_currency.decimals(),
Currency::Token(token) => token.decimals(),
}
}

fn symbol(&self) -> Option<String> {
match self {
Currency::NativeCurrency(native_currency) => native_currency.symbol(),
Currency::Token(token) => token.symbol(),
}
}

fn name(&self) -> Option<String> {
match self {
Currency::NativeCurrency(native_currency) => native_currency.name(),
Currency::Token(token) => token.name(),
}
}

fn equals(&self, other: &impl CurrencyTrait) -> bool {
match self {
Currency::NativeCurrency(native_currency) => native_currency.equals(other),
Currency::Token(token) => token.equals(other),
}
}

fn wrapped(&self) -> Token {
match self {
Currency::NativeCurrency(native_currency) => native_currency.wrapped(),
Currency::Token(token) => token.clone(),
}
}
}
79 changes: 53 additions & 26 deletions src/entities/ether.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{base_currency::BaseCurrency, token::Token};
use super::{base_currency::BaseCurrency, currency::CurrencyTrait, token::Token};
use crate::entities::weth9::WETH9;
use lazy_static::lazy_static;
use std::{collections::HashMap, sync::Mutex};

Expand All @@ -9,35 +10,32 @@ lazy_static! {
/// Ether is the main usage of a 'native' currency, i.e. for Ethereum mainnet and all testnets
#[derive(Clone, PartialEq)]
pub struct Ether {
base_currency: BaseCurrency,
wrapped: Token,
pub chain_id: u32,
pub decimals: u32,
pub symbol: Option<String>,
pub name: Option<String>,
}

impl CurrencyTrait for Ether {
fn is_native(&self) -> bool {
true
}

fn address(&self) -> String {
self.wrapped().address()
}
}

impl Ether {
pub fn new(chain_id: u32) -> Self {
Self {
base_currency: BaseCurrency::new(
chain_id,
18,
Some("Ether".to_string()),
Some("ETH".to_string()),
),
wrapped: Token::new(
chain_id,
"0x".to_string(),
18,
Some("WETH".to_string()),
Some("Wrapped Ether".to_string()),
None,
None,
),
chain_id,
decimals: 18,
symbol: Some("ETH".to_string()),
name: Some("Ether".to_string()),
}
}

pub fn wrapped(&self) -> &Token {
&self.wrapped
}

pub fn on_chain(chain_id: u32) -> Self {
let mut cache = ETHER_CACHE.lock().unwrap();
match cache.get(&chain_id) {
Expand All @@ -49,15 +47,44 @@ impl Ether {
}
}
}
}

impl BaseCurrency for Ether {
fn chain_id(&self) -> u32 {
self.chain_id
}

fn decimals(&self) -> u32 {
self.decimals
}

fn symbol(&self) -> Option<String> {
self.symbol.clone()
}

fn name(&self) -> Option<String> {
self.name.clone()
}

fn equals(&self, other: &impl CurrencyTrait) -> bool {
match other.is_native() {
true => self.chain_id() == other.chain_id(),
_ => false,
}
}

pub fn equals(&self, other: &BaseCurrency) -> bool {
other.is_native && other.chain_id == self.base_currency.chain_id
fn wrapped(&self) -> Token {
match WETH9::default().get(self.chain_id()) {
Some(weth9) => weth9.clone(),
None => panic!("WRAPPED"),
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::entities::currency::Currency;

#[test]
fn test_static_constructor_uses_cache() {
Expand All @@ -71,11 +98,11 @@ mod tests {

#[test]
fn test_equals_returns_false_for_different_chains() {
assert!(!Ether::on_chain(1).equals(&Ether::on_chain(2).base_currency));
assert!(!Ether::on_chain(1).equals(&Currency::NativeCurrency(Ether::on_chain(2))));
}

#[test]
fn test_equals_returns_true_for_same_chains() {
assert!(Ether::on_chain(1).equals(&Ether::on_chain(1).base_currency));
assert!(Ether::on_chain(1).equals(&Currency::NativeCurrency(Ether::on_chain(1))));
}
}
Loading

0 comments on commit 9e66f21

Please sign in to comment.