From 7c5c55ca5b0a981992a5d69f32a2727b28564fe6 Mon Sep 17 00:00:00 2001 From: arnabmitra Date: Fri, 4 Aug 2023 17:50:23 -0600 Subject: [PATCH] adding state for Loan Pool Collateral and other changes. --- crates/contract/src/core/collateral.rs | 15 +++- crates/contract/src/core/constants.rs | 3 + crates/contract/src/core/security.rs | 3 +- crates/contract/src/execute/router.rs | 2 +- .../src/execute/settlement/add_loanpool.rs | 88 +++++++++++++++---- .../whitelist_loanpool_contributors.rs | 2 +- .../src/storage/loan_pool_collateral.rs | 82 +++++++++++++++++ crates/contract/src/storage/mod.rs | 1 + .../storage/whitelist_contributors_store.rs | 4 +- 9 files changed, 173 insertions(+), 27 deletions(-) create mode 100644 crates/contract/src/storage/loan_pool_collateral.rs diff --git a/crates/contract/src/core/collateral.rs b/crates/contract/src/core/collateral.rs index 7c93cc3..9b900ea 100644 --- a/crates/contract/src/core/collateral.rs +++ b/crates/contract/src/core/collateral.rs @@ -1,5 +1,5 @@ -use cosmwasm_std::{Addr, Coin, Uint128}; -use provwasm_std::AccessGrant; +use cosmwasm_std::{Addr, Coin, CosmosMsg, Uint128}; +use provwasm_std::{AccessGrant, ProvenanceMsg}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -16,7 +16,7 @@ impl LoanPoolMarkerCollateral { marker_address: Addr, marker_denom: S, share_count: u128, - removed_permissions: &[AccessGrant], + removed_permissions: Vec, ) -> Self { Self { marker_address, @@ -38,3 +38,12 @@ impl LoanPoolMarkers { Self { collaterals } } } + + +/// Holds information about a loan pool addition. +pub struct LoanPoolAdditionData { + /// The collateral being added to the loan. + pub collateral: LoanPoolMarkerCollateral, + /// The Provenance messages associated with the loan. + pub messages: Vec>, +} diff --git a/crates/contract/src/core/constants.rs b/crates/contract/src/core/constants.rs index a4c6b36..8dcc3c9 100644 --- a/crates/contract/src/core/constants.rs +++ b/crates/contract/src/core/constants.rs @@ -8,3 +8,6 @@ pub const PAID_IN_CAPITAL_KEY: &str = "paid_in_capital"; pub const SECURITIES_MAP_KEY: &str = "security_types_map"; pub const REMAINING_SECURITIES_KEY: &str = "remaining_securities_map"; pub const AVAILABLE_CAPITAL_KEY: &str = "available_capital"; +pub const LOAN_POOL_COLLATERAL: &str = "paid_in_capital"; +pub const WHITELIST_CONTRIBUTORS: &str = "whitelist_contributors"; + diff --git a/crates/contract/src/core/security.rs b/crates/contract/src/core/security.rs index beec7ee..dcd563d 100644 --- a/crates/contract/src/core/security.rs +++ b/crates/contract/src/core/security.rs @@ -45,9 +45,8 @@ pub struct AcceptedCommitment { #[cw_serde] pub struct ContributeLoanPools { - pub original_owner: Addr, // who owns this set of loan pools, this assumes a homogenous loan pools, i.e one owner owns all loan pools in the markers field - pub markers: Vec, // marker address for loan pools being contributed, usually will be only a set of 1 + pub markers: Vec, // marker denoms for loan pools being contributed, usually will be only a set of 1 } diff --git a/crates/contract/src/execute/router.rs b/crates/contract/src/execute/router.rs index d641bef..25dd177 100644 --- a/crates/contract/src/execute/router.rs +++ b/crates/contract/src/execute/router.rs @@ -39,7 +39,7 @@ pub fn route(deps: ProvDepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> cancel_commitment::handle(deps, env, info.sender, lp) } ExecuteMsg::ContributeLoanPool { loan_pools } => { - add_loanpool::handle(deps, env, info.sender, loan_pools) + add_loanpool::handle(deps, env, info, loan_pools) } ExecuteMsg::WhiteListLoanPoolContributors { loan_pool_contributors } => { whitelist_loanpool_contributors::handle(deps, env, info.sender, loan_pool_contributors.addresses) diff --git a/crates/contract/src/execute/settlement/add_loanpool.rs b/crates/contract/src/execute/settlement/add_loanpool.rs index 1ee95f2..675926b 100644 --- a/crates/contract/src/execute/settlement/add_loanpool.rs +++ b/crates/contract/src/execute/settlement/add_loanpool.rs @@ -1,5 +1,5 @@ -use cosmwasm_std::{Addr, DepsMut, Env, Event, MessageInfo, Response, Storage}; -use provwasm_std::{AccessGrant, MarkerAccess, ProvenanceQuerier, ProvenanceQuery}; +use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Response, Storage}; +use provwasm_std::{AccessGrant, Marker, MarkerAccess, ProvenanceMsg, ProvenanceQuerier, ProvenanceQuery, revoke_marker_access}; use crate::{ core::{ @@ -15,17 +15,19 @@ use crate::{ }, util::settlement::timestamp_is_expired, }; -use crate::core::collateral::LoanPoolMarkerCollateral; +use crate::core::collateral::{LoanPoolAdditionData, LoanPoolMarkerCollateral}; +use crate::execute::settlement::extensions::ResultExtensions; use crate::execute::settlement::marker_loan_pool_validation::validate_marker_for_loan_pool_add_remove; +use crate::storage::loan_pool_collateral::set; use crate::storage::whitelist_contributors_store::get_whitelist_contributors; -use crate::util::provenance_utilities::query_total_supply; +use crate::util::provenance_utilities::{get_single_marker_coin_holding, query_total_supply}; use super::commitment::{Commitment, CommitmentState}; pub fn handle( deps: ProvDepsMut, env: Env, - sender: Addr, + info: MessageInfo, loan_pools: ContributeLoanPools, ) -> ProvTxResponse { let state = state::get(deps.storage)?; @@ -34,17 +36,23 @@ pub fn handle( let whitelist_contributors = get_whitelist_contributors(deps.storage)?; // Check if sender is in the whitelist - if !whitelist_contributors.contains(&sender) { + if !whitelist_contributors.contains(&info.sender) { return Err(ContractError::NotInWhitelist {}); } let mut response = Response::new() - .add_attribute("action", "accept_commitments") - .add_attribute("gp", state.gp); + .add_attribute("added_by", info.sender.clone()); for pool in loan_pools.markers { - // accept_commitment(deps.storage, commitment.clone())?; - // add the marker, change owner, escrow the account - response = response.add_event(Event::new("loanpool_added").add_attribute("marker_address", pool.to_string())); + let LoanPoolAdditionData { + collateral, + messages + } = create_marker_pool_collateral(&deps, &info, &env, pool.clone()).unwrap(); + //inset the collateral + set(deps.storage,&collateral)?; + + // Add messages and event in a chained manner + response = response.add_messages(messages) + .add_event(Event::new("loanpool_added").add_attribute("marker_address", pool.to_string())); } Ok(response) @@ -63,7 +71,9 @@ fn create_marker_pool_collateral( info: &MessageInfo, env: &Env, marker_denom: String, -) -> Result { +) -> Result { + + // get marker let marker = ProvenanceQuerier::new(&deps.querier).get_marker_by_denom(&marker_denom)?; @@ -85,14 +95,56 @@ fn create_marker_pool_collateral( &[MarkerAccess::Admin, MarkerAccess::Withdraw], supply, )?; -// Define some dummy data for removed_permissions - let empty_permissions: Vec = Vec::new(); - // Create a LoanPoolMarkerCollateral instance with some dummy values - let collateral = LoanPoolMarkerCollateral::new(info.sender.clone(), marker_denom, 10, &empty_permissions); - // Return the instance wrapped in a Result - Ok(collateral) + let messages = get_marker_permission_revoke_messages(&marker, &env.contract.address)?; + + LoanPoolAdditionData { + collateral: LoanPoolMarkerCollateral::new( + marker.address.clone(), + &marker.denom, + get_single_marker_coin_holding(&marker)?.amount.u128(), + marker.permissions + .into_iter() + .filter(|perm| perm.address != env.contract.address) + .collect::>(), + ), + messages, + } + .to_ok() +} + + +fn get_marker_permission_revoke_messages( + marker: &Marker, + contract_address: &Addr, +) -> Result>, ContractError> { + let mut messages: Vec> = vec![]; + for permission in marker + .permissions + .iter() + .filter(|perm| &perm.address != contract_address) + { + messages.push(revoke_marker_access( + &marker.denom, + permission.address.clone(), + )?); + } + messages.to_ok() } +#[cfg(test)] +mod tests { + use cosmwasm_std::{Empty, Event, Response}; + + #[test] + fn test_coin_trade_with_valid_data() { + let mut response: Response = Response::new(); + response = response.add_event(Event::new("loanpool_added").add_attribute("marker_address", "addr1")); + response = response.add_event(Event::new("loanpool_added").add_attribute("marker_address", "addr2")); + +// Now the response object contains two separate events with the name "loanpool_added." + assert_eq!(response.events.len(), 2); + } +} \ No newline at end of file diff --git a/crates/contract/src/execute/settlement/whitelist_loanpool_contributors.rs b/crates/contract/src/execute/settlement/whitelist_loanpool_contributors.rs index 0ad4683..fa09ca9 100644 --- a/crates/contract/src/execute/settlement/whitelist_loanpool_contributors.rs +++ b/crates/contract/src/execute/settlement/whitelist_loanpool_contributors.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Addr, Env, Response, Storage}; +use cosmwasm_std::{Addr, Env, MessageInfo, Response, Storage}; use crate::{ core::{ diff --git a/crates/contract/src/storage/loan_pool_collateral.rs b/crates/contract/src/storage/loan_pool_collateral.rs new file mode 100644 index 0000000..f3622f5 --- /dev/null +++ b/crates/contract/src/storage/loan_pool_collateral.rs @@ -0,0 +1,82 @@ +use cosmwasm_std::{Addr, Order, Storage}; +use cw_storage_plus::Map; +use crate::core::collateral::LoanPoolMarkerCollateral; +use crate::core::constants::LOAN_POOL_COLLATERAL; +use crate::core::error::ContractError; + +pub const COLLATERAL: Map = Map::new(LOAN_POOL_COLLATERAL); + +pub fn get(storage: &dyn Storage, marker_address: Addr) -> Result { + Ok(COLLATERAL.load(storage, marker_address)?) +} + +pub fn set(storage: &mut dyn Storage, collateral: &LoanPoolMarkerCollateral) -> Result<(), ContractError> { + Ok(COLLATERAL.save(storage, collateral.marker_address.clone(), collateral)?) +} + +pub fn remove(storage: &mut dyn Storage, commitment_lp: Addr) { + COLLATERAL.remove(storage, commitment_lp); +} + +pub fn exists(storage: &dyn Storage, lp: Addr) -> bool { + COLLATERAL.has(storage, lp) +} + +pub fn get_with_state(storage: &dyn Storage, state: LoanPoolMarkerCollateral) -> Vec { + let collateral: Vec = COLLATERAL + .range(storage, None, None, Order::Ascending) + .filter(|item| item.is_ok() && item.as_ref().unwrap().1.marker_denom == state.marker_denom) + .map(|item| item.unwrap().1) + .collect(); + collateral +} + +#[cfg(test)] +mod tests { + use provwasm_mocks::mock_dependencies; + use super::*; + + #[test] + fn test_get_and_set() { + let mut deps = mock_dependencies(&[]); + let marker_address = Addr::unchecked("addr1"); + let collateral = LoanPoolMarkerCollateral::new( + marker_address.clone(), + "denom".to_string(), + 100, + Vec::new() + ); + + // Test setting collateral + set(&mut deps.storage, &collateral).unwrap(); + let result = get(&deps.storage, marker_address.clone()).unwrap(); + assert_eq!(result, collateral); + + // Test removing collateral + remove(&mut deps.storage, marker_address.clone()); + let result = get(&deps.storage, marker_address.clone()); + assert!(result.is_err()); // Expect an error because the collateral has been removed + } + + #[test] + fn test_exists() { + let mut deps = mock_dependencies(&[]); + let marker_address = Addr::unchecked("addr1"); + let collateral = LoanPoolMarkerCollateral::new( + marker_address.clone(), + "denom".to_string(), + 100, + Vec::new() + ); + + // Test existence after setting + set(&mut deps.storage, &collateral).unwrap(); + assert!(exists(&deps.storage, marker_address.clone())); + + // Test existence after removing + remove(&mut deps.storage, marker_address.clone()); + assert!(!exists(&deps.storage, marker_address.clone())); + } + + // Add more tests as needed for other functions and edge cases +} \ No newline at end of file diff --git a/crates/contract/src/storage/mod.rs b/crates/contract/src/storage/mod.rs index 501fe10..5b6d5d4 100644 --- a/crates/contract/src/storage/mod.rs +++ b/crates/contract/src/storage/mod.rs @@ -5,3 +5,4 @@ pub mod remaining_securities; pub mod securities; pub mod state; pub mod whitelist_contributors_store; +pub mod loan_pool_collateral; diff --git a/crates/contract/src/storage/whitelist_contributors_store.rs b/crates/contract/src/storage/whitelist_contributors_store.rs index dcab68f..35be724 100644 --- a/crates/contract/src/storage/whitelist_contributors_store.rs +++ b/crates/contract/src/storage/whitelist_contributors_store.rs @@ -1,11 +1,11 @@ use cosmwasm_std::{Addr, Storage}; use cw_storage_plus::{Item}; +use crate::core::constants::WHITELIST_CONTRIBUTORS; use crate::core::error::ContractError; use crate::core::security::LoanPoolContributors; -const KEY: &'static str = "whitelist_contributors"; -pub const WHITELIST: Item> = Item::new(KEY); +pub const WHITELIST: Item> = Item::new(WHITELIST_CONTRIBUTORS); impl LoanPoolContributors { pub fn human_whitelist(&self) -> Vec {