Implement core logic
This commit is contained in:
parent
855c955ffe
commit
4a916357a6
5 changed files with 116 additions and 37 deletions
|
@ -1,10 +1,11 @@
|
||||||
#[cfg(not(feature = "library"))]
|
use cosmwasm_std::{
|
||||||
use cosmwasm_std::entry_point;
|
entry_point, to_json_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
|
||||||
use cosmwasm_std::{to_json_binary, 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, GetCountResponse, InstantiateMsg, QueryMsg};
|
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
|
||||||
use crate::state::{State, STATE};
|
use crate::state::{State, STATE};
|
||||||
|
|
||||||
// version info for migration info
|
// version info for migration info
|
||||||
|
@ -16,10 +17,10 @@ pub fn instantiate(
|
||||||
deps: DepsMut,
|
deps: DepsMut,
|
||||||
_env: Env,
|
_env: Env,
|
||||||
info: MessageInfo,
|
info: MessageInfo,
|
||||||
msg: InstantiateMsg,
|
_msg: InstantiateMsg,
|
||||||
) -> Result<Response, ContractError> {
|
) -> Result<Response, ContractError> {
|
||||||
let state = State {
|
let state = State {
|
||||||
count: msg.count,
|
utilization: Default::default(),
|
||||||
owner: info.sender.clone(),
|
owner: info.sender.clone(),
|
||||||
};
|
};
|
||||||
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
||||||
|
@ -27,8 +28,7 @@ pub fn instantiate(
|
||||||
|
|
||||||
Ok(Response::new()
|
Ok(Response::new()
|
||||||
.add_attribute("method", "instantiate")
|
.add_attribute("method", "instantiate")
|
||||||
.add_attribute("owner", info.sender)
|
.add_attribute("owner", info.sender))
|
||||||
.add_attribute("count", msg.count.to_string()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "library"), entry_point)]
|
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||||
|
@ -39,48 +39,106 @@ pub fn execute(
|
||||||
msg: ExecuteMsg,
|
msg: ExecuteMsg,
|
||||||
) -> Result<Response, ContractError> {
|
) -> Result<Response, ContractError> {
|
||||||
match msg {
|
match msg {
|
||||||
ExecuteMsg::Increment {} => execute::increment(deps),
|
ExecuteMsg::UploadObligation {
|
||||||
ExecuteMsg::Reset { count } => execute::reset(deps, info, count),
|
creditor,
|
||||||
|
amount,
|
||||||
|
memo,
|
||||||
|
} => execute::upload_obligation(deps, info, creditor, amount, memo),
|
||||||
|
ExecuteMsg::ApplyCycle { path, amount } => execute::apply_cycle(deps, path, amount),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod execute {
|
pub mod execute {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn increment(deps: DepsMut) -> Result<Response, ContractError> {
|
pub fn upload_obligation(
|
||||||
|
deps: DepsMut,
|
||||||
|
info: MessageInfo,
|
||||||
|
creditor: Addr,
|
||||||
|
amount: u64,
|
||||||
|
memo: String,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
|
STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
|
||||||
state.count += 1;
|
// Uncomment if we want to only allow ourselves to add obligations
|
||||||
|
// if info.sender != state.owner {
|
||||||
|
// return Err(ContractError::Unauthorized);
|
||||||
|
// }
|
||||||
|
|
||||||
|
*state
|
||||||
|
.utilization
|
||||||
|
.get_mut(&creditor)
|
||||||
|
.unwrap()
|
||||||
|
.get_mut(&info.sender)
|
||||||
|
.unwrap() += amount;
|
||||||
Ok(state)
|
Ok(state)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Response::new().add_attribute("action", "increment"))
|
Ok(Response::new()
|
||||||
|
.add_attribute("action", "upload_obligation")
|
||||||
|
.add_attribute("memo", memo))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(deps: DepsMut, info: MessageInfo, count: i32) -> Result<Response, ContractError> {
|
pub fn apply_cycle(
|
||||||
|
deps: DepsMut,
|
||||||
|
path: Vec<Addr>,
|
||||||
|
amount: u64,
|
||||||
|
) -> Result<Response, ContractError> {
|
||||||
|
let mut volume_cleared = 0;
|
||||||
|
|
||||||
STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
|
STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
|
||||||
if info.sender != state.owner {
|
validate_cycle(&path, amount, &state)?;
|
||||||
return Err(ContractError::Unauthorized {});
|
|
||||||
|
for (from, to) in path.into_iter().tuples() {
|
||||||
|
*state
|
||||||
|
.utilization
|
||||||
|
.get_mut(&to)
|
||||||
|
.unwrap()
|
||||||
|
.get_mut(&from)
|
||||||
|
.unwrap() -= amount;
|
||||||
|
volume_cleared += amount;
|
||||||
}
|
}
|
||||||
state.count = count;
|
|
||||||
Ok(state)
|
Ok(state)
|
||||||
})?;
|
})?;
|
||||||
Ok(Response::new().add_attribute("action", "reset"))
|
Ok(Response::new()
|
||||||
|
.add_attribute("action", "apply_cycle")
|
||||||
|
.add_attribute("volume_cleared", format!("{}", volume_cleared)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_cycle(path: &[Addr], amount: u64, state: &State) -> Result<(), ContractError> {
|
||||||
|
if path.first() != path.last() {
|
||||||
|
return Err(ContractError::PathNotCycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (from, to) in path.iter().tuples() {
|
||||||
|
if amount > state.utilization[to][from] {
|
||||||
|
return Err(ContractError::ClearingTooMuch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(feature = "library"), entry_point)]
|
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||||
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
|
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
|
||||||
match msg {
|
match msg {
|
||||||
QueryMsg::GetCount {} => to_json_binary(&query::count(deps)?),
|
QueryMsg::GetObligations { creditor } => {
|
||||||
|
to_json_binary(&query::get_obligations(deps, creditor)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod query {
|
pub mod query {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn count(deps: Deps) -> StdResult<GetCountResponse> {
|
use crate::msg::GetObligationsResponse;
|
||||||
|
|
||||||
|
pub fn get_obligations(deps: Deps, creditor: Addr) -> StdResult<GetObligationsResponse> {
|
||||||
let state = STATE.load(deps.storage)?;
|
let state = STATE.load(deps.storage)?;
|
||||||
Ok(GetCountResponse { count: state.count })
|
Ok(GetObligationsResponse {
|
||||||
|
obligations: state.utilization[&creditor].clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,11 @@ pub enum ContractError {
|
||||||
Std(#[from] StdError),
|
Std(#[from] StdError),
|
||||||
|
|
||||||
#[error("Unauthorized")]
|
#[error("Unauthorized")]
|
||||||
Unauthorized {},
|
Unauthorized,
|
||||||
// Add any other custom errors you like here.
|
|
||||||
// Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details.
|
#[error("Specified path does not form a cycle")]
|
||||||
|
PathNotCycle,
|
||||||
|
|
||||||
|
#[error("Amount is greater than utilization")]
|
||||||
|
ClearingTooMuch,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
|
#![deny(
|
||||||
|
warnings,
|
||||||
|
trivial_casts,
|
||||||
|
trivial_numeric_casts,
|
||||||
|
unused_import_braces,
|
||||||
|
unused_qualifications
|
||||||
|
)]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
pub mod contract;
|
pub mod contract;
|
||||||
mod error;
|
mod error;
|
||||||
pub mod helpers;
|
|
||||||
pub mod integration_tests;
|
pub mod integration_tests;
|
||||||
pub mod msg;
|
pub mod msg;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
|
|
|
@ -1,26 +1,34 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use cosmwasm_schema::{cw_serde, QueryResponses};
|
use cosmwasm_schema::{cw_serde, QueryResponses};
|
||||||
|
use cosmwasm_std::Addr;
|
||||||
|
|
||||||
#[cw_serde]
|
#[cw_serde]
|
||||||
pub struct InstantiateMsg {
|
pub struct InstantiateMsg;
|
||||||
pub count: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cw_serde]
|
#[cw_serde]
|
||||||
pub enum ExecuteMsg {
|
pub enum ExecuteMsg {
|
||||||
Increment {},
|
UploadObligation {
|
||||||
Reset { count: i32 },
|
creditor: Addr,
|
||||||
|
amount: u64,
|
||||||
|
memo: String,
|
||||||
|
},
|
||||||
|
ApplyCycle {
|
||||||
|
path: Vec<Addr>,
|
||||||
|
amount: u64,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cw_serde]
|
#[cw_serde]
|
||||||
#[derive(QueryResponses)]
|
#[derive(QueryResponses)]
|
||||||
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(GetCountResponse)]
|
#[returns(GetObligationsResponse)]
|
||||||
GetCount {},
|
GetObligations { creditor: Addr },
|
||||||
}
|
}
|
||||||
|
|
||||||
// We define a custom struct for each query response
|
// We define a custom struct for each query response
|
||||||
#[cw_serde]
|
#[cw_serde]
|
||||||
pub struct GetCountResponse {
|
pub struct GetObligationsResponse {
|
||||||
pub count: i32,
|
pub obligations: HashMap<Addr, u64>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use schemars::JsonSchema;
|
use std::collections::HashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use cosmwasm_std::Addr;
|
use cosmwasm_std::Addr;
|
||||||
use cw_storage_plus::Item;
|
use cw_storage_plus::Item;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub count: i32,
|
pub utilization: HashMap<Addr, HashMap<Addr, u64>>,
|
||||||
pub owner: Addr,
|
pub owner: Addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue