Obligato liquidity prototype (#21)
This commit is contained in:
parent
57b2a050ff
commit
aa438c0d62
5 changed files with 190 additions and 20 deletions
|
@ -47,6 +47,8 @@ cosmwasm-std = { version = "1.5.0", features = [
|
|||
# "cosmwasm_1_4",
|
||||
] }
|
||||
cw-storage-plus = "1.1.0"
|
||||
cw20-base = { version = "1.1.1", features = ["library"] }
|
||||
cw20 = "1.1.1"
|
||||
cw2 = "1.1.1"
|
||||
hex = { version = "0.4.3", default-features = false }
|
||||
k256 = { version = "0.13.2", default-features = false, features = ["ecdsa"] }
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
use cosmwasm_std::{entry_point, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult};
|
||||
use cosmwasm_std::{
|
||||
entry_point, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult,
|
||||
Uint128,
|
||||
};
|
||||
use cw2::set_contract_version;
|
||||
use cw20_base::contract::execute_mint;
|
||||
use cw20_base::contract::query_balance as cw20_query_balance;
|
||||
use cw20_base::state::{MinterData, TokenInfo, TOKEN_INFO};
|
||||
use quartz_cw::handler::RawHandler;
|
||||
use quartz_cw::state::EPOCH_COUNTER;
|
||||
|
||||
use crate::error::ContractError;
|
||||
use crate::msg::execute::{SubmitObligationMsg, SubmitSetoffsMsg};
|
||||
use crate::msg::execute::{SubmitObligationMsg, SubmitObligationsMsg, SubmitSetoffsMsg};
|
||||
use crate::msg::QueryMsg;
|
||||
use crate::msg::{ExecuteMsg, InstantiateMsg};
|
||||
use crate::state::{current_epoch_key, ObligationsItem, State, OBLIGATIONS_KEY, STATE};
|
||||
|
@ -28,9 +35,54 @@ pub fn instantiate(
|
|||
set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
|
||||
STATE.save(deps.storage, &state)?;
|
||||
|
||||
EPOCH_COUNTER.save(deps.storage, &1)?;
|
||||
|
||||
ObligationsItem::new(¤t_epoch_key(OBLIGATIONS_KEY, deps.storage)?)
|
||||
.save(deps.storage, &Default::default())?;
|
||||
|
||||
// store token info using cw20-base format
|
||||
let data = TokenInfo {
|
||||
name: "USD".to_string(),
|
||||
symbol: "!$".to_string(),
|
||||
decimals: 0,
|
||||
total_supply: Uint128::zero(),
|
||||
// set self as minter, so we can properly execute mint and burn
|
||||
mint: Some(MinterData {
|
||||
minter: env.contract.address.clone(),
|
||||
cap: None,
|
||||
}),
|
||||
};
|
||||
TOKEN_INFO.save(deps.storage, &data)?;
|
||||
|
||||
let info = MessageInfo {
|
||||
sender: env.contract.address.clone(),
|
||||
funds: vec![],
|
||||
};
|
||||
|
||||
execute_mint(
|
||||
deps.branch(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
"wasm1qv9nel6lwtrq5jmwruxfndqw7ejskn5ysz53hp".to_owned(),
|
||||
Uint128::new(1000),
|
||||
)?;
|
||||
|
||||
execute_mint(
|
||||
deps.branch(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
"wasm1tfxrdcj5kk6rewzmmkku4d9htpjqr0kk6lcftv".to_owned(),
|
||||
Uint128::new(1000),
|
||||
)?;
|
||||
|
||||
execute_mint(
|
||||
deps.branch(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
"wasm1gjg72awjl7jvtmq4kjqp3al9p6crstpar8wgn5".to_owned(),
|
||||
Uint128::new(1000),
|
||||
)?;
|
||||
|
||||
Ok(Response::new()
|
||||
.add_attribute("method", "instantiate")
|
||||
.add_attribute("owner", info.sender))
|
||||
|
@ -38,7 +90,7 @@ pub fn instantiate(
|
|||
|
||||
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||
pub fn execute(
|
||||
deps: DepsMut,
|
||||
mut deps: DepsMut,
|
||||
env: Env,
|
||||
info: MessageInfo,
|
||||
msg: ExecuteMsg,
|
||||
|
@ -48,21 +100,30 @@ pub fn execute(
|
|||
ExecuteMsg::SubmitObligation(SubmitObligationMsg { ciphertext, digest }) => {
|
||||
execute::submit_obligation(deps, ciphertext, digest)
|
||||
}
|
||||
ExecuteMsg::SubmitSetoffs(SubmitSetoffsMsg { setoffs_enc }) => {
|
||||
execute::submit_setoffs(deps, setoffs_enc)
|
||||
ExecuteMsg::SubmitObligations(SubmitObligationsMsg(obligations)) => {
|
||||
for o in obligations {
|
||||
execute::submit_obligation(deps.branch(), o.ciphertext, o.digest)?;
|
||||
}
|
||||
Ok(Response::new())
|
||||
}
|
||||
ExecuteMsg::SubmitSetoffs(SubmitSetoffsMsg { setoffs_enc }) => {
|
||||
execute::submit_setoffs(deps, env, info, setoffs_enc)
|
||||
}
|
||||
ExecuteMsg::InitClearing => execute::init_clearing(deps),
|
||||
}
|
||||
}
|
||||
|
||||
pub mod execute {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use cosmwasm_std::{DepsMut, HexBinary, Response};
|
||||
use cosmwasm_std::{DepsMut, Env, HexBinary, MessageInfo, Response, StdResult};
|
||||
use cw20_base::contract::{execute_burn, execute_mint};
|
||||
use quartz_cw::state::Hash;
|
||||
use quartz_cw::state::EPOCH_COUNTER;
|
||||
|
||||
use crate::state::{
|
||||
current_epoch_key, ObligationsItem, RawCipherText, RawHash, SetoffsItem, OBLIGATIONS_KEY,
|
||||
SETOFFS_KEY,
|
||||
current_epoch_key, previous_epoch_key, ObligationsItem, RawHash, SetoffsItem, SettleOff,
|
||||
OBLIGATIONS_KEY, SETOFFS_KEY,
|
||||
};
|
||||
use crate::ContractError;
|
||||
|
||||
|
@ -91,18 +152,74 @@ pub mod execute {
|
|||
}
|
||||
|
||||
pub fn submit_setoffs(
|
||||
deps: DepsMut,
|
||||
setoffs_enc: BTreeMap<RawHash, RawCipherText>,
|
||||
mut deps: DepsMut,
|
||||
env: Env,
|
||||
_info: MessageInfo,
|
||||
setoffs_enc: BTreeMap<RawHash, SettleOff>,
|
||||
) -> Result<Response, ContractError> {
|
||||
// store the `BTreeMap<RawHash, RawCipherText>`
|
||||
SetoffsItem::new(¤t_epoch_key(SETOFFS_KEY, deps.storage)?)
|
||||
SetoffsItem::new(&previous_epoch_key(SETOFFS_KEY, deps.storage)?)
|
||||
.save(deps.storage, &setoffs_enc)?;
|
||||
|
||||
for (_, so) in setoffs_enc {
|
||||
if let SettleOff::Transfer(t) = so {
|
||||
let info = MessageInfo {
|
||||
sender: env.contract.address.clone(),
|
||||
funds: vec![],
|
||||
};
|
||||
|
||||
execute_mint(
|
||||
deps.branch(),
|
||||
env.clone(),
|
||||
info.clone(),
|
||||
t.payee.to_string(),
|
||||
t.amount.into(),
|
||||
)?;
|
||||
|
||||
let payer = deps.api.addr_validate(&t.payer.to_string())?;
|
||||
let info = MessageInfo {
|
||||
sender: payer,
|
||||
funds: vec![],
|
||||
};
|
||||
|
||||
execute_burn(deps.branch(), env.clone(), info, t.amount.into())?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Response::new().add_attribute("action", "submit_setoffs"))
|
||||
}
|
||||
|
||||
pub fn init_clearing(deps: DepsMut) -> Result<Response, ContractError> {
|
||||
EPOCH_COUNTER.update(deps.storage, |mut counter| -> StdResult<_> {
|
||||
counter += 1;
|
||||
Ok(counter)
|
||||
})?;
|
||||
Ok(Response::new().add_attribute("action", "init_clearing"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "library"), entry_point)]
|
||||
pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
|
||||
match msg {}
|
||||
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
|
||||
match msg {
|
||||
QueryMsg::GetAllSetoffs => to_json_binary(&query::get_all_setoffs(deps)?),
|
||||
QueryMsg::Balance { address } => to_json_binary(&cw20_query_balance(deps, address)?),
|
||||
}
|
||||
}
|
||||
|
||||
pub mod query {
|
||||
use cosmwasm_std::Deps;
|
||||
use cosmwasm_std::StdResult;
|
||||
|
||||
use crate::msg::GetAllSetoffsResponse;
|
||||
use crate::state::previous_epoch_key;
|
||||
use crate::state::SetoffsItem;
|
||||
use crate::state::SETOFFS_KEY;
|
||||
|
||||
pub fn get_all_setoffs(deps: Deps) -> StdResult<GetAllSetoffsResponse> {
|
||||
let setoffs = SetoffsItem::new(&previous_epoch_key(SETOFFS_KEY, deps.storage)?)
|
||||
.load(deps.storage)?
|
||||
.into_iter()
|
||||
.collect();
|
||||
Ok(GetAllSetoffsResponse { setoffs })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use cosmwasm_std::StdError;
|
||||
use cw20_base::ContractError as Cw20ContractError;
|
||||
use hex::FromHexError;
|
||||
use k256::ecdsa::Error as K256Error;
|
||||
use quartz_cw::error::Error as QuartzError;
|
||||
|
@ -26,6 +27,9 @@ pub enum ContractError {
|
|||
|
||||
#[error("Invalid length")]
|
||||
BadLength,
|
||||
|
||||
#[error("Cw20 error: {0}")]
|
||||
Cw20(Cw20ContractError),
|
||||
}
|
||||
|
||||
impl From<K256Error> for ContractError {
|
||||
|
@ -33,3 +37,9 @@ impl From<K256Error> for ContractError {
|
|||
Self::K256(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cw20ContractError> for ContractError {
|
||||
fn from(e: Cw20ContractError) -> Self {
|
||||
Self::Cw20(e)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use cosmwasm_schema::{cw_serde, QueryResponses};
|
||||
use cosmwasm_std::HexBinary;
|
||||
use quartz_cw::prelude::*;
|
||||
|
||||
use crate::state::{RawCipherText, RawHash};
|
||||
use crate::state::RawHash;
|
||||
use crate::state::SettleOff;
|
||||
|
||||
#[cw_serde]
|
||||
#[serde(transparent)]
|
||||
pub struct InstantiateMsg(pub QuartzInstantiateMsg);
|
||||
|
||||
#[cw_serde]
|
||||
|
@ -14,12 +15,12 @@ pub struct InstantiateMsg(pub QuartzInstantiateMsg);
|
|||
pub enum ExecuteMsg {
|
||||
Quartz(QuartzExecuteMsg),
|
||||
SubmitObligation(execute::SubmitObligationMsg),
|
||||
SubmitObligations(execute::SubmitObligationsMsg),
|
||||
SubmitSetoffs(execute::SubmitSetoffsMsg),
|
||||
InitClearing,
|
||||
}
|
||||
|
||||
pub mod execute {
|
||||
use cosmwasm_std::HexBinary;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[cw_serde]
|
||||
|
@ -30,15 +31,37 @@ pub mod execute {
|
|||
// pub proof: π
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
#[serde(transparent)]
|
||||
pub struct SubmitObligationsMsg(pub Vec<SubmitObligationMsg>);
|
||||
|
||||
#[cw_serde]
|
||||
pub struct SubmitTenderMsg {
|
||||
pub ciphertext: HexBinary,
|
||||
pub digest: HexBinary,
|
||||
// pub proof: π
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct SubmitSetoffsMsg {
|
||||
pub setoffs_enc: BTreeMap<RawHash, RawCipherText>,
|
||||
pub setoffs_enc: BTreeMap<RawHash, SettleOff>,
|
||||
// pub proof: π,
|
||||
}
|
||||
}
|
||||
#[cw_serde]
|
||||
#[derive(QueryResponses)]
|
||||
pub enum QueryMsg {}
|
||||
pub enum QueryMsg {
|
||||
#[returns(GetAllSetoffsResponse)]
|
||||
GetAllSetoffs,
|
||||
#[returns(cw20::BalanceResponse)]
|
||||
Balance { address: String },
|
||||
}
|
||||
|
||||
// We define a custom struct for each query response
|
||||
#[cw_serde]
|
||||
pub struct GetAllSetoffsResponse {
|
||||
pub setoffs: Vec<(HexBinary, SettleOff)>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
|
@ -9,13 +9,27 @@ pub type RawHash = HexBinary;
|
|||
pub type RawCipherText = HexBinary;
|
||||
|
||||
pub type ObligationsItem<'a> = Item<'a, BTreeMap<RawHash, RawCipherText>>;
|
||||
pub type SetoffsItem<'a> = Item<'a, BTreeMap<RawHash, RawCipherText>>;
|
||||
pub type SetoffsItem<'a> = Item<'a, BTreeMap<RawHash, SettleOff>>;
|
||||
|
||||
#[cw_serde]
|
||||
pub struct State {
|
||||
pub owner: String,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
pub struct Transfer {
|
||||
pub payer: String,
|
||||
pub payee: String,
|
||||
pub amount: u64,
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
#[serde(untagged)]
|
||||
pub enum SettleOff {
|
||||
SetOff(Vec<RawCipherText>),
|
||||
Transfer(Transfer),
|
||||
}
|
||||
|
||||
pub const STATE: Item<State> = Item::new("state");
|
||||
pub const OBLIGATIONS_KEY: &str = "obligations";
|
||||
pub const SETOFFS_KEY: &str = "setoffs";
|
||||
|
@ -23,3 +37,7 @@ pub const SETOFFS_KEY: &str = "setoffs";
|
|||
pub fn current_epoch_key(key: &str, storage: &dyn Storage) -> Result<String, StdError> {
|
||||
Ok(format!("{}/{key}", EPOCH_COUNTER.load(storage)?))
|
||||
}
|
||||
|
||||
pub fn previous_epoch_key(key: &str, storage: &dyn Storage) -> Result<String, StdError> {
|
||||
Ok(format!("{}/{key}", EPOCH_COUNTER.load(storage)? - 1))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue