Skip to content

Commit

Permalink
Merge pull request #19 from EuclidProtocol/fix/redundant-messages
Browse files Browse the repository at this point in the history
Cleanup IBC methods, Update queries, and make LP ratio dynamic based on swap
  • Loading branch information
SlayerAnsh authored Jun 1, 2024
2 parents 5c3b19a + e814d7a commit 6826a8b
Show file tree
Hide file tree
Showing 28 changed files with 312 additions and 209 deletions.
Binary file removed contracts/.DS_Store
Binary file not shown.
15 changes: 4 additions & 11 deletions contracts/hub/vlp/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{ensure, Binary, Deps, DepsMut, Env, MessageInfo, Response, Uint128};
use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, Uint128};
use cw2::set_contract_version;

use crate::state::{State, POOLS, STATE};
use crate::state::{State, STATE};
use euclid::error::ContractError;
use euclid::msgs::vlp::{ExecuteMsg, InstantiateMsg, QueryMsg};

Expand All @@ -24,20 +24,13 @@ pub fn instantiate(
router: info.sender.to_string(),
fee: msg.fee,
last_updated: 0,
total_reserve_1: msg.pool.reserve_1,
total_reserve_2: msg.pool.reserve_2,
total_reserve_1: Uint128::zero(),
total_reserve_2: Uint128::zero(),
total_lp_tokens: Uint128::zero(),
lq_ratio: msg.lq_ratio,
};
ensure!(
!state.lq_ratio.is_zero(),
ContractError::InvalidLiquidityRatio {}
);

set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
STATE.save(deps.storage, &state)?;
// stores initial pool to map
POOLS.save(deps.storage, &msg.pool.chain, &msg.pool)?;
Ok(Response::new()
.add_attribute("method", "instantiate")
.add_attribute("owner", info.sender))
Expand Down
46 changes: 31 additions & 15 deletions contracts/hub/vlp/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ use euclid::{
error::ContractError,
pool::{LiquidityResponse, Pool, PoolCreationResponse},
swap::SwapResponse,
token::{Pair, PairInfo, Token},
token::{PairInfo, Token},
};
use euclid_ibc::{ack::make_ack_success, msg::AcknowledgementMsg};

use crate::{
query::{assert_slippage_tolerance, calculate_lp_allocation, calculate_swap},
state::{self, POOLS, STATE},
state::{self, FACTORIES, POOLS, STATE},
};

/// Registers a new pool in the contract. Function called by Router Contract
Expand All @@ -34,6 +34,7 @@ pub fn register_pool(
deps: DepsMut,
env: Env,
chain_id: String,
factory: String,
pair_info: PairInfo,
) -> Result<IbcReceiveResponse, ContractError> {
let state = STATE.load(deps.storage)?;
Expand All @@ -43,18 +44,28 @@ pub fn register_pool(
POOLS.may_load(deps.storage, &chain_id)?.is_none(),
ContractError::PoolAlreadyExists {}
);

// Check for token id
ensure!(
state.pair.token_1.get_token() == pair_info.token_1.get_token(),
ContractError::AssetDoesNotExist {}
);

ensure!(
state.pair.token_2.get_token() == pair_info.token_2.get_token(),
ContractError::AssetDoesNotExist {}
);

let pool = Pool::new(&chain_id, pair_info, Uint128::zero(), Uint128::zero());

// Store the pool in the map
POOLS.save(deps.storage, &chain_id, &pool)?;
FACTORIES.save(deps.storage, &chain_id, &factory)?;

STATE.save(deps.storage, &state)?;

let ack = AcknowledgementMsg::Ok(PoolCreationResponse {
vlp_contract: env.contract.address.to_string(),
token_pair: Pair {
token_1: pool.pair.token_1.get_token(),
token_2: pool.pair.token_2.get_token(),
},
});

Ok(IbcReceiveResponse::new()
Expand Down Expand Up @@ -97,13 +108,17 @@ pub fn add_liquidity(
}
})?;

// Lets get lq ratio, it will be the current ratio of token reserves or if its first time then it will be ratio of tokens provided
let lq_ratio = Decimal256::checked_from_ratio(state.total_reserve_1, state.total_reserve_2)
.unwrap_or(ratio);

// Verify slippage tolerance is between 0 and 100
ensure!(
slippage_tolerance.le(&100),
ContractError::InvalidSlippageTolerance {}
);

assert_slippage_tolerance(ratio, state.lq_ratio, slippage_tolerance)?;
assert_slippage_tolerance(ratio, lq_ratio, slippage_tolerance)?;

