Skip to content

Commit

Permalink
Vesting
Browse files Browse the repository at this point in the history
  • Loading branch information
Rhaki committed Dec 3, 2023
1 parent 981aa01 commit 760eced
Show file tree
Hide file tree
Showing 11 changed files with 482 additions and 125 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
# let members inline
members = ["package", "contracts/otc"]
members = ["package", "contracts/otc", "tests"]

[workspace.package]
version = "0.1.0"
Expand Down
3 changes: 2 additions & 1 deletion contracts/otc/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use cosmwasm_otc_pkg::otc::{
use rhaki_cw_plus::traits::{IntoAddr, IntoBinaryResult};

use crate::{
execute::{run_cancel_otc, run_create_otc, run_execute_otc},
execute::{run_cancel_otc, run_claim_otc, run_create_otc, run_execute_otc},
query::{
qy_active_position, qy_active_positions, qy_active_positions_by_dealer,
qy_active_positions_by_owner, qy_executed_position, qy_executed_positions,
Expand Down Expand Up @@ -42,6 +42,7 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> C
match msg {
ExecuteMsg::CreateOtc(msg) => run_create_otc(deps, env, info, msg),
ExecuteMsg::ExecuteOtc(msg) => run_execute_otc(deps, env, info, msg),
ExecuteMsg::ClaimOtc(msg) => run_claim_otc(deps, env, info, msg),
ExecuteMsg::CancelOtc(msg) => run_cancel_otc(deps, env, info, msg),
}
}
Expand Down
102 changes: 61 additions & 41 deletions contracts/otc/src/execute.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use cosmwasm_otc_pkg::otc::{
definitions::{OtcItemsChecker, OtcPosition},
msgs::{CancelOtcMsg, CreateOtcMsg, ExecuteOtcMsg},
definitions::OtcPosition,
msgs::{CancelOtcMsg, ClaimOtcMsg, CreateOtcMsg, ExecuteOtcMsg},
};
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response, StdError};
use rhaki_cw_plus::traits::IntoAddr;

use crate::{
functions::{cancel_otc, collect_otc_items, send_fee, send_otc_items, try_close_position},
response::{ContractError, ContractResponse},
state::{active_positions, execute_positions, CONFIG},
state::{active_positions, CONFIG},
};

pub fn run_create_otc(
Expand All @@ -21,22 +22,17 @@ pub fn run_create_otc(

let position = OtcPosition::from_create_otc_msg(
deps.as_ref(),
&env,
msg,
config.counter_otc,
info.sender.clone(),
)?;
position.validate(deps.as_ref())?;

let (msgs_deposit, remaining_coins) =
position
.ask
.gather_items(env.contract.address, info.sender.clone(), Some(info.funds))?;

let (msgs_fee, _) = config.fee.gather_items(
config.fee_collector.clone(),
info.sender,
Some(remaining_coins),
)?;
collect_otc_items(&env, &position.ask, info.sender, info.funds)?;

let msgs_fee = send_fee(&env, &config.fee, &config.fee_collector, remaining_coins)?;

CONFIG.save(deps.storage, &config)?;

Expand All @@ -59,40 +55,63 @@ pub fn run_execute_otc(
info: MessageInfo,
msg: ExecuteOtcMsg,
) -> ContractResponse {
let position = active_positions().load(deps.storage, msg.id)?;
let mut position = active_positions().load(deps.storage, msg.id)?;
position.active(&env, &info.sender)?;

let config = CONFIG.load(deps.storage)?;

if let Some(dealer) = position.dealer.clone() {
if dealer != info.sender {
return Err(ContractError::Unauthorized {});
}
}
let (msgs_deposit, remaining_coins) =
collect_otc_items(&env, &position.ask, info.sender, info.funds)?;

let (msgs_to_owner, remaining_funds) = position.offer.gather_items(
position.owner.clone(),
info.sender.clone(),
Some(info.funds),
)?;
let msgs_fee = send_fee(&env, &config.fee, &config.fee_collector, remaining_coins)?;

let (msg_fee, _) = config.fee.gather_items(
config.fee_collector,
info.sender.clone(),
Some(remaining_funds),
let msgs_to_owner = send_otc_items(&env, &mut position.ask, &position.status, &position.owner)?;
let msgs_to_dealer = send_otc_items(
&env,
&mut position.offer,
&position.status,
&position.dealer.clone().unwrap(),
)?;

let (msg_to_dealer, _) = position
.ask
.gather_items(info.sender, env.contract.address, None)?;

active_positions().remove(deps.storage, msg.id)?;
execute_positions().save(deps.storage, msg.id, &position)?;
let attrs_close = try_close_position(deps, &env, &mut position)?;

Ok(Response::new()
.add_messages(msgs_deposit)
.add_messages(msgs_fee)
.add_messages(msgs_to_owner)
.add_messages(msg_fee)
.add_messages(msg_to_dealer)
.add_messages(msgs_to_dealer)
.add_attribute("action", "execute_otc")
.add_attribute("otc_id", msg.id.to_string()))
.add_attribute("otc_id", msg.id.to_string())
.add_attributes(attrs_close))
}

pub fn run_claim_otc(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ClaimOtcMsg,
) -> ContractResponse {
let mut position = active_positions().load(deps.storage, msg.id)?;

let msgs = if info.sender == position.owner {
send_otc_items(&env, &mut position.ask, &position.status, &info.sender)?
} else if info.sender == position.dealer.clone().unwrap() {
send_otc_items(&env, &mut position.offer, &position.status, &info.sender)?
} else {
return Err(ContractError::Unauthorized {});
};

if msgs.is_empty() {
return Err(StdError::generic_err("Nothing to claim").into());
}

let attrs_close = try_close_position(deps, &env, &mut position)?;

Ok(Response::new()
.add_messages(msgs)
.add_attribute("action", "claim")
.add_attribute("id", msg.id.to_string())
.add_attributes(attrs_close))
}

pub fn run_cancel_otc(
Expand All @@ -107,14 +126,15 @@ pub fn run_cancel_otc(
return Err(ContractError::Unauthorized {});
}

let (msgs, _) = position
.offer
.gather_items(info.sender, env.contract.address, None)?;
if !position.status.is_in_pending() {
return Err(StdError::generic_err("Can't cancel a position non in pending status").into());
}
let msgs_to_owner = cancel_otc(&env, &position)?;

active_positions().remove(deps.storage, msg.id)?;

Ok(Response::new()
.add_messages(msgs)
.add_messages(msgs_to_owner)
.add_attribute("action", "cancel_otc")
.add_attribute("id", msg.id.to_string()))
}
130 changes: 130 additions & 0 deletions contracts/otc/src/functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use cosmwasm_otc_pkg::otc::definitions::{OtcItem, OtcItemInfo, OtcPosition, OtcPositionStatus};
use cosmwasm_std::{
attr, Addr, Attribute, Coin, CosmosMsg, DepsMut, Env, StdError, StdResult, Uint128,
};

use crate::state::{active_positions, execute_positions};

pub fn collect_otc_items(
env: &Env,
items: &Vec<OtcItem>,
sender: Addr,
funds: Vec<Coin>,
) -> StdResult<(Vec<CosmosMsg>, Vec<Coin>)> {
let coins = assert_received_funds(
&items.iter().map(|val| val.item_info.clone()).collect(),
funds,
)?;
let mut msgs: Vec<CosmosMsg> = vec![];
for item in items {
match &item.item_info {
OtcItemInfo::Cw20 { .. } | &OtcItemInfo::Cw721 { .. } => msgs.push(
item.item_info
.build_send_msg(env, &sender, &env.contract.address, None)?,
),
_ => {}
}
}

Ok((msgs, coins))
}

pub fn send_otc_items(
env: &Env,
items: &mut Vec<OtcItem>,
position_status: &OtcPositionStatus,
to: &Addr,
) -> StdResult<Vec<CosmosMsg>> {
let mut msgs: Vec<CosmosMsg> = vec![];
for item in items {
let amount = item.sendable_amount_and_update_claimed_amount(env, position_status)?;

if amount > Uint128::zero() {
msgs.push(item.item_info.build_send_msg(
env,
&env.contract.address,
to,
Some(amount),
)?)
}
}
Ok(msgs)
}

pub fn send_fee(
env: &Env,
items_info: &Vec<OtcItemInfo>,
fee_collector: &Addr,
funds: Vec<Coin>,
) -> StdResult<Vec<CosmosMsg>> {
assert_received_funds(items_info, funds)?;
build_send_otc_info_items(env, items_info, fee_collector)
}

pub fn cancel_otc(env: &Env, position: &OtcPosition) -> StdResult<Vec<CosmosMsg>> {
build_send_otc_info_items(
env,
&position
.offer
.iter()
.map(|val| val.item_info.clone())
.collect(),
&position.owner,
)
}

pub fn build_send_otc_info_items(
env: &Env,
items_info: &Vec<OtcItemInfo>,
to: &Addr,
) -> StdResult<Vec<CosmosMsg>> {
let mut msgs: Vec<CosmosMsg> = vec![];
for item_info in items_info {
msgs.push(item_info.build_send_msg(env, &env.contract.address, to, None)?)
}
Ok(msgs)
}

pub fn assert_received_funds(items: &Vec<OtcItemInfo>, funds: Vec<Coin>) -> StdResult<Vec<Coin>> {
let mut coins = rhaki_cw_plus::coin::vec_coins_to_hashmap(funds)?;

for item in items {
if let OtcItemInfo::Token { denom, amount } = &item {
let available_amount = coins
.get(denom)
.ok_or(StdError::generic_err(format!("Coin not received {denom}")))?;

if amount > available_amount {
return Err(StdError::generic_err(format!(
"Amount received for {denom} is to low: expected: {amount}, received: {amount}"
)));
}

coins.insert(denom.clone(), available_amount - amount);
}
}

Ok(coins
.into_iter()
.map(|(denom, amount)| Coin::new(amount.u128(), denom))
.collect())
}

pub fn try_close_position(
deps: DepsMut,
env: &Env,
position: &mut OtcPosition,
) -> StdResult<Vec<Attribute>> {
position.try_close(env)?;

if let OtcPositionStatus::Executed(..) = position.status {
active_positions().remove(deps.storage, position.id)?;
execute_positions().save(deps.storage, position.id, position)?;
return Ok(vec![
attr("action", "executed_position"),
attr("id", position.id.to_string()),
]);
}

Ok(vec![])
}
1 change: 1 addition & 0 deletions contracts/otc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[cfg(not(feature = "library"))]
pub mod contract;
mod execute;
mod functions;
mod query;
mod response;
mod state;
2 changes: 1 addition & 1 deletion contracts/otc/src/response.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cosmwasm_std::{StdError, Response};
use cosmwasm_std::{Response, StdError};
use thiserror::Error;

pub type ContractResponse = Result<Response, ContractError>;
Expand Down
Loading

0 comments on commit 760eced

Please sign in to comment.