Skip to content

Commit

Permalink
Merge pull request #4 from input-output-hk/LW-5228
Browse files Browse the repository at this point in the history
LW 5228
  • Loading branch information
will-break-it authored Apr 21, 2023
2 parents 049a4c2 + 1d9a2d9 commit 7a65741
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 59 deletions.
16 changes: 11 additions & 5 deletions src/reducers/liquidity_by_token_pair/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
This reducer intends to aggregate changes across different AMM DEXs (decentralized exchanges). It currently supports the most popular ones which includes:

- MinSwap
- Muesliswap
- SundaeSwap
- Wingriders

Note, that Muesliswap is not a pure AMM DEX and therefore, its liquidity for different token pairs cannot be indexed in a similar way.
### Note

> Muesliswap is considered a hybrid DEX, offering orderbook liquidity and liquidity via pool in form of an AMM DEX. This reducer currently only observes its liquidity pools.
## Configuration

Expand Down Expand Up @@ -44,12 +47,13 @@ Therefore, `_` denotes the start or end of a specific part of a key.

### Redis Value Schema

The reducer's value is a set. Each entry is a single liquidity source that is json encoded. A single member can contain up to four fields:
The reducer's value is a set. Each entry is a single liquidity source that is json encoded. A single member can contain up to five fields:

- dex specific prefix to identify the origin of the liquidity source
- amount of token a
- amount of token b
- a decimal number defining the fee of the liquidity source that's paid to liquidity providers
- a decimal number defining the fee of the liquidity source that's paid to liquidity providers _(optional)_
- a pool_id encoded base16 \*(optional)\_ only available for Sundaeswap liquidity pools

Below you can find the general schema for a JSON encoded member:

Expand All @@ -58,7 +62,8 @@ Below you can find the general schema for a JSON encoded member:
"token_a": string,
"token_b": string,
"dex": string,
"fee": number
"fee": number,
"pool_id": string
}
```

Expand All @@ -69,7 +74,8 @@ Example ADA/MIN liquidity source from SundaeSwap DEX:
"token_a": "31249392392",
"token_b": "1323123231221",
"dex": "sun",
"fee": 0.003
"fee": 0.003,
"pool_id": "2d01"
}
```

Expand Down
21 changes: 19 additions & 2 deletions src/reducers/liquidity_by_token_pair/minswap.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
use super::model::TokenPair;
use pallas::ledger::primitives::babbage::PlutusData;

pub type MinSwapPoolDatum = TokenPair;
use super::model::{PoolAsset, TokenPair};

pub struct MinSwapPoolDatum {
pub a: PoolAsset,
pub b: PoolAsset,
}

impl TryFrom<&PlutusData> for MinSwapPoolDatum {
type Error = ();

fn try_from(value: &PlutusData) -> Result<Self, Self::Error> {
if let Some(TokenPair { a, b }) = TokenPair::try_from(value).ok() {
return Ok(Self { a, b });
}

Err(())
}
}

