diff --git a/packages/bindings/src/msg.rs b/packages/bindings/src/msg.rs index d6e2919..c741f04 100644 --- a/packages/bindings/src/msg.rs +++ b/packages/bindings/src/msg.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Coin, CosmosMsg, CustomMsg, Decimal, Uint128,Addr}; +use cosmwasm_std::{Coin, CosmosMsg, CustomMsg, Decimal, Uint128}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -113,26 +113,26 @@ pub enum ComdexMessages { }, MsgEmissionRewards { app_id: u64, - emission_amount :u128, + amount :Uint128, extended_pair : Vec, voting_ratio: Vec } , MsgFoundationEmission { app_id: u64, - amount :u128, - foundation_address : Vec, + amount :Uint128, + foundation_address : Vec, }, MsgRebaseMint { app_id: u64, - amount :u128, - contract_addr : Addr, + amount :Uint128, + contract_addr : String, }, MsgGetSurplusFund{ app_id: u64, asset_id: u64, - contract_addr: Addr, + contract_addr: String, amount: Coin, } diff --git a/packages/bindings/target/debug/deps/libcomdex_bindings-083005091e80b8c7.rmeta b/packages/bindings/target/debug/deps/libcomdex_bindings-083005091e80b8c7.rmeta index 8c24529..c352083 100644 Binary files a/packages/bindings/target/debug/deps/libcomdex_bindings-083005091e80b8c7.rmeta and b/packages/bindings/target/debug/deps/libcomdex_bindings-083005091e80b8c7.rmeta differ diff --git a/src/contract.rs b/src/contract.rs index 175689b..6a97e9e 100644 --- a/src/contract.rs +++ b/src/contract.rs @@ -1,27 +1,26 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - to_binary, Addr, BankMsg, Coin, CosmosMsg, Decimal, Deps, DepsMut, Env, MessageInfo, - QueryRequest, Response, StdError, StdResult, Storage, Timestamp, Uint128, WasmQuery, + to_binary, Addr, BankMsg, Coin, Decimal, Deps, DepsMut, Env, MessageInfo, + QueryRequest, Response, StdError, StdResult, Storage, Uint128, WasmQuery, }; use cw2::set_contract_version; -use schemars::_serde_json::de; -use std::ops::{AddAssign, Div, Mul, Sub, SubAssign}; - +use std::ops::{Div, Mul}; use crate::error::ContractError; use crate::helpers::{ get_token_supply, query_app_exists, query_extended_pair_by_app, query_get_asset_data, query_surplus_reward, query_whitelisted_asset, }; -use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg}; +use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg,SudoMsg}; use crate::state::{ - Emission, LockingPeriod, PeriodWeight, State, Status, TokenInfo, TokenSupply, Vtoken, STATE, - SUPPLY, TOKENS, VTOKENS, + LockingPeriod, PeriodWeight, State, Status, TokenInfo, TokenSupply, Vtoken, STATE, + SUPPLY, TOKENS, VTOKENS, }; use crate::state::{ Proposal, Vote, APPCURRENTPROPOSAL, BRIBES_BY_PROPOSAL, COMPLETEDPROPOSALS, EMISSION, MAXPROPOSALCLAIMED, PROPOSAL, PROPOSALCOUNT, PROPOSALVOTE, VOTERSPROPOSAL, VOTERS_VOTE, - VOTINGPERIOD, + LOCKINGADDRESS + }; use comdex_bindings::{ComdexMessages, ComdexQuery}; @@ -48,12 +47,16 @@ pub fn instantiate( surplus_asset_id: msg.surplus_asset_id, voting_period: msg.voting_period, }; + + //// Set Contract version set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + //// Set State STATE.save(deps.storage, &state)?; - set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - VOTINGPERIOD.save(deps.storage, &msg.voting_period)?; + EMISSION.save(deps.storage, msg.emission.app_id, &msg.emission)?; + PROPOSALCOUNT.save(deps.storage, &0)?; + Ok(Response::new() .add_attribute("method", "instantiate") .add_attribute("owner", info.sender)) @@ -77,29 +80,23 @@ pub fn execute( proposal_id, extended_pair, } => bribe_proposal(deps, env, info, proposal_id, extended_pair), - ExecuteMsg::ClaimReward { app_id } => claim_rewards(deps, env, info, app_id), - ExecuteMsg::Emmission { proposal_id } => emission(deps, env, info, proposal_id), - ExecuteMsg::Lock { app_id, locking_period, } => handle_lock_nft(deps, env, info, app_id, locking_period), - - ExecuteMsg::Withdraw { - denom, - lockingperiod, - } => handle_withdraw(deps, env, info, denom, lockingperiod), - + ExecuteMsg::Withdraw {denom,} => handle_withdraw(deps, env, info, denom), ExecuteMsg::Transfer { recipent, locking_period, denom, } => handle_transfer(deps, env, info, recipent, locking_period, denom), - ExecuteMsg::FoundationRewards { proposal_id } => { - emission_foundation(deps, env, info, proposal_id) - } + ExecuteMsg::FoundationRewards { proposal_id } => + emission_foundation(deps, env, info, proposal_id), + ExecuteMsg::Rebase { proposal_id,app_id } => + calculate_rebase_reward(deps, env, info, proposal_id,app_id), + _ => panic!("Not implemented"), } } @@ -115,7 +112,7 @@ pub fn emission_foundation( // check emission already compluted and executed if !proposal.emission_completed { return Err(ContractError::CustomError { - val: "Emission caluclation did not take place to initiate rebase calculation" + val: "Emission caluclation did not take place to initiate foundation calculation" .to_string(), }); } @@ -128,23 +125,27 @@ pub fn emission_foundation( } let state = STATE.load(deps.storage)?; + let foundation_addr = state.foundation_addr; + let foundation_emission = proposal.foundation_distributed; - //// addr binding pending - let emission_msg = ComdexMessages::MsgFoundationEmission { - app_id: proposal.app_id, - amount: foundation_emission, - foundation_address: foundation_addr, - }; + + //// message to send tokens to foundation_address + let emission_msg = ComdexMessages::MsgFoundationEmission {app_id: proposal.app_id, + amount: Uint128::from(foundation_emission), + foundation_address: foundation_addr,}; proposal.foundation_emission_completed = true; + PROPOSAL.save(deps.storage, proposal_id, &proposal)?; Ok(Response::new() .add_messages(vec![emission_msg]) - .add_attribute("action", "lock") - .add_attribute("from", info.sender)) + .add_attribute("action", "Foundation_Emission") + .add_attribute("from", info.sender) + ) } + fn lock_funds( deps: DepsMut, env: Env, @@ -187,6 +188,8 @@ fn lock_funds( token_id: state.num_tokens, }; + STATE.save(deps.storage, &state)?; + new_nft.vtokens.push(new_vtoken.clone()); TOKENS.save(deps.storage, sender.clone(), &new_nft)?; } @@ -211,7 +214,6 @@ fn lock_funds( Ok(()) } - /// Lock the sent tokens and create corresponding vtokens pub fn handle_lock_nft( deps: DepsMut, @@ -233,6 +235,20 @@ pub fn handle_lock_nft( return Err(ContractError::InsufficientFunds { funds: 0 }); } + let mut addresses = match LOCKINGADDRESS.may_load(deps.storage, app_id)? + { + Some(val)=>val , + None => vec![], + + }; + + match addresses.contains(&info.sender) { + true => (), + false => { addresses.push(info.sender.clone()); + } + } + + let app_response = query_app_exists(deps.as_ref(), app_id)?; let gov_token_id = app_response.gov_token_id; let gov_token_denom = query_get_asset_data(deps.as_ref(), gov_token_id)?; @@ -326,9 +342,13 @@ fn update_denom_supply( denom_supply_struct.token += quantity; } else { if denom_supply_struct.vtoken < vquantity { - return Err(ContractError::InsufficientFunds { funds: vquantity }); + return Err(ContractError::InsufficientFunds { + funds: denom_supply_struct.vtoken, + }); } else if denom_supply_struct.token < quantity { - return Err(ContractError::InsufficientFunds { funds: quantity }); + return Err(ContractError::InsufficientFunds { + funds: denom_supply_struct.token, + }); } denom_supply_struct.vtoken -= vquantity; @@ -339,14 +359,12 @@ fn update_denom_supply( Ok(()) } - /// Handles the withdrawal of tokens after completion of locking period. pub fn handle_withdraw( deps: DepsMut, env: Env, info: MessageInfo, denom: String, - locking_period: LockingPeriod, ) -> Result, ContractError> { if info.funds.len() != 0 { return Err(ContractError::FundsNotAllowed {}); @@ -367,24 +385,26 @@ pub fn handle_withdraw( let vtokens: Vec<(usize, &Vtoken)> = vtokens_denom .iter() .enumerate() - .filter(|s| s.1.period == locking_period && s.1.end_time < env.block.time) + .filter(|s| s.1.end_time < env.block.time) .collect(); // No unlocked tokens if vtokens.is_empty() { return Err(ContractError::NotFound { - msg: format!("No unlocked tokens found for {:?}", locking_period), + msg: format!("No unlocked tokens found for {:?}", denom), }); } // Calculate total withdrawable amount and remove the corresponding VToken let mut withdrawable = 0u128; + let mut vwithdrawable = 0u128; let mut indices: Vec = vec![]; for (index, vtoken) in vtokens { withdrawable += vtoken.token.amount.u128(); + vwithdrawable += vtoken.vtoken.amount.u128(); indices.push(index); } - for index in indices { + for index in indices.into_iter().rev() { vtokens_denom.remove(index); } // Update VTOKENS @@ -394,17 +414,16 @@ pub fn handle_withdraw( VTOKENS.save(deps.storage, (info.sender.clone(), &denom), &vtokens_denom)?; }; + // Reduce the total supply + update_denom_supply(deps.storage, &denom, vwithdrawable, withdrawable, false)?; + // Update nft let mut nft = TOKENS.load(deps.as_ref().storage, info.sender.clone())?; let denom_indicies: Vec<(usize, &Vtoken)> = nft .vtokens .iter() .enumerate() - .filter(|el| { - el.1.token.denom == denom - && el.1.period == locking_period - && el.1.end_time < env.block.time - }) + .filter(|el| el.1.token.denom == denom && el.1.end_time < env.block.time) .collect(); // Remove the unlocked tokens @@ -412,7 +431,7 @@ pub fn handle_withdraw( for (index, _) in denom_indicies.into_iter() { indices.push(index); } - for index in indices { + for index in indices.into_iter().rev() { nft.vtokens.remove(index); } TOKENS.save(deps.storage, info.sender.clone(), &nft)?; @@ -438,6 +457,8 @@ fn get_period(state: State, locking_period: LockingPeriod) -> Result, @@ -572,24 +593,41 @@ pub fn bribe_proposal( ) -> Result, ContractError> { //check if active proposal let proposal = PROPOSAL.load(deps.storage, proposal_id)?; - if proposal.voting_end_time < env.block.time.seconds() { + if proposal.voting_end_time < env.block.time { return Err(ContractError::CustomError { val: "Proposal Bribing Period Ended".to_string(), }); } + + // check if ext_pair param exist in extended pair list to vote for + + let extended_pairs = proposal.extended_pair.clone(); + + match extended_pairs.binary_search(&extended_pair) { + Ok(_) => (), + Err(_) => { + return Err(ContractError::CustomError { + val: "Invalid Extended pair".to_string(), + }) + } + } + // bribe denom should be a single coin if info.funds.is_empty() { return Err(ContractError::InsufficientFunds { funds: 0 }); - } else if info.funds.len() > 1 { + } + else if info.funds.len() > 1 { return Err(ContractError::CustomError { val: String::from("Multiple denominations are not supported as yet."), }); } - + + // bribe coin should not have zero amount if info.funds[0].amount.is_zero() { return Err(ContractError::InsufficientFunds { funds: 0 }); } + // CHECK IF BRIBE ASSET EXISTS ON-CHAIN let bribe_coin = info.funds[0].clone(); let found = query_whitelisted_asset(deps.as_ref(), bribe_coin.denom.clone())?; if !found { @@ -597,25 +635,37 @@ pub fn bribe_proposal( val: String::from("Asset not whitelisted on chain"), }); } - let mut existing_bribes = - BRIBES_BY_PROPOSAL.load(deps.storage, (proposal_id, extended_pair))?; - let mut found = false; - for mut coin in existing_bribes.clone() { - if bribe_coin.denom == coin.denom { - coin.amount += bribe_coin.amount; - found = true; - } + + // UPDATE BRIBE FOR PROPOSAL (IF EXISTS THEN UPDATE ELSE APPEND) + let mut existing_bribes = match BRIBES_BY_PROPOSAL.may_load(deps.storage, (proposal_id, extended_pair))? + { + Some(record) => record, + None => vec![], + }; + + if existing_bribes.len()>=1{ + let mut found = false; + for coin1 in existing_bribes.iter_mut() { + if bribe_coin.denom == coin1.denom { + coin1.amount += bribe_coin.amount; + found = true; + } + } + if !found { + existing_bribes.push(bribe_coin.clone()); } - if !found { - existing_bribes.push(bribe_coin); } - + else{ + existing_bribes=vec![bribe_coin]; + } + BRIBES_BY_PROPOSAL.save(deps.storage, (proposal_id, extended_pair), &existing_bribes)?; - Ok(Response::new().add_attribute("method", "bribe")) + Ok(Response::new() + .add_attribute("method", "bribe")) } pub fn claim_rewards( - mut deps: DepsMut, + deps: DepsMut, env: Env, info: MessageInfo, app_id: u64, @@ -626,17 +676,14 @@ pub fn claim_rewards( .load(deps.storage, (app_id, info.sender.clone())) .unwrap_or_default(); - let all_proposals = COMPLETEDPROPOSALS.load(deps.storage, app_id)?; - calculate_rebase_reward( - deps.branch(), - env.clone(), - info.clone(), - max_proposal_claimed, - all_proposals.clone(), - app_id, - )?; + let all_proposals = match COMPLETEDPROPOSALS.may_load(deps.storage, app_id)? + { + Some(val)=>val , + None => vec![], - let bribe_coins = calculate_bribe_reward( + }; + + let mut bribe_coins = calculate_bribe_reward( deps.as_ref(), env.clone(), info.clone(), @@ -644,7 +691,9 @@ pub fn claim_rewards( all_proposals.clone(), app_id, )?; - let surplus_share = calculate_surplus_reward( + + let mut back_messages:Vec=vec![]; + let surplus_share = calculate_surplus_reward( deps.as_ref(), env.clone(), info.clone(), @@ -653,21 +702,42 @@ pub fn claim_rewards( app_id, )?; + if bribe_coins.len()!=0{ + let bribe=BankMsg::Send { + to_address: info.sender.to_string(), + amount: bribe_coins.clone(), + }; + back_messages.push(bribe); + } + + if !surplus_share.amount.is_zero(){ + for coin1 in bribe_coins.iter_mut() { + if surplus_share.denom == coin1.denom { + coin1.amount += surplus_share.amount; + } + } + } + MAXPROPOSALCLAIMED.save( deps.storage, (app_id, info.sender.clone()), all_proposals.last().unwrap(), )?; + + if back_messages.len()!=0{ Ok(Response::new() - .add_attribute("method", "voted for proposal") - .add_message(BankMsg::Send { + .add_attribute("method", "Bribe Claimed") + .add_message( BankMsg::Send { to_address: info.sender.to_string(), - amount: bribe_coins, - }) - .add_message(BankMsg::Send { - to_address: info.sender.to_string(), - amount: vec![surplus_share], - })) + amount: bribe_coins + }))} + + else { + return Err(ContractError::CustomError { + val: String::from("No rewards to claim."), + }); + } + } pub fn calculate_bribe_reward( @@ -678,19 +748,19 @@ pub fn calculate_bribe_reward( all_proposals: Vec, _app_id: u64, ) -> Result, ContractError> { - //check if active proposal let mut bribe_coins: Vec = vec![]; for proposalid in all_proposals.clone() { if proposalid <= max_proposal_claimed { continue; } - let vote = VOTERSPROPOSAL.load(deps.storage, (info.sender.clone(), proposalid))?; + let vote = match VOTERSPROPOSAL.may_load(deps.storage, (info.sender.clone(), proposalid))? + { + Some(val) => val, + None => continue + }; + let proposal1 = PROPOSAL.load(deps.storage, proposalid)?; - if vote.bribe_claimed { - return Err(ContractError::CustomError { - val: "Bribe Already Claimed".to_string(), - }); - } + let total_vote_weight = PROPOSALVOTE .load(deps.storage, (proposal1.app_id, vote.extended_pair))? .u128(); @@ -707,20 +777,21 @@ pub fn calculate_bribe_reward( }; claimable_bribe.push(claimable_coin); } - for bribr_deposited in claimable_bribe.clone() { + for bribe_deposited in claimable_bribe.clone() { match bribe_coins .iter_mut() - .find(|ref p| bribr_deposited.denom == p.denom) + .find(|ref p| bribe_deposited.denom == p.denom) { Some(pivot) => { - pivot.denom = bribr_deposited.denom; - pivot.amount += bribr_deposited.amount; + pivot.denom = bribe_deposited.denom; + pivot.amount += bribe_deposited.amount; } None => { - bribe_coins.push(bribr_deposited); + bribe_coins.push(bribe_deposited); } } } + } //// send bank message to band @@ -731,25 +802,35 @@ pub fn calculate_bribe_reward( pub fn calculate_rebase_reward( mut deps: DepsMut, env: Env, - info: MessageInfo, - max_proposal_claimed: u64, - all_proposals: Vec, - app_id: u64, -) -> Result<(), ContractError> { - let mut total_rebase_amount: u128 = 0; - for proposalid in all_proposals.clone() { - if proposalid <= max_proposal_claimed { - continue; - } - let proposal = PROPOSAL.load(deps.storage, proposalid)?; - total_rebase_amount += proposal.rebase_distributed; + _info: MessageInfo, + proposal_id: u64, + app_id :u64, +) -> Result, ContractError> { + + let mut proposal = PROPOSAL.load(deps.storage, proposal_id)?; + + if proposal.rebase_completed{ + return Err(ContractError::CustomError { + val: String::from("Rebase already completed"), + }); } + let total_rebase_amount: u128 = proposal.rebase_distributed; let app_response = query_app_exists(deps.as_ref(), app_id)?; + let gov_token_denom = query_get_asset_data(deps.as_ref(), app_response.gov_token_id)?; - let vtokens = VTOKENS.load(deps.storage, (info.sender.clone(), &gov_token_denom))?; + + let vtokenholders=LOCKINGADDRESS.load(deps.storage, app_id)?; + + for addr in vtokenholders.iter(){ + let vtokens = match VTOKENS.may_load(deps.storage, (addr.to_owned(), &gov_token_denom))? + { + Some(val)=>val , + None => vec![], + + }; let supply = SUPPLY.load(deps.storage, &gov_token_denom)?; - let total_locked: u128 = supply.vtoken; + let total_locked: u128 = supply.token; //// get rebase amount per period let mut locked_t1: u128 = 0; let mut locked_t2: u128 = 0; @@ -758,10 +839,10 @@ pub fn calculate_rebase_reward( for vtoken in vtokens.clone() { match vtoken.period { - LockingPeriod::T1 => locked_t1 += vtoken.vtoken.amount.u128(), - LockingPeriod::T2 => locked_t2 += vtoken.vtoken.amount.u128(), - LockingPeriod::T3 => locked_t3 += vtoken.vtoken.amount.u128(), - LockingPeriod::T4 => locked_t4 += vtoken.vtoken.amount.u128(), + LockingPeriod::T1 => locked_t1 += vtoken.token.amount.u128(), + LockingPeriod::T2 => locked_t2 += vtoken.token.amount.u128(), + LockingPeriod::T3 => locked_t3 += vtoken.token.amount.u128(), + LockingPeriod::T4 => locked_t4 += vtoken.token.amount.u128(), } } @@ -777,7 +858,7 @@ pub fn calculate_rebase_reward( deps.branch(), env.clone(), app_id, - info.sender.clone(), + addr.clone(), fund_t1, LockingPeriod::T1, )?; @@ -791,7 +872,7 @@ pub fn calculate_rebase_reward( deps.branch(), env.clone(), app_id, - info.sender.clone(), + addr.clone(), fund_t2, LockingPeriod::T2, )?; @@ -805,7 +886,7 @@ pub fn calculate_rebase_reward( deps.branch(), env.clone(), app_id, - info.sender.clone(), + addr.clone(), fund_t3, LockingPeriod::T3, )?; @@ -819,12 +900,17 @@ pub fn calculate_rebase_reward( deps.branch(), env.clone(), app_id, - info.sender.clone(), + addr.clone(), fund_t4, LockingPeriod::T4, )?; + } - Ok(()) + proposal.rebase_completed=true; + PROPOSAL.save(deps.storage, proposal_id , &proposal)?; + + Ok(Response::new() + .add_attribute("method", "rebase all holders")) } pub fn calculate_surplus_reward( @@ -850,20 +936,28 @@ pub fn calculate_surplus_reward( let app_response = query_app_exists(deps, app_id)?; let gov_token_denom = query_get_asset_data(deps, app_response.gov_token_id)?; - let vtokens = VTOKENS.load(deps.storage, (info.sender.clone(), &gov_token_denom))?; + let vtokens = VTOKENS.may_load(deps.storage, (info.sender.clone(), &gov_token_denom))?; + if vtokens.is_none() + { + let claim_coin=Coin { + amount: Uint128::zero(), + denom: gov_token_denom, + }; + return Ok(claim_coin); + } let supply = SUPPLY.load(deps.storage, &gov_token_denom)?; let total_locked: u128 = supply.vtoken; //// get rebase amount per period let mut locked: u128 = 0; - + let vtokens=vtokens.unwrap(); for vtoken in vtokens.clone() { locked += vtoken.vtoken.amount.u128(); } - - let share = locked.div(total_locked); + let mut share = locked.div(total_locked); + share=share*total_surplus_available.amount.u128(); let claim_coin = Coin { amount: Uint128::from(share), - denom: gov_token_denom, + denom: total_surplus_available.denom, }; Ok(claim_coin) @@ -878,7 +972,13 @@ pub fn emission( // check if already emission executed //check if active proposal let mut proposal = PROPOSAL.load(deps.storage, proposal_id)?; - if proposal.voting_end_time > env.block.time.seconds() { + if proposal.emission_completed{ + return Err(ContractError::CustomError { + val: "Emission already completed" + .to_string(), + }); + } + if proposal.voting_end_time > env.block.time{ return Err(ContractError::CustomError { val: "Proposal Voting Period not ended to execute emission for the proposal" .to_string(), @@ -934,22 +1034,27 @@ pub fn emission( // mint and distribue to vault owner based vote portion let ext_pair = proposal.extended_pair.clone(); let mut votes: Vec = vec![]; + let mut total_vote: Uint128 =Uint128::zero(); for i in 0..ext_pair.len() { let vote = PROPOSALVOTE .load(deps.storage, (app_id, ext_pair[i])) - .unwrap_or_default(); + .unwrap_or(Uint128::from(0 as u32)); votes.push(vote); + total_vote+=vote; } //// UPDATE Foundation Nodes Share proposal.foundation_distributed = (state.foundation_percentage.mul(effective_emission)).u128(); //// Update proposal Emission State proposal.emission_completed = true; - proposal.emission_distributed = effective_emission.u128(); + //// effective emission + proposal.emission_distributed = effective_emission.u128()-(state.foundation_percentage.mul(effective_emission)).u128(); + // update effective emission + //// UPDATE REBASE AMOUNT proposal.rebase_distributed = (reward_emision.mul(percentage_locked)).u128(); - + //proposal.rebase_completed=true; //// EMISSION Data Update emission.rewards_pending -= effective_emission.u128(); emission.distributed_rewards += effective_emission.u128(); @@ -961,29 +1066,38 @@ pub fn emission( let mut msg: Vec = vec![]; let emission_msg = ComdexMessages::MsgEmissionRewards { app_id: app_id, - emission_amount: effective_emission.u128(), + amount: effective_emission, extended_pair: proposal.extended_pair, voting_ratio: votes, }; let rebase_msg = ComdexMessages::MsgRebaseMint { app_id: app_id, - amount: proposal.rebase_distributed, - contract_addr: env.contract.address.clone(), + amount: Uint128::from(proposal.rebase_distributed), + contract_addr: env.contract.address.to_string(), }; let surplus_msg = ComdexMessages::MsgGetSurplusFund { app_id: app_id, asset_id: state.surplus_asset_id, - contract_addr: env.contract.address, + contract_addr: env.contract.address.into_string(), amount: surplus.clone(), }; + + if total_vote!=Uint128::zero(){ msg.push(emission_msg); + } msg.push(rebase_msg); if surplus.amount != Uint128::new(0) { msg.push(surplus_msg); } - let mut all_proposals = COMPLETEDPROPOSALS.load(deps.storage, app_id)?; + let mut all_proposals = match COMPLETEDPROPOSALS.may_load(deps.storage, app_id)? + { + Some(val) => val, + None =>vec![], + + }; + all_proposals.push(proposal_id); COMPLETEDPROPOSALS.save(deps.storage, app_id, &all_proposals)?; Ok(Response::new() @@ -999,31 +1113,38 @@ pub fn vote_proposal( proposal_id: u64, extended_pair: u64, ) -> Result, ContractError> { - //// check if already voted for proposal - let has_voted = VOTERS_VOTE - .load(deps.storage, (info.sender.clone(), proposal_id)) - .unwrap_or_default(); - if has_voted { - return Err(ContractError::CustomError { - val: "Already voted for the proposal".to_string(), - }); - } - //check if active proposal + //check if active proposal let mut proposal = PROPOSAL.load(deps.storage, proposal_id)?; - // Check if proposal in voting period - if proposal.voting_end_time < env.block.time.seconds() { + // Check if proposal in voting period + if proposal.voting_end_time < env.block.time { return Err(ContractError::CustomError { val: "Proposal Voting Period Ended".to_string(), }); } + //// check if already voted for proposal + let has_voted = VOTERS_VOTE.may_load(deps.storage, (info.sender.clone(), proposal_id))?.unwrap_or_default(); + + + + //// get App Data let app_response = query_app_exists(deps.as_ref(), app_id)?; - let extended_pairs = proposal.extended_pair.clone(); + //// get gov token denom for app + let gov_token_denom = query_get_asset_data(deps.as_ref(), app_response.gov_token_id)?; + + if gov_token_denom.is_empty() || app_response.gov_token_id == 0 { + return Err(ContractError::CustomError { + val: "Gov token not found for the app".to_string(), + }); + } // check if ext_pair param exist in extended pair list to vote for + let extended_pairs = proposal.extended_pair.clone(); + + match extended_pairs.binary_search(&extended_pair) { Ok(_) => (), Err(_) => { @@ -1035,15 +1156,16 @@ pub fn vote_proposal( //balance of owner for the for denom for voting - let gov_token_denom = query_get_asset_data(deps.as_ref(), app_response.gov_token_id)?; + let vtokens = VTOKENS.may_load(deps.storage, (info.sender.clone(), &gov_token_denom))?; - if gov_token_denom.is_empty() || app_response.gov_token_id == 0 { + if vtokens.is_none() + { return Err(ContractError::CustomError { - val: "Gov token not found for the app".to_string(), + val: "No tokens locked to perform voting on proposals".to_string(), }); } - let vtokens = VTOKENS.load(deps.storage, (info.sender.clone(), &gov_token_denom))?; - + + let vtokens =vtokens.unwrap(); // calculate voting power for the the proposal let mut vote_power: u128 = 0; @@ -1052,27 +1174,98 @@ pub fn vote_proposal( vote_power += vtoken.vtoken.amount.u128(); } + // Update proposal Vote for an app - let proposal_vote = PROPOSALVOTE + let mut proposal_vote = PROPOSALVOTE .load(deps.storage, (proposal_id, extended_pair)) .unwrap_or_default(); + // if already voted , update voting stats + if has_voted{ + let prev_vote=VOTERSPROPOSAL.load(deps.storage, (info.sender.clone(),proposal_id))?; + let last_vote_weight=prev_vote.vote_weight; + let last_voted_pair=prev_vote.extended_pair; + if last_voted_pair==extended_pair + { + proposal_vote=proposal_vote-Uint128::from(last_vote_weight); + proposal.total_voted_weight-=last_vote_weight; + proposal_vote=proposal_vote+Uint128::from(vote_power); + proposal.total_voted_weight+=vote_power; + PROPOSALVOTE.save( + deps.storage, + (proposal_id, extended_pair), + &proposal_vote, + )?; + PROPOSAL.save(deps.storage, proposal_id, &proposal)?; + let vote = Vote { + app_id: app_id, + extended_pair: extended_pair, + vote_weight: vote_power, + }; + + VOTERSPROPOSAL.save(deps.storage, (info.sender.clone(), proposal_id), &vote)?; + + } + else { + let mut prev_proposal_vote=PROPOSALVOTE + .load(deps.storage, (proposal_id, last_voted_pair)) + .unwrap_or_default(); + + prev_proposal_vote=prev_proposal_vote-Uint128::from(last_vote_weight); + proposal_vote=proposal_vote+Uint128::from(vote_power); + PROPOSALVOTE.save( + deps.storage, + (proposal_id, extended_pair), + &proposal_vote, + )?; + PROPOSALVOTE.save( + deps.storage, + (proposal_id, last_voted_pair), + &prev_proposal_vote, + )?; + + proposal.total_voted_weight-=last_vote_weight; + proposal.total_voted_weight+=vote_power; + PROPOSAL.save(deps.storage, proposal_id, &proposal)?; + + let vote = Vote { + app_id: app_id, + extended_pair: extended_pair, + vote_weight: vote_power, + }; + + VOTERSPROPOSAL.save(deps.storage, (info.sender.clone(), proposal_id), &vote)?; + + + } + + } + +else { + let updated_vote=Uint128::from(vote_power)+ proposal_vote; PROPOSALVOTE.save( deps.storage, (proposal_id, extended_pair), - &(Uint128::from(vote_power) + proposal_vote), + &updated_vote, )?; - // update proposal - PROPOSAL.save(deps.storage, proposal_id, &proposal)?; let vote = Vote { app_id: app_id, extended_pair: extended_pair, vote_weight: vote_power, - bribe_claimed: false, }; - VOTERSPROPOSAL.save(deps.storage, (info.sender, proposal_id), &vote)?; + + VOTERSPROPOSAL.save(deps.storage, (info.sender.clone(), proposal_id), &vote)?; + PROPOSAL.save(deps.storage, proposal_id, &proposal)?; + + } + + + VOTERS_VOTE.save(deps.storage, (info.sender.clone(), proposal_id),&true)?; + + // update proposal + Ok(Response::new().add_attribute("method", "voted for proposal")) } @@ -1085,9 +1278,9 @@ pub fn raise_proposal( ) -> Result, ContractError> { //check if app exist query_app_exists(deps.as_ref(), app_id)?; - //get ext pairs vec from app + ////get ext pairs vec from app let ext_pairs = query_extended_pair_by_app(deps.as_ref(), app_id)?; - + //check no proposal active for app let current_app_proposal = match APPCURRENTPROPOSAL.may_load(deps.storage, app_id)? { Some(val) => val, @@ -1098,7 +1291,7 @@ pub fn raise_proposal( // proposal cannot be raised until current proposal voting time is ended if current_app_proposal != 0 { let proposal = PROPOSAL.load(deps.storage, current_app_proposal)?; - if proposal.voting_end_time > env.block.time.seconds() { + if proposal.voting_end_time > env.block.time { return Err(ContractError::CustomError { val: "Previous proposal in voting state for the app".to_string(), }); @@ -1106,12 +1299,14 @@ pub fn raise_proposal( } // set proposal data - let voting_period = VOTINGPERIOD.load(deps.storage).unwrap_or_default(); + let state = STATE.load(deps.storage)?; + let voting_period = state.voting_period; + //update proposal maps let proposal = Proposal { app_id: app_id, - voting_start_time: env.block.time.seconds(), - voting_end_time: env.block.time.seconds() + voting_period, + voting_start_time: env.block.time, + voting_end_time: env.block.time.plus_seconds(voting_period), extended_pair: ext_pairs, emission_completed: false, rebase_completed: false, @@ -1126,11 +1321,13 @@ pub fn raise_proposal( }, height: env.block.height, }; - let current_proposal = PROPOSALCOUNT.load(deps.storage).unwrap_or_default(); - PROPOSALCOUNT.save(deps.storage, &(current_proposal + 1))?; - APPCURRENTPROPOSAL.save(deps.storage, app_id, &(current_proposal + 1))?; - PROPOSAL.save(deps.storage, current_proposal + 1, &proposal)?; - Ok(Response::new().add_attribute("method", "reset")) + let mut current_proposal = PROPOSALCOUNT.load(deps.storage).unwrap_or(0); + current_proposal+=1; + PROPOSALCOUNT.save(deps.storage, ¤t_proposal)?; + APPCURRENTPROPOSAL.save(deps.storage, app_id, ¤t_proposal)?; + PROPOSAL.save(deps.storage, current_proposal , &proposal)?; + Ok(Response::new().add_attribute("method", "proposal_raise") + .add_attribute("proposal_id",current_proposal.to_string())) } #[entry_point] @@ -1141,7 +1338,7 @@ pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result= CONTRACT_VERSION.to_string() { + if ver.version > CONTRACT_VERSION.to_string() { return Err(StdError::generic_err("Cannot upgrade from a newer version").into()); } @@ -1153,11 +1350,48 @@ pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result Result { + match msg { + SudoMsg::UpdateVestingContract { address } => { + let mut state = STATE.load(deps.storage)?; + state.vesting_contract=address; + STATE.save(deps.storage,&state)?; + Ok(Response::new()) + } + SudoMsg::UpdateEmissionRate { emission }=>{ + + EMISSION.save(deps.storage, emission.app_id, &emission)?; + Ok(Response::new()) + } + SudoMsg::UpdateFoundationInfo{addresses,foundation_percentage}=> + { + let mut state = STATE.load(deps.storage)?; + state.foundation_addr=addresses.iter().map(|e| e.to_string()).collect(); + state.foundation_percentage=foundation_percentage; + STATE.save(deps.storage,&state)?; + Ok(Response::new()) + }, + SudoMsg::UpdateLockingPeriod{t1,t2,t3,t4}=> + { + let mut state = STATE.load(deps.storage)?; + state.t1=t1; + state.t2=t2; + state.t2=t3; + state.t2=t4; + STATE.save(deps.storage,&state)?; + Ok(Response::new()) + } +} +} + #[cfg(test)] mod tests { use std::marker::PhantomData; use super::*; + use crate::state::Emission; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; use cosmwasm_std::{coin, coins, Addr, CosmosMsg, OwnedDeps, StdError}; @@ -1166,7 +1400,6 @@ mod tests { /// Returns default InstantiateMsg with each value in seconds. /// - t1 is 1 week (7*24*60*60), similarly, t2 is 2 weeks, t3 is 3 weeks /// and t4 is 4 weeks. - /// - unlock_period is 1 week fn init_msg() -> InstantiateMsg { InstantiateMsg { t1: PeriodWeight { @@ -1187,7 +1420,7 @@ mod tests { }, voting_period: 604_800, vesting_contract: Addr::unchecked("vesting_contract"), - foundation_addr: vec![Addr::unchecked("vesting_contract")], + foundation_addr: vec![], foundation_percentage: Decimal::new(Uint128::from(2 as u32)), surplus_asset_id: 3, emission: Emission { @@ -1519,20 +1752,14 @@ mod tests { let owner = Addr::unchecked("owner"); let info = mock_info("owner", &coins(100, DENOM.to_string())); - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()).unwrap(); + let _res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()).unwrap(); env.block.time = env.block.time.plus_seconds(imsg.t1.period + 1u64); // Withdrawing 10 Tokens let info = mock_info("owner", &[]); - let res = handle_withdraw( - deps.as_mut(), - env.clone(), - info.clone(), - DENOM.to_string(), - LockingPeriod::T1, - ) - .unwrap(); + let res = + handle_withdraw(deps.as_mut(), env.clone(), info.clone(), DENOM.to_string()).unwrap(); assert_eq!(res.messages.len(), 1); assert_eq!(res.attributes.len(), 2); assert_eq!( @@ -1549,7 +1776,7 @@ mod tests { assert_eq!(vtoken_balance1, vtoken_balance2); // Check correct update in VTOKENS - let vtoken = VTOKENS + let _vtoken = VTOKENS .load(&deps.storage, (info.sender.clone(), DENOM)) .unwrap_err(); // assert_eq!(vtoken.len(), 1); @@ -1572,14 +1799,8 @@ mod tests { let env = mock_env(); let info = mock_info("sender", &[]); - let res = handle_withdraw( - deps.as_mut(), - env.clone(), - info.clone(), - DENOM.to_string(), - LockingPeriod::T1, - ) - .unwrap_err(); + let res = handle_withdraw(deps.as_mut(), env.clone(), info.clone(), DENOM.to_string()) + .unwrap_err(); match res { ContractError::NotFound { .. } => {} e => panic!("{:?}", e), @@ -1601,22 +1822,12 @@ mod tests { locking_period: LockingPeriod::T1, }; - let owner = Addr::unchecked("owner"); - let info = mock_info("owner", &coins(100, DENOM.to_string())); - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()).unwrap(); + let _owner = Addr::unchecked("owner"); + let _info = mock_info("owner", &coins(100, DENOM.to_string())); + let _res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()).unwrap(); - let res = handle_withdraw( - deps.as_mut(), - env.clone(), - info.clone(), - DENOM.to_string(), - LockingPeriod::T1, - ) - .unwrap_err(); - // match res { - // ContractError::NotUnlocked { .. } => {} - // e => panic!("{:?}", e), - // }; + let _res = handle_withdraw(deps.as_mut(), env.clone(), info.clone(), DENOM.to_string()) + .unwrap_err(); } #[test] @@ -1634,19 +1845,13 @@ mod tests { locking_period: LockingPeriod::T1, }; - let owner = Addr::unchecked("owner"); + let _owner = Addr::unchecked("owner"); let info = mock_info("owner", &coins(100, DENOM.to_string())); - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()).unwrap(); + let _res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()).unwrap(); let info = mock_info("owner", &[]); - let res = handle_withdraw( - deps.as_mut(), - env.clone(), - info.clone(), - DENOM.to_string(), - LockingPeriod::T1, - ) - .unwrap_err(); + let res = handle_withdraw(deps.as_mut(), env.clone(), info.clone(), DENOM.to_string()) + .unwrap_err(); match res { ContractError::NotFound { .. } => {} e => panic!("{:?}", e), @@ -1668,19 +1873,13 @@ mod tests { locking_period: LockingPeriod::T1, }; - let owner = Addr::unchecked("owner"); + let _owner = Addr::unchecked("owner"); let info = mock_info("owner", &coins(100, DENOM.to_string())); - let res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()).unwrap(); + let _res = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone()).unwrap(); let info = mock_info("owner", &[]); - let res = handle_withdraw( - deps.as_mut(), - env.clone(), - info.clone(), - "DNM1".to_string(), - LockingPeriod::T1, - ) - .unwrap_err(); + let res = handle_withdraw(deps.as_mut(), env.clone(), info.clone(), "DNM1".to_string()) + .unwrap_err(); match res { ContractError::NotFound { .. } => {} e => panic!("{:?}", e), diff --git a/src/integration_tests.rs b/src/integration_tests.rs deleted file mode 100644 index bbe2737..0000000 --- a/src/integration_tests.rs +++ /dev/null @@ -1,71 +0,0 @@ -// #[cfg(test)] -// mod tests { -// use crate::helpers::CwTemplateContract; -// use crate::msg::InstantiateMsg; -// use cosmwasm_std::{Addr, Coin, Empty, Uint128}; -// use cw_multi_test::{App, AppBuilder, Contract, ContractWrapper, Executor}; - -// pub fn contract_template() -> Box> { -// let contract = ContractWrapper::new( -// crate::contract::execute, -// crate::contract::instantiate, -// crate::contract::query, -// ); -// Box::new(contract) -// } - -// const USER: &str = "USER"; -// const ADMIN: &str = "ADMIN"; -// const NATIVE_DENOM: &str = "denom"; - -// fn mock_app() -> App { -// AppBuilder::new().build(|router, _, storage| { -// router -// .bank -// .init_balance( -// storage, -// &Addr::unchecked(USER), -// vec![Coin { -// denom: NATIVE_DENOM.to_string(), -// amount: Uint128::new(1), -// }], -// ) -// .unwrap(); -// }) -// } - -// fn proper_instantiate() -> (App, CwTemplateContract) { -// let mut app = mock_app(); -// let cw_template_id = app.store_code(contract_template()); - -// let msg = InstantiateMsg { count: 1i32 }; -// let cw_template_contract_addr = app -// .instantiate_contract( -// cw_template_id, -// Addr::unchecked(ADMIN), -// &msg, -// &[], -// "test", -// None, -// ) -// .unwrap(); - -// let cw_template_contract = CwTemplateContract(cw_template_contract_addr); - -// (app, cw_template_contract) -// } - -// mod count { -// use super::*; -// use crate::msg::ExecuteMsg; - -// #[test] -// fn count() { -// let (mut app, cw_template_contract) = proper_instantiate(); - -// let msg = ExecuteMsg::Increment {}; -// let cosmos_msg = cw_template_contract.call(msg).unwrap(); -// app.execute(Addr::unchecked(USER), cosmos_msg).unwrap(); -// } -// } -// } diff --git a/src/lib.rs b/src/lib.rs index f7360d2..e1d7755 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ pub mod contract; mod error; pub mod helpers; -pub mod integration_tests; pub mod msg; pub mod query; pub mod state; diff --git a/src/msg.rs b/src/msg.rs index ba99f8d..f57931a 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -11,7 +11,7 @@ pub struct InstantiateMsg { pub t4: PeriodWeight, pub voting_period: u64, pub vesting_contract: Addr, - pub foundation_addr: Vec, + pub foundation_addr: Vec, pub foundation_percentage: Decimal, pub surplus_asset_id: u64, pub emission: Emission, @@ -40,6 +40,7 @@ pub enum ExecuteMsg { }, Rebase { proposal_id: u64, + app_id: u64, }, Lock { app_id: u64, @@ -47,7 +48,6 @@ pub enum ExecuteMsg { }, Withdraw { denom: String, - lockingperiod: LockingPeriod, }, Transfer { recipent: String, @@ -71,6 +71,8 @@ pub enum QueryMsg { IssuedVtokens { address: Addr, denom: String, + start_after: u32, + limit: Option, }, VestedTokens { denom: String, @@ -87,7 +89,7 @@ pub enum QueryMsg { }, BribeByProposal { proposal_id: u64, - app_id: u64, + extended_pair_id: u64, }, HasVoted { address: Addr, @@ -108,6 +110,27 @@ pub enum QueryMsg { address: String, denom: String, }, + TotalVTokens { + address: Addr, + denom: String, + }, + State {}, + Emission { + app_id: u64, + }, + ExtendedPairVote { + proposal_id: u64, + extended_pair_id: u64, + }, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum SudoMsg { + UpdateVestingContract { address: Addr }, + UpdateEmissionRate{emission:Emission}, + UpdateFoundationInfo{addresses: Vec,foundation_percentage:Decimal}, + UpdateLockingPeriod{t1:PeriodWeight,t2:PeriodWeight,t3:PeriodWeight,t4:PeriodWeight}, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] diff --git a/src/query.rs b/src/query.rs index 55866c6..accbc90 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,60 +1,118 @@ -// !------- IssuedVtokens query not implemented-------! - use std::borrow::Borrow; +use crate::error::ContractError; +use crate::msg::{IssuedNftResponse, QueryMsg, WithdrawableResponse}; +use crate::state::{ + Emission, Proposal, State, TokenSupply, Vote, Vtoken, APPCURRENTPROPOSAL, BRIBES_BY_PROPOSAL, + COMPLETEDPROPOSALS, EMISSION, MAXPROPOSALCLAIMED, PROPOSAL, PROPOSALVOTE, STATE, SUPPLY, + TOKENS, VOTERSPROPOSAL, VOTERS_VOTE, VTOKENS, +}; use comdex_bindings::ComdexQuery; use cosmwasm_std::{ - entry_point, to_binary, Addr, Binary, Coin, Deps, Env, MessageInfo, StdError, StdResult, - Uint128 + entry_point, to_binary, Addr, Binary, Coin, Deps, Env, StdError, StdResult, Uint128, }; -use crate::error::ContractError; -use crate::contract::calculate_bribe_reward; -use crate::msg::{IssuedNftResponse, IssuedVtokensResponse, QueryMsg, WithdrawableResponse}; -use crate::state::{ - Proposal, State, TokenSupply, Vote, Vtoken, APPCURRENTPROPOSAL, BRIBES_BY_PROPOSAL, - COMPLETEDPROPOSALS, MAXPROPOSALCLAIMED, PROPOSAL, STATE, SUPPLY, TOKENS, VOTERSPROPOSAL, - VOTERS_VOTE, VTOKENS,PROPOSALVOTE -}; +const MAX_LIMIT: u32 = 30; +const DEFAULT_LIMIT: u32 = 10; #[cfg_attr(not(feature = "library"), entry_point)] pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { match msg { QueryMsg::IssuedNft { address } => to_binary(&query_issued_nft(deps, env, address)?), - - QueryMsg::IssuedVtokens { address, denom } => { - to_binary(&query_issued_vtokens(deps, env, address, denom)?) - } - + QueryMsg::IssuedVtokens { + address, + denom, + start_after, + limit, + } => to_binary(&query_issued_vtokens( + deps, + env, + address, + denom, + start_after, + limit, + )?), QueryMsg::Supply { denom } => to_binary(&query_issued_supply(deps, env, denom)?), - QueryMsg::CurrentProposal { app_id } => { to_binary(&query_current_proposal(deps, env, app_id)?) } - QueryMsg::Proposal { proposal_id } => to_binary(&query_proposal(deps, env, proposal_id)?), - QueryMsg::BribeByProposal { proposal_id, - app_id, - } => to_binary(&query_bribe(deps, env, app_id, proposal_id)?), - + extended_pair_id, + } => to_binary(&query_bribe(deps, env, proposal_id, extended_pair_id)?), QueryMsg::Vote { proposal_id, address, } => to_binary(&query_vote(deps, env, address, proposal_id)?), - QueryMsg::ClaimableBribe { address, app_id } => { to_binary(&query_bribe_eligible(deps, env, address, app_id)?) } QueryMsg::Withdrawable { address, denom } => { to_binary(&query_withdrawable(deps, env, address, denom)?) } - + QueryMsg::TotalVTokens { address, denom } => { + to_binary(&query_vtoken_balance(deps, env, address, denom)?) + } + QueryMsg::State {} => to_binary(&query_state(deps, env)?), + QueryMsg::Emission { app_id } => to_binary(&query_emission(deps, env, app_id)?), + QueryMsg::ExtendedPairVote { + proposal_id, + extended_pair_id, + } => to_binary(&query_extendedpairvote( + deps, + env, + proposal_id, + extended_pair_id, + )?), + QueryMsg::HasVoted { + address, + proposal_id, + } => to_binary(&query_is_voted(deps, env, address, proposal_id)?), _ => panic!("Not implemented"), } } +pub fn query_emission( + deps: Deps, + _env: Env, + proposal_id: u64, +) -> StdResult> { + let supply = EMISSION.may_load(deps.storage, proposal_id)?; + Ok(supply) +} + +pub fn query_extendedpairvote( + deps: Deps, + _env: Env, + proposal_id: u64, + extended_pair_id: u64, +) -> StdResult> { + let supply = PROPOSALVOTE.may_load(deps.storage, (proposal_id, extended_pair_id))?; + + Ok(supply) +} + +pub fn query_vtoken_balance( + deps: Deps, + _env: Env, + address: Addr, + denom: String, +) -> StdResult { + let vtokens = VTOKENS.may_load(deps.storage, (address, &denom))?; + if vtokens.is_none() { + return Ok(Uint128::zero()); + } + + let vtokens = vtokens.unwrap(); + let mut total_vtoken: u128 = 0; + for vtoken in vtokens.clone() { + total_vtoken += vtoken.vtoken.amount.u128(); + } + + Ok(Uint128::from(total_vtoken)) +} + pub fn query_state(deps: Deps, _env: Env) -> StdResult { let state = STATE.may_load(deps.storage)?; match state { @@ -86,9 +144,27 @@ pub fn query_issued_vtokens( _env: Env, address: Addr, denom: String, + start_after: u32, + limit: Option, ) -> StdResult> { + let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; + let start = start_after as usize; + let checkpoint = start + limit; + let state = match VTOKENS.may_load(deps.storage, (address, &denom))? { - Some(val) => val, + Some(val) => { + // If the vec len is smaller than start_after, then empty vec + // If the checkpoint is >= length, then return all remaining elements + // else return the specific elements + let length = val.len(); + if length <= start { + vec![] + } else if checkpoint >= length { + val[start..].to_vec() + } else { + val[start..checkpoint].to_vec() + } + } None => vec![], }; @@ -99,29 +175,33 @@ pub fn query_issued_supply( deps: Deps, _env: Env, denom: String, -) -> StdResult { +) -> StdResult> { let supply = SUPPLY.may_load(deps.storage, &denom)?; - Ok(supply.unwrap()) + Ok(supply) } pub fn query_current_proposal(deps: Deps, _env: Env, app_id: u64) -> StdResult { let supply = APPCURRENTPROPOSAL.may_load(deps.storage, app_id)?; - Ok(supply.unwrap_or_default()) + Ok(supply.unwrap_or(0)) } -pub fn query_proposal(deps: Deps, _env: Env, proposal_id: u64) -> StdResult { +pub fn query_proposal( + deps: Deps, + _env: Env, + proposal_id: u64, +) -> StdResult> { let supply = PROPOSAL.may_load(deps.storage, proposal_id)?; - Ok(supply.unwrap()) + Ok(supply) } pub fn query_bribe( deps: Deps, _env: Env, - app_id: u64, proposal_id: u64, -) -> StdResult> { - let supply = BRIBES_BY_PROPOSAL.may_load(deps.storage, (app_id, proposal_id))?; - Ok(supply.unwrap()) + extended_pair_id: u64, +) -> StdResult>> { + let supply = BRIBES_BY_PROPOSAL.may_load(deps.storage, (proposal_id, extended_pair_id))?; + Ok(supply) } pub fn query_is_voted( @@ -131,7 +211,7 @@ pub fn query_is_voted( proposal_id: u64, ) -> StdResult { let supply = VOTERS_VOTE.may_load(deps.storage, (address, proposal_id))?; - Ok(supply.unwrap()) + Ok(supply.unwrap_or(false)) } pub fn query_vote( @@ -139,9 +219,9 @@ pub fn query_vote( _env: Env, address: Addr, proposal_id: u64, -) -> StdResult { +) -> StdResult> { let supply = VOTERSPROPOSAL.may_load(deps.storage, (address, proposal_id))?; - Ok(supply.unwrap()) + Ok(supply) } pub fn query_withdrawable( @@ -185,7 +265,10 @@ pub fn query_bribe_eligible( .load(deps.storage, (app_id, address.clone())) .unwrap_or_default(); - let all_proposals = COMPLETEDPROPOSALS.load(deps.storage, app_id)?; + let all_proposals = match COMPLETEDPROPOSALS.may_load(deps.storage, app_id)? { + Some(val) => val, + None => vec![], + }; let bribe_coins = calculate_bribe_reward_query( deps, @@ -198,7 +281,6 @@ pub fn query_bribe_eligible( Ok(bribe_coins.unwrap_or_default()) } - pub fn calculate_bribe_reward_query( deps: Deps, _env: Env, @@ -213,18 +295,24 @@ pub fn calculate_bribe_reward_query( if proposalid <= max_proposal_claimed { continue; } - let vote = VOTERSPROPOSAL.load(deps.storage, (address.to_owned(), proposalid))?; - let proposal1 = PROPOSAL.load(deps.storage, proposalid)?; - if vote.bribe_claimed { - return Err(ContractError::CustomError { - val: "Bribe Already Claimed".to_string(), - }); - } + let vote = match VOTERSPROPOSAL.may_load(deps.storage, (address.to_owned(), proposalid))? { + Some(val) => val, + None => continue, + }; + let proposal1 = match PROPOSAL.may_load(deps.storage, proposalid)? { + Some(val) => val, + None => continue, + }; + let total_vote_weight = PROPOSALVOTE .load(deps.storage, (proposal1.app_id, vote.extended_pair))? .u128(); - let total_bribe = - BRIBES_BY_PROPOSAL.load(deps.storage, (proposal1.app_id, vote.extended_pair))?; + let total_bribe = match BRIBES_BY_PROPOSAL + .may_load(deps.storage, (proposal1.app_id, vote.extended_pair))? + { + Some(val) => val, + None => vec![], + }; let mut claimable_bribe: Vec = vec![]; @@ -257,12 +345,10 @@ pub fn calculate_bribe_reward_query( #[cfg(test)] mod tests { use super::*; - use crate::contract::{execute, instantiate}; - use crate::msg::{ExecuteMsg, InstantiateMsg}; - use crate::state::{LockingPeriod, PeriodWeight, Status}; + use crate::state::{LockingPeriod, Status}; use comdex_bindings::ComdexQuery; use cosmwasm_std::testing::{mock_env, mock_info, MockApi, MockQuerier, MockStorage}; - use cosmwasm_std::{coins, Decimal, OwnedDeps, Timestamp, Uint128}; + use cosmwasm_std::{OwnedDeps, Timestamp, Uint128}; use std::marker::PhantomData; const DENOM: &str = "TKN"; @@ -279,7 +365,7 @@ mod tests { #[test] fn withdrawable() { let mut deps = mock_dependencies(); - let mut env = mock_env(); + let env = mock_env(); let info = mock_info("sender", &[]); // Store some test vtokens @@ -313,7 +399,7 @@ mod tests { status: Status::Locked, }, ]; - VTOKENS.save(deps.as_mut().storage, (info.sender.clone(), DENOM), &data); + _ = VTOKENS.save(deps.as_mut().storage, (info.sender.clone(), DENOM), &data); // Query the withdrawable balance; should be 250 // let res = query_withdrawable(deps.as_ref(), env.clone(), DENOM.to_string()) diff --git a/src/state.rs b/src/state.rs index 6e15e73..0f8c75d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{Addr, Timestamp}; use cosmwasm_std::{Coin, Decimal, Uint128}; -use cw_storage_plus::{Item, Map }; +use cw_storage_plus::{Item, Map}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -20,8 +20,6 @@ pub enum LockingPeriod { T4, } - - #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum Status { @@ -49,17 +47,6 @@ pub struct Vtoken { pub status: Status, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum CallType { - /// Update only the amount in the Vtoken if another deposit for the same - /// locking period exists. - UpdateAmount, - /// Update amount and time period in the Vtoken, if another deposit for the - /// same locking period exists. - UpdatePeriod, -} - /// NFT struct for holding the token info #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -82,10 +69,10 @@ pub struct State { pub t4: PeriodWeight, pub num_tokens: u64, pub vesting_contract: Addr, - pub foundation_addr: Vec, + pub foundation_addr: Vec, pub foundation_percentage: Decimal, - pub voting_period:u64, - pub surplus_asset_id:u64, + pub voting_period: u64, + pub surplus_asset_id: u64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -107,23 +94,21 @@ pub const SUPPLY: Map<&str, TokenSupply> = Map::new("supply"); // Vtoken owned by an address for a specific denom pub const VTOKENS: Map<(Addr, &str), Vec> = Map::new("Vtokens by owner"); - #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Proposal { pub app_id: u64, - pub voting_start_time: u64, - pub voting_end_time: u64, + pub voting_start_time: Timestamp, + pub voting_end_time: Timestamp, pub extended_pair: Vec, pub emission_completed: bool, pub rebase_completed: bool, - pub foundation_emission_completed:bool, + pub foundation_emission_completed: bool, pub emission_distributed: u128, pub rebase_distributed: u128, - pub foundation_distributed : u128, + pub foundation_distributed: u128, pub total_voted_weight: u128, pub total_surplus: Coin, - pub height : u64 - + pub height: u64, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -140,7 +125,6 @@ pub struct Vote { pub app_id: u64, pub extended_pair: u64, pub vote_weight: u128, - pub bribe_claimed: bool, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -149,27 +133,24 @@ pub struct Rewards { pub rebase: Coin, } +pub const PROPOSALCOUNT: Item = Item::new("Proposal Count"); -pub const VOTINGPERIOD: Item = Item::new("Voting_period"); - -pub const PROPOSALCOUNT: Item = Item::new("Voting_period"); - -pub const APPCURRENTPROPOSAL: Map = Map::new("App_Current_proposal"); +pub const APPCURRENTPROPOSAL: Map = Map::new("App Current_proposal"); pub const PROPOSALVOTE: Map<(u64, u64), Uint128> = Map::new("Proposal vote"); -pub const PROPOSAL: Map = Map::new("Proposal vote"); +pub const PROPOSAL: Map = Map::new("Proposal"); -pub const BRIBES_BY_PROPOSAL: Map<(u64, u64), Vec> = Map::new("Proposal vote"); +pub const BRIBES_BY_PROPOSAL: Map<(u64, u64), Vec> = Map::new("BRIBES_BY_PROPOSALe"); -pub const EMISSION: Map = Map::new("Proposal vote"); +pub const EMISSION: Map = Map::new("Emission"); -pub const VOTERS_VOTE: Map<(Addr, u64), bool> = Map::new("has voted"); +pub const VOTERS_VOTE: Map<(Addr, u64), bool> = Map::new("Has voted"); -pub const VOTERSPROPOSAL: Map<(Addr, u64), Vote> = Map::new("has voted"); +pub const VOTERSPROPOSAL: Map<(Addr, u64), Vote> = Map::new("Proposal Vote by voter"); -pub const CLAIMABLEREWARD: Map<(u64,Addr), Rewards> = Map::new("has voted"); +pub const MAXPROPOSALCLAIMED: Map<(u64, Addr), u64> = Map::new("max proposal claimed"); -pub const MAXPROPOSALCLAIMED: Map<(u64,Addr), u64> = Map::new("has voted"); +pub const COMPLETEDPROPOSALS: Map> = Map::new("completed proposals"); -pub const COMPLETEDPROPOSALS: Map>= Map::new("has voted"); +pub const LOCKINGADDRESS: Map> = Map::new("locking addresses ");