use cosmwasm_std::{ entry_point, to_json_binary, Binary, Deps, DepsMut, Env, HexBinary, MessageInfo, Response, StdResult, }; use quartz_cw::handler::RawHandler; use crate::{ error::ContractError, msg::{ execute::{QueryResponseMsg, Request, UpdateMsg}, ExecuteMsg, InstantiateMsg, QueryMsg, }, state::{BALANCES, DENOM, REQUESTS, STATE}, }; #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( mut deps: DepsMut, env: Env, info: MessageInfo, msg: InstantiateMsg, ) -> Result { // must be handled first! msg.quartz.handle_raw(deps.branch(), &env, &info)?; DENOM.save(deps.storage, &msg.denom)?; let requests: Vec = Vec::new(); REQUESTS.save(deps.storage, &requests)?; let state: HexBinary = HexBinary::from(&[0x00]); STATE.save(deps.storage, &state)?; Ok(Response::new() .add_attribute("method", "instantiate") .add_attribute("owner", info.sender)) } #[cfg_attr(not(feature = "library"), entry_point)] pub fn execute( mut deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { use execute::*; match msg { // Quartz msgs ExecuteMsg::Quartz(msg) => msg.handle_raw(deps, &env, &info).map_err(Into::into), // Clear user msgs ExecuteMsg::Deposit => deposit(deps, env, info), ExecuteMsg::Withdraw => withdraw(deps, env, info), ExecuteMsg::ClearTextTransferRequest(_) => unimplemented!(), ExecuteMsg::QueryRequest(msg) => query_balance(deps, env, info, msg), // Cipher user msgs ExecuteMsg::TransferRequest(msg) => transfer_request(deps, env, info, msg), // Enclave msgs ExecuteMsg::Update(attested_msg) => { let _ = attested_msg .clone() .handle_raw(deps.branch(), &env, &info)?; let UpdateMsg { ciphertext, quantity, withdrawals, } = attested_msg.msg.0; update( deps, env, info, UpdateMsg { ciphertext, quantity, withdrawals, }, ) } ExecuteMsg::QueryResponse(attested_msg) => { let _ = attested_msg .clone() .handle_raw(deps.branch(), &env, &info)?; let QueryResponseMsg { address, encrypted_bal, } = attested_msg.msg.0; store_balance( deps, env, info, QueryResponseMsg { address, encrypted_bal, }, ) } } } pub mod execute { use cosmwasm_std::{coins, BankMsg, DepsMut, Env, Event, MessageInfo, Response}; use cw_utils::must_pay; use crate::{ error::ContractError, msg::execute::{QueryRequestMsg, QueryResponseMsg, Request, TransferRequestMsg, UpdateMsg}, state::{BALANCES, DENOM, REQUESTS, STATE}, }; pub fn deposit(deps: DepsMut, _env: Env, info: MessageInfo) -> Result { let denom: String = DENOM.load(deps.storage)?; let quantity = must_pay(&info, &denom)?; let mut requests = REQUESTS.load(deps.storage)?; requests.push(Request::Deposit(info.sender, quantity)); REQUESTS.save(deps.storage, &requests)?; let event = Event::new("transfer").add_attribute("action", "user"); let resp = Response::new().add_event(event); Ok(resp) } pub fn withdraw( deps: DepsMut, _env: Env, info: MessageInfo, ) -> Result { let mut requests = REQUESTS.load(deps.storage)?; requests.push(Request::Withdraw(info.sender)); REQUESTS.save(deps.storage, &requests)?; let event = Event::new("transfer").add_attribute("action", "user"); let resp = Response::new().add_event(event); Ok(resp) } pub fn query_balance( _deps: DepsMut, _env: Env, _info: MessageInfo, msg: QueryRequestMsg, ) -> Result { let event = Event::new("query_balance") .add_attribute("query", "user") .add_attribute("emphemeral_pubkey", msg.emphemeral_pubkey.to_string()); let resp = Response::new().add_event(event); Ok(resp) } pub fn transfer_request( deps: DepsMut, _env: Env, _info: MessageInfo, msg: TransferRequestMsg, ) -> Result { let mut requests = REQUESTS.load(deps.storage)?; requests.push(Request::Transfer(msg.ciphertext)); REQUESTS.save(deps.storage, &requests)?; let event = Event::new("transfer").add_attribute("action", "user"); let resp = Response::new().add_event(event); Ok(resp) } pub fn update( deps: DepsMut, _env: Env, _info: MessageInfo, msg: UpdateMsg, ) -> Result { // Store state STATE.save(deps.storage, &msg.ciphertext)?; // Clear queue let mut requests: Vec = REQUESTS.load(deps.storage)?; requests.drain(0..msg.quantity as usize); REQUESTS.save(deps.storage, &requests)?; // Process withdrawals let denom = DENOM.load(deps.storage)?; let messages = msg .withdrawals .into_iter() .map(|(user, funds)| BankMsg::Send { to_address: user.to_string(), amount: coins(funds.into(), &denom), }); let resp = Response::new().add_messages(messages); Ok(resp) } pub fn store_balance( deps: DepsMut, _env: Env, _info: MessageInfo, msg: QueryResponseMsg, ) -> Result { // Store state BALANCES.save(deps.storage, &msg.address.to_string(), &msg.encrypted_bal)?; // Emit event let event = Event::new("store_balance") .add_attribute("query", "enclave") // TODO Weird to name it enclave? .add_attribute("address", msg.address.to_string()) .add_attribute("encrypted_balance", msg.encrypted_bal.to_string()); let resp = Response::new().add_event(event); Ok(resp) } } #[cfg_attr(not(feature = "library"), entry_point)] pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { match msg { QueryMsg::GetBalance { address } => to_json_binary(&query::get_balance(deps, address)?), } } mod query { use super::*; pub fn get_balance(deps: Deps, address: String) -> StdResult { let balance = BALANCES.may_load(deps.storage, &address)?; Ok(balance.unwrap_or_default()) } }