#[cfg(test)]
mod test {
Expand Down
43 changes: 10 additions & 33 deletions src/reducers/liquidity_by_token_pair/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use lazy_static::__Deref;
use pallas::ledger::{
primitives::babbage::PlutusData,
traverse::{Asset, MultiEraBlock, MultiEraOutput, MultiEraTx},
Expand All @@ -7,16 +6,19 @@ use serde::Deserialize;

pub mod minswap;
pub mod model;
pub mod muesliswap;
pub mod sundaeswap;
pub mod utils;
pub mod wingriders;

use crate::{crosscut, prelude::*};

use self::{
model::{LiquidityPoolDatum, PoolAsset, TokenPair},
minswap::MinSwapPoolDatum,
model::{LiquidityPoolDatum, TokenPair},
muesliswap::MuesliSwapPoolDatum,
sundaeswap::SundaePoolDatum,
utils::{build_key_value_pair, contains_currency_symbol, resolve_datum},
utils::{build_key_value_pair, contains_currency_symbol, get_asset_amount, resolve_datum},
wingriders::WingriderPoolDatum,
};

Expand All @@ -32,34 +34,6 @@ pub struct Reducer {
policy: crosscut::policies::RuntimePolicy,
}

fn get_asset_amount(asset: &PoolAsset, assets: &Vec<Asset>) -> Option<u64> {
match asset {
PoolAsset::Ada => {
for asset in assets {
if let Asset::Ada(lovelace_amount) = asset {
return Some(*lovelace_amount);
}
}
}
PoolAsset::AssetClass(matched_currency_symbol_hash, matched_token_name_bytes) => {
let currency_symbol: String =
hex::encode(matched_currency_symbol_hash.deref().to_vec());
let token_name: String = hex::encode(matched_token_name_bytes.deref());
for asset in assets {
if let Asset::NativeAsset(currency_symbol_hash, token_name_vector, amount) = asset {
if hex::encode(currency_symbol_hash.deref()).eq(&currency_symbol)
&& hex::encode(token_name_vector).eq(&token_name)
{
return Some(*amount);
}
}
}
}
}

None
}

impl Reducer {
fn get_key_value_pair(
&self,
Expand All @@ -76,7 +50,8 @@ impl Reducer {
let pool_datum = LiquidityPoolDatum::try_from(&plutus_data)?;
let assets: Vec<Asset> = utxo.assets();
match pool_datum {
LiquidityPoolDatum::Minswap(TokenPair { a, b })
LiquidityPoolDatum::MuesliSwapPoolDatum(MuesliSwapPoolDatum { a, b })
| LiquidityPoolDatum::Minswap(MinSwapPoolDatum { a, b })
| LiquidityPoolDatum::Wingriders(WingriderPoolDatum { a, b }) => {
let a_amount_opt: Option<u64> = get_asset_amount(&a, &assets);
let b_amount_opt: Option<u64> = get_asset_amount(&b, &assets);
Expand All @@ -86,10 +61,11 @@ impl Reducer {
a_amount_opt,
b_amount_opt,
None,
None,
)
.ok_or(());
}
LiquidityPoolDatum::Sundaeswap(SundaePoolDatum { a, b, fee }) => {
LiquidityPoolDatum::Sundaeswap(SundaePoolDatum { a, b, fee, pool_id }) => {
let a_amount_opt: Option<u64> = get_asset_amount(&a, &assets);
let b_amount_opt: Option<u64> = get_asset_amount(&b, &assets);
return build_key_value_pair(
Expand All @@ -98,6 +74,7 @@ impl Reducer {
a_amount_opt,
b_amount_opt,
Some(fee),
Some(pool_id),
)
.ok_or(());
}
Expand Down
10 changes: 8 additions & 2 deletions src/reducers/liquidity_by_token_pair/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ use pallas::{
use std::{fmt, str::FromStr};

use super::{
minswap::MinSwapPoolDatum, sundaeswap::SundaePoolDatum, wingriders::WingriderPoolDatum,
minswap::MinSwapPoolDatum, muesliswap::MuesliSwapPoolDatum, sundaeswap::SundaePoolDatum,
wingriders::WingriderPoolDatum,
};

pub enum LiquidityPoolDatum {
MuesliSwapPoolDatum(MuesliSwapPoolDatum),
Minswap(MinSwapPoolDatum),
Sundaeswap(SundaePoolDatum),
Wingriders(WingriderPoolDatum),
Expand All @@ -19,7 +21,11 @@ impl TryFrom<&PlutusData> for LiquidityPoolDatum {
type Error = ();

fn try_from(value: &PlutusData) -> Result<Self, Self::Error> {
if let Some(minswap_token_pair) = MinSwapPoolDatum::try_from(value).ok() {
if let Some(muesliswap_token_pair) = MuesliSwapPoolDatum::try_from(value).ok() {
return Ok(LiquidityPoolDatum::MuesliSwapPoolDatum(
muesliswap_token_pair,
));
} else if let Some(minswap_token_pair) = MinSwapPoolDatum::try_from(value).ok() {
return Ok(LiquidityPoolDatum::Minswap(minswap_token_pair));
} else if let Some(sundae_token_pair) = SundaePoolDatum::try_from(value).ok() {
return Ok(LiquidityPoolDatum::Sundaeswap(sundae_token_pair));
Expand Down
44 changes: 44 additions & 0 deletions src/reducers/liquidity_by_token_pair/muesliswap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use pallas::ledger::primitives::babbage::PlutusData;

use super::model::{PoolAsset, TokenPair};

pub struct MuesliSwapPoolDatum {
pub a: PoolAsset,
pub b: PoolAsset,
}

impl TryFrom<&PlutusData> for MuesliSwapPoolDatum {
type Error = ();

fn try_from(value: &PlutusData) -> Result<Self, Self::Error> {
if let Some(TokenPair { a, b }) = TokenPair::try_from(value).ok() {
return Ok(Self { a, b });
}

Err(())
}
}

#[cfg(test)]
mod test {
use pallas::ledger::primitives::{babbage::PlutusData, Fragment};

use crate::reducers::liquidity_by_token_pair::{
model::PoolAsset, muesliswap::MuesliSwapPoolDatum, utils::pool_asset_from,
};

#[test]
fn test_decoding_pool_datum_ada_min() {
let hex_pool_datum = "d8799fd8799f4040ffd8799f581c29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6434d494eff1a9041264e181eff";
let data = hex::decode(hex_pool_datum).unwrap();
let plutus_data = PlutusData::decode_fragment(&data).unwrap();
let pool_datum = MuesliSwapPoolDatum::try_from(&plutus_data).unwrap();
assert_eq!(PoolAsset::Ada, pool_datum.a);
let minswap_token = pool_asset_from(
&String::from("29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6"),
&String::from("4d494e"),
)
.unwrap();
assert_eq!(minswap_token, pool_datum.b);
}
}
8 changes: 7 additions & 1 deletion src/reducers/liquidity_by_token_pair/sundaeswap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub struct SundaePoolDatum {
pub a: PoolAsset,
pub b: PoolAsset,
pub fee: f64,
pub pool_id: String,
}

impl TryFrom<&PlutusData> for SundaePoolDatum {
Expand All @@ -17,7 +18,11 @@ impl TryFrom<&PlutusData> for SundaePoolDatum {
let token_pair_pd = pd.fields.get(0).ok_or(())?;
let token_pair = TokenPair::try_from(token_pair_pd)?;

if let Some(PlutusData::Constr(fee_pd)) = pd.fields.get(3) {
if let (
Some(PlutusData::BoundedBytes(pool_id_bytes)),
Some(PlutusData::Constr(fee_pd)),
) = (pd.fields.get(1), pd.fields.get(3))
{
return match (fee_pd.fields.get(0), fee_pd.fields.get(1)) {
(
Some(PlutusData::BigInt(pallas::ledger::primitives::babbage::BigInt::Int(
Expand All @@ -33,6 +38,7 @@ impl TryFrom<&PlutusData> for SundaePoolDatum {
a: token_pair.a,
b: token_pair.b,
fee: (n as f64) / (d as f64),
pool_id: hex::encode(pool_id_bytes.clone().to_vec()),
})
}
_ => Err(()),
Expand Down
Loading

0 comments on commit 7a65741

Please sign in to comment.