// Add liquidity to the pool
pool.reserve_1 = pool.reserve_1.checked_add(token_1_liquidity)?;
Expand Down Expand Up @@ -221,7 +236,8 @@ pub fn execute_swap(
// Verify that the asset exists for the VLP
let asset_info = asset.clone().id;
ensure!(
asset_info == state.clone().pair.token_1.id || asset_info == state.clone().pair.token_2.id,
asset_info == state.clone().pair.token_1.get_token().id
|| asset_info == state.clone().pair.token_2.get_token().id,
ContractError::AssetDoesNotExist {}
);

Expand Down Expand Up @@ -254,7 +270,7 @@ pub fn execute_swap(
let swap_amount = asset_amount.checked_sub(fee_amount)?;

// verify if asset is token 1 or token 2
let swap_info = if asset_info == state.clone().pair.token_1.id {
let swap_info = if asset_info == state.pair.token_1.get_token().id {
(
swap_amount,
state.clone().total_reserve_1,
Expand Down Expand Up @@ -282,7 +298,7 @@ pub fn execute_swap(
// Verify that the pool has enough liquidity to swap to user
// Should activate ELP algorithm to get liquidity from other available pool

if asset_info == state.clone().pair.token_1.id {
if asset_info == state.clone().pair.token_1.get_token().id {
ensure!(
pool.reserve_1.ge(&swap_amount),
ContractError::SlippageExceeded {
Expand All @@ -301,7 +317,7 @@ pub fn execute_swap(
}

// Move liquidity from the pool
if asset_info == state.clone().pair.token_1.id {
if asset_info == state.pair.token_1.get_token().id {
pool.reserve_1 = pool.reserve_1.checked_add(swap_amount)?;
pool.reserve_2 = pool.reserve_2.checked_sub(receive_amount)?;
} else {
Expand All @@ -313,7 +329,7 @@ pub fn execute_swap(
POOLS.save(deps.storage, &chain_id, &pool)?;

// Move liquidity for the state
if asset_info == state.clone().pair.token_1.id {
if asset_info == state.pair.token_1.get_token().id {
state.total_reserve_1 = state.clone().total_reserve_1.checked_add(swap_amount)?;
state.total_reserve_2 = state.clone().total_reserve_2.checked_sub(receive_amount)?;
} else {
Expand All @@ -322,10 +338,10 @@ pub fn execute_swap(
}

// Get asset to be recieved by user
let asset_out = if asset_info == state.pair.token_1.id {
state.clone().pair.token_2
let asset_out = if asset_info == state.pair.token_1.get_token().id {
state.clone().pair.token_2.get_token()
} else {
state.clone().pair.token_1
state.clone().pair.token_1.get_token()
};

STATE.save(deps.storage, &state)?;
Expand Down
34 changes: 19 additions & 15 deletions contracts/hub/vlp/src/ibc.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
from_json, DepsMut, Env, IbcBasicResponse, IbcChannel, IbcChannelCloseMsg,
ensure, from_json, DepsMut, Env, IbcBasicResponse, IbcChannel, IbcChannelCloseMsg,
IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcOrder, IbcPacketAckMsg,
IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, StdResult,
};
Expand Down Expand Up @@ -110,10 +110,11 @@ pub fn do_ibc_packet_receive(
..
} => execute::execute_swap(deps, chain_id, asset, asset_amount, min_amount_out, swap_id),
IbcExecuteMsg::RequestPoolCreation {
pair_info,
chain,
pool_rq_id: _,
} => execute::register_pool(deps, env, chain, pair_info),
factory,
pair_info,
} => execute::register_pool(deps, env, chain, factory, pair_info),
}
}

Expand Down Expand Up @@ -159,16 +160,18 @@ pub fn validate_order_and_version(
// We expect an unordered channel here. Ordered channels have the
// property that if a message is lost the entire channel will stop
// working until you start it again.
if channel.order != IbcOrder::Unordered {
return Err(ContractError::OrderedChannel {});
}

if channel.version != IBC_VERSION {
return Err(ContractError::InvalidVersion {
ensure!(
channel.order == IbcOrder::Unordered,
ContractError::OrderedChannel {}
);

ensure!(
channel.version == IBC_VERSION,
ContractError::InvalidVersion {
actual: channel.version.to_string(),
expected: IBC_VERSION.to_string(),
});
}
}
);

// Make sure that we're talking with a counterparty who speaks the
// same "protocol" as us.
Expand All @@ -179,12 +182,13 @@ pub fn validate_order_and_version(
// `OpenAck`. We verify it when we have it but when we don't it's
// alright.
if let Some(counterparty_version) = counterparty_version {
if counterparty_version != IBC_VERSION {
return Err(ContractError::InvalidVersion {
ensure!(
counterparty_version == IBC_VERSION,
ContractError::InvalidVersion {
actual: counterparty_version.to_string(),
expected: IBC_VERSION.to_string(),
});
}
}
);
}

Ok(())
Expand Down
1 change: 1 addition & 0 deletions contracts/hub/vlp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod contract;
pub mod execute;
pub mod ibc;
pub mod integration_tests;
pub mod migrate;
pub mod query;
pub mod state;

Expand Down
9 changes: 9 additions & 0 deletions contracts/hub/vlp/src/migrate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use cosmwasm_std::{entry_point, DepsMut, Env, Response};
use euclid::{error::ContractError, msgs::vlp::MigrateMsg};

/// This is the migrate entry point for the contract.
/// Currently, it does not perform any migration logic and simply returns an empty response.
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
Ok(Response::default())
}
57 changes: 34 additions & 23 deletions contracts/hub/vlp/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use cosmwasm_std::{to_json_binary, Binary, Decimal256, Deps, Isqrt, Uint128};
use cosmwasm_std::{ensure, to_json_binary, Binary, Decimal256, Deps, Isqrt, Uint128};
use euclid::error::ContractError;
use euclid::pool::MINIMUM_LIQUIDITY;
use euclid::token::Token;
use euclid::token::{PairInfo, Token};

use euclid::msgs::vlp::{AllPoolsResponse, GetLiquidityResponse, GetSwapResponse, PairInfo};
use euclid::msgs::vlp::{
AllPoolsResponse, FeeResponse, GetLiquidityResponse, GetSwapResponse, PoolInfo, PoolResponse,
};

use crate::state::{POOLS, STATE};
use crate::state::{FACTORIES, POOLS, STATE};

// Function to simulate swap in a query
pub fn query_simulate_swap(
Expand All @@ -17,14 +19,16 @@ pub fn query_simulate_swap(

// Verify that the asset exists for the VLP
let asset_info = asset.id;
if asset_info != state.pair.token_1.id && asset_info != state.pair.token_2.id {
return Err(ContractError::AssetDoesNotExist {});
}

// asset should match either token
ensure!(
asset_info == state.pair.token_1.get_token().id
|| asset_info == state.pair.token_2.get_token().id,
ContractError::AssetDoesNotExist {}
);

// Verify that the asset amount is non-zero
if asset_amount.is_zero() {
return Err(ContractError::ZeroAssetAmount {});
}
ensure!(!asset_amount.is_zero(), ContractError::ZeroAssetAmount {});

// Get Fee from the state
let fee = state.fee;
Expand All @@ -39,7 +43,7 @@ pub fn query_simulate_swap(
let swap_amount = asset_amount.checked_sub(fee_amount)?;

// verify if asset is token 1 or token 2
let swap_info = if asset_info == state.pair.token_1.id {
let swap_info = if asset_info == state.pair.token_1.get_token().id {
(swap_amount, state.total_reserve_1, state.total_reserve_2)
} else {
(swap_amount, state.total_reserve_2, state.total_reserve_1)
Expand Down Expand Up @@ -70,22 +74,28 @@ pub fn query_liquidity(deps: Deps) -> Result<Binary, ContractError> {
// Function to query fee of the contract
pub fn query_fee(deps: Deps) -> Result<Binary, ContractError> {
let state = STATE.load(deps.storage)?;
Ok(to_json_binary(&state.fee)?)
Ok(to_json_binary(&FeeResponse { fee: state.fee })?)
}

// Function to query a Euclid Pool Information for this pair
pub fn query_pool(deps: Deps, chain_id: String) -> Result<Binary, ContractError> {
let pool = POOLS.load(deps.storage, &chain_id)?;
Ok(to_json_binary(&pool)?)
Ok(to_json_binary(&PoolResponse { pool })?)
}
// Function to query all Euclid Pool Information
pub fn query_all_pools(deps: Deps) -> Result<Binary, ContractError> {
let pools: Vec<String> = POOLS
let pools: Result<_, ContractError> = POOLS
.range(deps.storage, None, None, cosmwasm_std::Order::Ascending)
.map(|item| item.map(|(_, pool)| pool.chain.clone()))
.collect::<Result<Vec<String>, _>>()?;

Ok(to_json_binary(&AllPoolsResponse { pools })?)
.map(|item| {
let (chain, pool) = item?;
Ok::<PoolInfo, ContractError>(PoolInfo {
factory_address: FACTORIES.load(deps.storage, &chain)?,
chain,
pool,
})
})
.collect();

Ok(to_json_binary(&AllPoolsResponse { pools: pools? })?)
}
// Function to calculate the asset to be recieved after a swap
pub fn calculate_swap(
Expand Down Expand Up @@ -131,11 +141,12 @@ pub fn assert_slippage_tolerance(
pool_ratio: Decimal256,
slippage_tolerance: u64,
) -> Result<bool, ContractError> {
let slippage = pool_ratio.checked_sub(ratio)?;
let slippage = pool_ratio.abs_diff(ratio);
let slippage_tolerance =
Decimal256::from_ratio(Uint128::from(slippage_tolerance), Uint128::from(100u128));
if slippage > slippage_tolerance {
return Err(ContractError::LiquiditySlippageExceeded {});
}
ensure!(
slippage.le(&slippage_tolerance),
ContractError::LiquiditySlippageExceeded {}
);
Ok(true)
}
Loading

0 comments on commit 6826a8b

Please sign in to comment.