Skip to content

Commit

Permalink
Merge pull request #71 from EuclidProtocol/cross-chain-hard-limit
Browse files Browse the repository at this point in the history
feat: Cross Chain Limits
  • Loading branch information
SlayerAnsh authored Dec 11, 2024
2 parents 4f34033 + cc86bb2 commit fbf17f0
Show file tree
Hide file tree
Showing 23 changed files with 416 additions and 120 deletions.
1 change: 0 additions & 1 deletion contracts/hub/router/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> Result<Response, ContractEr
ADD_LIQUIDITY_REPLY_ID => reply::on_add_liquidity_reply(deps, msg),
REMOVE_LIQUIDITY_REPLY_ID => reply::on_remove_liquidity_reply(deps, env, msg),
SWAP_REPLY_ID => reply::on_swap_reply(deps, env, msg),

VIRTUAL_BALANCE_INSTANTIATE_REPLY_ID => {
reply::on_virtual_balance_instantiate_reply(deps, msg)
}
Expand Down
53 changes: 47 additions & 6 deletions contracts/hub/router/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use cosmwasm_std::{
};

use euclid::{
chain::{Chain, ChainUid, CrossChainUser, CrossChainUserWithLimit},
chain::{Chain, ChainUid, CrossChainUser, CrossChainUserWithLimit, Limit},
error::ContractError,
events::{tx_event, TxType},
msgs::{
Expand All @@ -23,7 +23,7 @@ use crate::{
query::verify_cross_chain_addresses,
state::{
State, CHAIN_UID_TO_CHAIN, CHANNEL_TO_CHAIN_UID, DEREGISTERED_CHAINS, ESCROW_BALANCES,
STATE,
STATE, TOKEN_DENOMS,
},
};

Expand Down Expand Up @@ -307,23 +307,36 @@ pub fn execute_release_escrow(
sender.address.as_str(),
TxType::EscrowRelease,
))
.add_attribute("tx_id", tx_id);
.add_attribute("tx_id", tx_id.clone());

let timeout = get_timeout(timeout)?;
let mut release_msgs: Vec<SubMsg> = vec![];

let mut cross_chain_addresses_iterator = cross_chain_addresses.into_iter().peekable();
let mut remaining_withdraw_amount = amount;
let token_denoms = TOKEN_DENOMS.load(deps.storage, token.clone())?;

let mut transfer_amount = Uint128::zero();
// Ensure that the amount desired doesn't exceed the current balance
while !remaining_withdraw_amount.is_zero() && cross_chain_addresses_iterator.peek().is_some() {
let cross_chain_address = cross_chain_addresses_iterator
.clone()
.next()
.ok_or(ContractError::new("Cross Chain Address Iter Failed"))?;
let chain =
CHAIN_UID_TO_CHAIN.load(deps.storage, cross_chain_address.user.chain_uid.clone())?;

if let Some(ref preferred_denom) = cross_chain_address.preferred_denom {
// Ensure that the preferred denom is valid
ensure!(
token_denoms
.iter()
.any(|x| x.token_type == preferred_denom.clone()
&& x.chain_uid == cross_chain_address.user.chain_uid),
ContractError::InvalidDenom {}
);
}

let escrow_key =
ESCROW_BALANCES.key((token.clone(), cross_chain_address.user.chain_uid.clone()));
let escrow_balance = escrow_key
Expand All @@ -336,7 +349,36 @@ pub fn execute_release_escrow(
remaining_withdraw_amount
};

let release_amount = release_amount.min(cross_chain_address.limit.unwrap_or(Uint128::MAX));
match cross_chain_address.limit {
Some(Limit::LessThanOrEqual(limit)) => {
ensure!(
release_amount.le(&limit),
ContractError::LimitExceeded {
limit,
amount: release_amount
}
);
}
Some(Limit::Equal(limit)) => {
ensure!(
release_amount.eq(&limit),
ContractError::AmountMismatch {
expected: limit,
received: release_amount
}
);
}
Some(Limit::GreaterThanOrEqual(limit)) => {
ensure!(
release_amount.ge(&limit),
ContractError::InsufficientAmount {
min_amount: limit,
amount: release_amount
}
);
}
_ => {}
}

if release_amount.is_zero() {
continue;
Expand All @@ -350,11 +392,10 @@ pub fn execute_release_escrow(
let send_msg = HubIbcExecuteMsg::ReleaseEscrow {
sender: sender.clone(),
amount: release_amount,
recipient: cross_chain_address.clone(),
token: token.clone(),
to_address: cross_chain_address.user.address.clone(),
// We can't use same tx id because it might conflict with pending requests on receiving chain
tx_id: generate_tx(deps.branch(), &env, &sender)?,
chain_uid: cross_chain_address.user.chain_uid.clone(),
}
.to_msg(deps, &env, chain, timeout)?;

Expand Down
8 changes: 3 additions & 5 deletions contracts/hub/router/src/ibc/ack_and_timeout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,10 @@ pub fn reusable_internal_ack_call(
token,
tx_id,
sender,
chain_uid,
..
} => {
let res = from_json(ack)?;
ibc_ack_release_escrow(deps, env, chain_uid, sender, amount, token, res, tx_id)
ibc_ack_release_escrow(deps, env, sender, amount, token, res, tx_id)
}
HubIbcExecuteMsg::UpdateFactoryChannel { chain_uid, tx_id } => {
let res = from_json(ack)?;
Expand Down Expand Up @@ -228,7 +227,6 @@ pub fn ibc_ack_update_factory_channel(
pub fn ibc_ack_release_escrow(
deps: DepsMut,
_env: Env,
chain_uid: ChainUid,
sender: CrossChainUser,
amount: Uint128,
token: Token,
Expand Down Expand Up @@ -264,7 +262,7 @@ pub fn ibc_ack_release_escrow(
let mint_msg = VirtualBalanceExecuteMsg::Mint(ExecuteMint {
amount,
balance_key: BalanceKey {
cross_chain_user: sender,
cross_chain_user: sender.clone(),
token_id: token.to_string(),
},
});
Expand All @@ -275,7 +273,7 @@ pub fn ibc_ack_release_escrow(
});

// Escrow release is failed, add the old escrow balance again
let escrow_key = ESCROW_BALANCES.key((token, chain_uid));
let escrow_key = ESCROW_BALANCES.key((token, sender.chain_uid));
let new_balance = escrow_key.load(deps.storage)?.checked_add(amount)?;
escrow_key.save(deps.storage, &new_balance)?;

Expand Down
1 change: 0 additions & 1 deletion contracts/hub/router/src/ibc/receive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,6 @@ pub fn ibc_execute_add_liquidity(
sender,
tx_id,
slippage_tolerance_bps,
called_by_register_pool_with_funds: false,
};

let msg = WasmMsg::Execute {
Expand Down
34 changes: 31 additions & 3 deletions contracts/hub/router/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use cosmwasm_std::{ensure, to_json_binary, Binary, Deps, Order, Uint128};
use cw_storage_plus::{Bound, PrefixBound};
use euclid::{
chain::{ChainUid, CrossChainUser, CrossChainUserWithLimit},
chain::{ChainUid, CrossChainUser, CrossChainUserWithLimit, Limit},
error::ContractError,
msgs::router::{
AllChainResponse, AllEscrowsResponse, AllTokensResponse, AllVlpResponse, ChainResponse,
Expand Down Expand Up @@ -162,8 +162,36 @@ pub fn query_simulate_escrow_release(
remaining_withdraw_amount
};

let release_amount = release_amount.min(cross_chain_address.limit.unwrap_or(Uint128::MAX));

match cross_chain_address.limit {
Some(Limit::LessThanOrEqual(limit)) => {
ensure!(
release_amount.le(&limit),
ContractError::LimitExceeded {
limit,
amount: release_amount
}
);
}
Some(Limit::Equal(limit)) => {
ensure!(
release_amount.eq(&limit),
ContractError::AmountMismatch {
expected: limit,
received: release_amount
}
);
}
Some(Limit::GreaterThanOrEqual(limit)) => {
ensure!(
release_amount.ge(&limit),
ContractError::InsufficientAmount {
min_amount: limit,
amount: release_amount
}
);
}
_ => {}
}
if release_amount.is_zero() {
continue;
}
Expand Down
34 changes: 17 additions & 17 deletions contracts/hub/router/src/reply.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use cosmwasm_std::{
ensure, from_json, to_json_binary, CosmosMsg, DepsMut, Env, Reply, Response, SubMsgResult,
WasmMsg,
ensure, from_json, to_json_binary, CosmosMsg, DepsMut, Env, Reply, Response, SubMsg,
SubMsgResult, WasmMsg,
};
use cw_utils::{
parse_execute_response_data, parse_reply_execute_data, parse_reply_instantiate_data,
Expand Down Expand Up @@ -261,7 +261,6 @@ pub fn on_swap_reply(deps: DepsMut, env: Env, msg: Reply) -> Result<Response, Co
amount_out: vlp_swap_response.amount_out,
tx_id: vlp_swap_response.tx_id,
};
let ack = AcknowledgementMsg::Ok(swap_response.clone());

// Prepare burn msg
let release_msg = ExecuteMsg::ReleaseEscrowInternal {
Expand All @@ -273,20 +272,21 @@ pub fn on_swap_reply(deps: DepsMut, env: Env, msg: Reply) -> Result<Response, Co
tx_id: swap_msg.tx_id,
};

Ok(Response::new()
.add_message(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: env.contract.address.to_string(),
msg: to_json_binary(&release_msg)?,
funds: vec![],
}))
.add_attribute("action", "reply_swap")
.add_attribute("swap", format!("{swap_response:?}"))
.add_attribute("amount_out", swap_response.amount_out)
.add_attribute("asset_out", swap_msg.asset_out.to_string())
.add_attribute("asset_in", swap_msg.asset_in.token.to_string())
.add_attribute("asset_type", swap_msg.asset_in.token_type.get_key())
.add_attribute("amount_in", swap_msg.amount_in)
.set_data(to_json_binary(&ack)?))
Ok(
Response::new()
.add_submessage(SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute {
contract_addr: env.contract.address.to_string(),
msg: to_json_binary(&release_msg)?,
funds: vec![],
})))
.add_attribute("action", "reply_swap")
.add_attribute("swap", format!("{swap_response:?}"))
.add_attribute("amount_out", swap_response.amount_out)
.add_attribute("asset_out", swap_msg.asset_out.to_string())
.add_attribute("asset_in", swap_msg.asset_in.token.to_string())
.add_attribute("asset_type", swap_msg.asset_in.token_type.get_key())
.add_attribute("amount_in", swap_msg.amount_in), // .set_data(to_json_binary(&ack)?)
)
}
}
}
Expand Down
2 changes: 0 additions & 2 deletions contracts/hub/vlp/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ pub fn execute(
tx_id,
slippage_tolerance_bps,
liquidity,
called_by_register_pool_with_funds,
} => add_liquidity(
deps,
env,
Expand All @@ -106,7 +105,6 @@ pub fn execute(
liquidity,
slippage_tolerance_bps,
tx_id,
called_by_register_pool_with_funds,
),
ExecuteMsg::RemoveLiquidity {
sender,
Expand Down
4 changes: 2 additions & 2 deletions contracts/hub/vlp/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ pub fn register_pool_with_funds(
pair_with_amount,
slippage_tolerance_bps,
tx_id,
true,
)
}

Expand Down Expand Up @@ -144,7 +143,6 @@ pub fn add_liquidity(
liquidity: PairWithAmount,
slippage_tolerance_bps: u64,
tx_id: String,
called_by_register_pool_with_funds: bool,
) -> Result<Response, ContractError> {
let mut state = STATE.load(deps.storage)?;
ensure!(info.sender == state.router, ContractError::Unauthorized {});
Expand Down Expand Up @@ -298,6 +296,8 @@ pub fn remove_liquidity(
// Prepare Liquidity Response
let liquidity_response = VlpRemoveLiquidityResponse {
burn_lp_tokens: lp_allocation,
//TODO
preferred_denom: None,
tx_id: tx_id.clone(),
sender: sender.clone(),
vlp_address: env.contract.address.to_string(),
Expand Down
36 changes: 25 additions & 11 deletions contracts/liquidity/escrow/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::execute::{
execute_withdraw, receive_cw20,
};
use crate::query::{self, query_token_id};
use crate::reply::{handle_refund, FORWARDING_MESSAGE_REPLY_ID};
use crate::state::{State, STATE};

use euclid::msgs::escrow::{EscrowInstantiateResponse, ExecuteMsg, InstantiateMsg, QueryMsg};
Expand Down Expand Up @@ -67,9 +68,22 @@ pub fn execute(
ExecuteMsg::AddAllowedDenom { denom } => execute_add_allowed_denom(deps, env, info, denom),
ExecuteMsg::DisallowDenom { denom } => execute_disallow_denom(deps, env, info, denom),
ExecuteMsg::Receive(msg) => receive_cw20(deps, env, info, msg),
ExecuteMsg::Withdraw { recipient, amount } => {
execute_withdraw(deps, env, info, recipient, amount)
}
ExecuteMsg::Withdraw {
recipient,
amount,
preferred_denom,
forwarding_message,
refund_address,
} => execute_withdraw(
deps,
env,
info,
recipient,
amount,
preferred_denom,
forwarding_message,
refund_address,
),
}
}

Expand All @@ -83,13 +97,13 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<Binary, ContractErr
}
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn reply(_deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
pub fn reply(deps: DepsMut, _env: Env, msg: Reply) -> Result<Response, ContractError> {
let id = msg.id;
Err(ContractError::Std(StdError::generic_err(format!(
"Unknown reply id: {}",
id
))))
match id {
FORWARDING_MESSAGE_REPLY_ID => handle_refund(deps, msg),
_ => Err(ContractError::Std(StdError::generic_err(format!(
"Unknown reply id: {}",
id
)))),
}
}

#[cfg(test)]
mod tests {}
Loading

0 comments on commit fbf17f0

Please sign in to comment.