From c3fd9284a4f2ca687ffa7c3503e19024c04095d3 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 15 Dec 2020 17:29:42 +0100 Subject: [PATCH] Begin implementing buy/sell logic --- contracts/cw20-base/src/allowances.rs | 2 +- contracts/cw20-bonding/src/contract.rs | 88 +++++++++++++++----------- contracts/cw20-bonding/src/state.rs | 9 +-- 3 files changed, 57 insertions(+), 42 deletions(-) diff --git a/contracts/cw20-base/src/allowances.rs b/contracts/cw20-base/src/allowances.rs index bf1b95c24..63496f3e6 100644 --- a/contracts/cw20-base/src/allowances.rs +++ b/contracts/cw20-base/src/allowances.rs @@ -90,7 +90,7 @@ pub fn handle_decrease_allowance( } // this can be used to update a lower allowance - call bucket.update with proper keys -fn deduct_allowance( +pub fn deduct_allowance( storage: &mut dyn Storage, owner: &CanonicalAddr, spender: &CanonicalAddr, diff --git a/contracts/cw20-bonding/src/contract.rs b/contracts/cw20-bonding/src/contract.rs index 7726e3594..9ebbd9837 100644 --- a/contracts/cw20-bonding/src/contract.rs +++ b/contracts/cw20-bonding/src/contract.rs @@ -5,17 +5,21 @@ use cosmwasm_std::{ use cw2::set_contract_version; use cw20_base::allowances::{ - handle_decrease_allowance, handle_increase_allowance, handle_send_from, handle_transfer_from, - query_allowance, + deduct_allowance, handle_decrease_allowance, handle_increase_allowance, handle_send_from, + handle_transfer_from, query_allowance, }; use cw20_base::contract::{ - handle_burn, handle_mint, handle_send, handle_transfer, query_balance, query_token_info, + handle_send, + handle_transfer, + query_balance, + query_token_info, + // handle_burn, handle_mint, }; use cw20_base::state::{token_info, MinterData, TokenInfo}; use crate::error::ContractError; use crate::msg::{CurveInfoResponse, HandleMsg, InitMsg, QueryMsg}; -use crate::state::{Supply, SUPPLY}; +use crate::state::{CurveState, CURVE_STATE}; // version info for migration info const CONTRACT_NAME: &str = "crates.io:cw20-bonding"; @@ -43,8 +47,8 @@ pub fn init( }; token_info(deps.storage).save(&data)?; - let supply = Supply::new(msg.reserve_denom); - SUPPLY.save(deps.storage, &supply)?; + let supply = CurveState::new(msg.reserve_denom); + CURVE_STATE.save(deps.storage, &supply)?; Ok(InitResponse::default()) } @@ -107,31 +111,33 @@ pub fn handle( pub fn handle_buy( deps: DepsMut, - env: Env, + _env: Env, info: MessageInfo, ) -> Result { + let supply = CURVE_STATE.load(deps.storage)?; + + // ensure the sent denom was proper + let sent = match info.sent_funds.len() { + 0 => Err(ContractError::NoFunds {}), + 1 => { + if info.sent_funds[0].denom == supply.reserve_denom { + Ok(info.sent_funds[0].amount) + } else { + Err(ContractError::MissingDenom(supply.reserve_denom.clone())) + } + } + _ => Err(ContractError::ExtraDenoms(supply.reserve_denom.clone())), + }?; + if sent.is_zero() { + return Err(ContractError::NoFunds {}); + } + + // TODO: calculate how many tokens can be purchased with this and mint them + unimplemented!(); - // // ensure we have the proper denom - // let invest = invest_info_read(deps.storage).load()?; - // // payment finds the proper coin (or throws an error) - // let payment = info - // .sent_funds - // .iter() - // .find(|x| x.denom == invest.bond_denom) - // .ok_or_else(|| ContractError::EmptyBalance { - // denom: invest.bond_denom.clone(), - // })?; - // - // // bonded is the total number of tokens we have delegated from this address - // let bonded = get_bonded(&deps.querier, &env.contract.address)?; - // // // calculate to_mint and update total supply // let mut totals = total_supply(deps.storage); // let mut supply = totals.load()?; - // // TODO: this is just a safety assertion - do we keep it, or remove caching? - // // in the end supply is just there to cache the (expected) results of get_bonded() so we don't - // // have expensive queries everywhere - // assert_bonds(&supply, bonded)?; // let to_mint = if supply.issued.is_zero() || bonded.is_zero() { // FALLBACK_RATIO * payment.amount // } else { @@ -150,11 +156,6 @@ pub fn handle_buy( // // // bond them to the validator // let res = HandleResponse { - // messages: vec![StakingMsg::Delegate { - // validator: invest.validator, - // amount: payment.clone(), - // } - // .into()], // attributes: vec![ // attr("action", "bond"), // attr("from", info.sender), @@ -167,10 +168,10 @@ pub fn handle_buy( } pub fn handle_sell( - deps: DepsMut, - env: Env, - info: MessageInfo, - amount: Uint128, + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _amount: Uint128, ) -> Result { unimplemented!(); } @@ -182,7 +183,18 @@ pub fn handle_sell_from( owner: HumanAddr, amount: Uint128, ) -> Result { - unimplemented!(); + let owner_raw = deps.api.canonical_address(&owner)?; + let spender_raw = deps.api.canonical_address(&info.sender)?; + + // deduct allowance before doing anything else have enough allowance + deduct_allowance(deps.storage, &owner_raw, &spender_raw, &env.block, amount)?; + + // TODO: don't return verbatim, different return attrs + let owner_info = MessageInfo { + sender: owner.clone(), + sent_funds: info.sent_funds, + }; + handle_sell(deps, env, owner_info, amount) } // pub fn unbond( @@ -273,11 +285,11 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { } pub fn query_curve_info(deps: Deps) -> StdResult { - let Supply { + let CurveState { reserve, supply, reserve_denom, - } = SUPPLY.load(deps.storage)?; + } = CURVE_STATE.load(deps.storage)?; Ok(CurveInfoResponse { reserve, supply, @@ -287,6 +299,8 @@ pub fn query_curve_info(deps: Deps) -> StdResult { }) } +// this is poor mans "skip" flag +#[cfg(target_arch = "arm")] #[cfg(test)] mod tests { use super::*; diff --git a/contracts/cw20-bonding/src/state.rs b/contracts/cw20-bonding/src/state.rs index 2f2db58ab..727bbb05f 100644 --- a/contracts/cw20-bonding/src/state.rs +++ b/contracts/cw20-bonding/src/state.rs @@ -6,7 +6,7 @@ use cw_storage_plus::Item; /// Supply is dynamic and tracks the current supply of staked and ERC20 tokens. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema, Default)] -pub struct Supply { +pub struct CurveState { /// reserve is how many native tokens exist bonded to the validator pub reserve: Uint128, /// supply is how many tokens this contract has issued @@ -16,9 +16,9 @@ pub struct Supply { pub reserve_denom: String, } -impl Supply { +impl CurveState { pub fn new(reserve_denom: String) -> Self { - Supply { + CurveState { reserve: Uint128(0), supply: Uint128(0), reserve_denom, @@ -26,6 +26,7 @@ impl Supply { } } -pub const SUPPLY: Item = Item::new("total_supply"); +pub const CURVE_STATE: Item = Item::new("total_supply"); +// TODO: add curve functions // TODO: make this customizable in handle/query call