Use Map to store utilization
This commit is contained in:
parent
4b343ea6ff
commit
cdb09737a2
3 changed files with 76 additions and 64 deletions
|
@ -2,11 +2,10 @@ use cosmwasm_std::{
|
||||||
entry_point, to_json_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
|
entry_point, to_json_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
|
||||||
};
|
};
|
||||||
use cw2::set_contract_version;
|
use cw2::set_contract_version;
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use crate::error::ContractError;
|
use crate::error::ContractError;
|
||||||
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
|
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
|
||||||
use crate::state::{State, STATE};
|
use crate::state::{State, STATE, UTILIZATION};
|
||||||
|
|
||||||
// version info for migration info
|
// version info for migration info
|
||||||
const CONTRACT_NAME: &str = "crates.io:cw-mtcs";
|
const CONTRACT_NAME: &str = "crates.io:cw-mtcs";
|
||||||
|
@ -20,8 +19,7 @@ pub fn instantiate(
|
||||||
_msg: InstantiateMsg,
|
_msg: InstantiateMsg,
|
||||||
) -> Result<Response, ContractError> {
|
) -> Result<Response, ContractError> {
|
||||||
let state = State {
|
let state = State {
|
||||||
utilization: Default::default(),
|
owner: info.sender.to_string(),
|
||||||
owner: info.sender.clone(),
|
|
||||||
};
|
};
|
||||||
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
||||||
STATE.save(deps.storage, &state)?;
|
STATE.save(deps.storage, &state)?;
|
||||||
|
@ -49,29 +47,32 @@ pub fn execute(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod execute {
|
pub mod execute {
|
||||||
|
use cosmwasm_std::Uint128;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn upload_obligation(
|
pub fn upload_obligation(
|
||||||
deps: DepsMut,
|
deps: DepsMut,
|
||||||
info: MessageInfo,
|
info: MessageInfo,
|
||||||
creditor: Addr,
|
creditor: String,
|
||||||
amount: u64,
|
amount: Uint128,
|
||||||
memo: String,
|
memo: String,
|
||||||
) -> Result<Response, ContractError> {
|
) -> Result<Response, ContractError> {
|
||||||
STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
|
let creditor = deps.api.addr_validate(&creditor)?;
|
||||||
|
|
||||||
|
UTILIZATION.update(
|
||||||
|
deps.storage,
|
||||||
|
(&creditor, &info.sender),
|
||||||
|
|utilization| -> Result<_, ContractError> {
|
||||||
// Uncomment if we want to only allow ourselves to add obligations
|
// Uncomment if we want to only allow ourselves to add obligations
|
||||||
// if info.sender != state.owner {
|
// if info.sender != state.owner {
|
||||||
// return Err(ContractError::Unauthorized);
|
// return Err(ContractError::Unauthorized);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
*state
|
let utilization = utilization.unwrap_or_default() + amount;
|
||||||
.utilization
|
Ok(utilization)
|
||||||
.entry(creditor)
|
},
|
||||||
.or_default()
|
)?;
|
||||||
.entry(info.sender)
|
|
||||||
.or_default() += amount;
|
|
||||||
Ok(state)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(Response::new()
|
Ok(Response::new()
|
||||||
.add_attribute("action", "upload_obligation")
|
.add_attribute("action", "upload_obligation")
|
||||||
|
@ -80,38 +81,46 @@ pub mod execute {
|
||||||
|
|
||||||
pub fn apply_cycle(
|
pub fn apply_cycle(
|
||||||
deps: DepsMut,
|
deps: DepsMut,
|
||||||
path: Vec<Addr>,
|
path: Vec<String>,
|
||||||
amount: u64,
|
amount: Uint128,
|
||||||
) -> Result<Response, ContractError> {
|
) -> Result<Response, ContractError> {
|
||||||
let mut volume_cleared = 0;
|
let mut volume_cleared = Uint128::zero();
|
||||||
|
|
||||||
STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
|
let path = path
|
||||||
validate_cycle(&path, amount, &state)?;
|
.into_iter()
|
||||||
|
.map(|addr| deps.api.addr_validate(&addr))
|
||||||
|
.collect::<StdResult<Vec<Addr>>>()?;
|
||||||
|
|
||||||
for (from, to) in path.into_iter().tuples() {
|
validate_cycle(&path, amount, &deps)?;
|
||||||
*state
|
|
||||||
.utilization
|
for from_to in path.windows(2) {
|
||||||
.get_mut(&to)
|
let (from, to) = (&from_to[0], &from_to[1]);
|
||||||
.unwrap()
|
|
||||||
.get_mut(&from)
|
UTILIZATION.update(
|
||||||
.unwrap() -= amount;
|
deps.storage,
|
||||||
|
(&to, &from),
|
||||||
|
|utilization| -> Result<_, ContractError> {
|
||||||
|
let utilization = utilization.unwrap_or_default() - amount;
|
||||||
volume_cleared += amount;
|
volume_cleared += amount;
|
||||||
}
|
|
||||||
|
|
||||||
Ok(state)
|
Ok(utilization)
|
||||||
})?;
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
Ok(Response::new()
|
Ok(Response::new()
|
||||||
.add_attribute("action", "apply_cycle")
|
.add_attribute("action", "apply_cycle")
|
||||||
.add_attribute("volume_cleared", format!("{}", volume_cleared)))
|
.add_attribute("volume_cleared", format!("{}", volume_cleared)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_cycle(path: &[Addr], amount: u64, state: &State) -> Result<(), ContractError> {
|
fn validate_cycle(path: &[Addr], amount: Uint128, deps: &DepsMut) -> Result<(), ContractError> {
|
||||||
if path.first() != path.last() {
|
if path.first() != path.last() {
|
||||||
return Err(ContractError::PathNotCycle);
|
return Err(ContractError::PathNotCycle);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (from, to) in path.iter().tuples() {
|
for from_to in path.windows(2) {
|
||||||
if amount > state.utilization[to][from] {
|
let (from, to) = (&from_to[0], &from_to[1]);
|
||||||
|
|
||||||
|
if amount > UTILIZATION.load(deps.storage, (to, from))? {
|
||||||
return Err(ContractError::ClearingTooMuch);
|
return Err(ContractError::ClearingTooMuch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,18 +140,26 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
|
||||||
|
|
||||||
pub mod query {
|
pub mod query {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::collections::HashMap;
|
use cosmwasm_std::Order;
|
||||||
|
|
||||||
use crate::msg::GetObligationsResponse;
|
use crate::msg::GetObligationsResponse;
|
||||||
|
use crate::state::UTILIZATION;
|
||||||
|
|
||||||
pub fn get_obligations(deps: Deps, creditor: Addr) -> StdResult<GetObligationsResponse> {
|
pub fn get_obligations(deps: Deps, creditor: String) -> StdResult<GetObligationsResponse> {
|
||||||
let state = STATE.load(deps.storage)?;
|
let creditor = deps.api.addr_validate(&creditor)?;
|
||||||
|
|
||||||
|
let keys = UTILIZATION
|
||||||
|
.keys(deps.storage, None, None, Order::Ascending)
|
||||||
|
.collect::<StdResult<Vec<(Addr, Addr)>>>()?
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(from, _)| from == creditor);
|
||||||
Ok(GetObligationsResponse {
|
Ok(GetObligationsResponse {
|
||||||
obligations: state
|
obligations: keys
|
||||||
.utilization
|
.map(|(from, to)| {
|
||||||
.get(&creditor)
|
let utilization = UTILIZATION.load(deps.storage, (&from, &to)).unwrap();
|
||||||
.unwrap_or(&HashMap::new())
|
(to.to_string(), utilization)
|
||||||
.clone(),
|
})
|
||||||
|
.collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use cosmwasm_schema::{cw_serde, QueryResponses};
|
use cosmwasm_schema::{cw_serde, QueryResponses};
|
||||||
use cosmwasm_std::Addr;
|
use cosmwasm_std::Uint128;
|
||||||
|
|
||||||
#[cw_serde]
|
#[cw_serde]
|
||||||
pub struct InstantiateMsg;
|
pub struct InstantiateMsg;
|
||||||
|
@ -9,13 +7,13 @@ pub struct InstantiateMsg;
|
||||||
#[cw_serde]
|
#[cw_serde]
|
||||||
pub enum ExecuteMsg {
|
pub enum ExecuteMsg {
|
||||||
UploadObligation {
|
UploadObligation {
|
||||||
creditor: Addr,
|
creditor: String,
|
||||||
amount: u64,
|
amount: Uint128,
|
||||||
memo: String,
|
memo: String,
|
||||||
},
|
},
|
||||||
ApplyCycle {
|
ApplyCycle {
|
||||||
path: Vec<Addr>,
|
path: Vec<String>,
|
||||||
amount: u64,
|
amount: Uint128,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,11 +22,11 @@ pub enum ExecuteMsg {
|
||||||
pub enum QueryMsg {
|
pub enum QueryMsg {
|
||||||
// GetCount returns the current count as a json-encoded number
|
// GetCount returns the current count as a json-encoded number
|
||||||
#[returns(GetObligationsResponse)]
|
#[returns(GetObligationsResponse)]
|
||||||
GetObligations { creditor: Addr },
|
GetObligations { creditor: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
// We define a custom struct for each query response
|
// We define a custom struct for each query response
|
||||||
#[cw_serde]
|
#[cw_serde]
|
||||||
pub struct GetObligationsResponse {
|
pub struct GetObligationsResponse {
|
||||||
pub obligations: HashMap<Addr, u64>,
|
pub obligations: Vec<(String, Uint128)>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
use std::collections::HashMap;
|
use cosmwasm_schema::cw_serde;
|
||||||
|
use cosmwasm_std::{Addr, Uint128};
|
||||||
|
use cw_storage_plus::{Item, Map};
|
||||||
|
|
||||||
use cosmwasm_std::Addr;
|
#[cw_serde]
|
||||||
use cw_storage_plus::Item;
|
|
||||||
use schemars::JsonSchema;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub utilization: HashMap<Addr, HashMap<Addr, u64>>,
|
pub owner: String,
|
||||||
pub owner: Addr,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const STATE: Item<State> = Item::new("state");
|
pub const STATE: Item<State> = Item::new("state");
|
||||||
|
pub const UTILIZATION: Map<(&Addr, &Addr), Uint128> = Map::new("utilization");
|
||||||
|
|
Loading…
Reference in a new issue