From 0b0c190db8a71179f431756e15b5bf5e57449d6b Mon Sep 17 00:00:00 2001 From: Zeek Date: Mon, 26 Feb 2024 15:48:35 -0700 Subject: [PATCH] validation --- .../zomes/integrity/grants/src/application.rs | 210 +++++++++++++----- .../grants/src/evaluation_template.rs | 2 +- .../zomes/integrity/grants/src/grant_pool.rs | 2 + .../grants/src/grant_pool_outcome.rs | 93 ++++---- 4 files changed, 200 insertions(+), 107 deletions(-) diff --git a/dnas/grant_pools/zomes/integrity/grants/src/application.rs b/dnas/grant_pools/zomes/integrity/grants/src/application.rs index 17be7ce..108b864 100644 --- a/dnas/grant_pools/zomes/integrity/grants/src/application.rs +++ b/dnas/grant_pools/zomes/integrity/grants/src/application.rs @@ -1,11 +1,11 @@ -use hdi::prelude::*; use alloy_primitives::U256; -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +use hdi::prelude::*; +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] pub struct ApplicationOutcome { approved: bool, grant_pool: ActionHash, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[serde(tag = "type")] pub enum ApplicationStatus { Draft, @@ -15,8 +15,35 @@ pub enum ApplicationStatus { // EVM claim Transaction Hash Claimed(U256), } +impl ApplicationStatus { + fn is_draft(&self) -> bool { + match self { + ApplicationStatus::Draft => true, + _ => false, + } + } + fn is_submitted(&self) -> bool { + match self { + ApplicationStatus::Submitted(_) => true, + _ => false, + } + } + fn is_evaluated(&self) -> bool { + match self { + ApplicationStatus::Evaluated(_) => true, + _ => false, + } + } + fn _is_claimed(&self) -> bool { + match self { + ApplicationStatus::Claimed(_) => true, + _ => false, + } + } +} + #[hdk_entry_helper] -#[derive(Clone, PartialEq)] +#[derive(Clone, Eq, PartialEq)] pub struct Application { pub application_template: ActionHash, pub content: String, @@ -25,24 +52,100 @@ pub struct Application { } pub fn validate_create_application( _action: EntryCreationAction, - _application: Application, + application: Application, ) -> ExternResult { + if application.content.is_empty() { + return Ok(ValidateCallbackResult::Invalid( + "Content cannot be empty".to_string(), + )); + } + if application.amount == U256::from(0) { + return Ok(ValidateCallbackResult::Invalid( + "Amount cannot be zero".to_string(), + )); + } + let record = must_get_valid_record(application.application_template.clone())?; + let _application_template: crate::ApplicationTemplate = record + .entry() + .to_app_option() + .map_err(|e| wasm_error!(e))? + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "Dependant action must be accompanied by an entry" + ))))?; + Ok(ValidateCallbackResult::Valid) } pub fn validate_update_application( - _action: Update, - _application: Application, - _original_action: EntryCreationAction, - _original_application: Application, + action: Update, + application: Application, + original_action: EntryCreationAction, + original_application: Application, ) -> ExternResult { + let original_status = original_application.status; + if &action.author != original_action.author() { + return Ok(ValidateCallbackResult::Invalid( + "Only original author can update".to_string(), + )); + } + if original_application.application_template != application.application_template { + return Ok(ValidateCallbackResult::Invalid( + "Application template action hash must be the same".to_string(), + )); + } + if !&original_status.is_draft() { + if original_application.content != application.content { + return Ok(ValidateCallbackResult::Invalid( + "Content can only be changed in draft".to_string(), + )); + } + if original_application.amount != application.amount { + return Ok(ValidateCallbackResult::Invalid( + "Amount can only be changed in draft".to_string(), + )); + } + } + + match application.status { + ApplicationStatus::Draft => { + if !&original_status.is_draft() { + return Ok(ValidateCallbackResult::Invalid( + "Status cannot be reverted".to_string(), + )); + } + } + ApplicationStatus::Submitted(_) => { + if !&original_status.is_draft() { + return Ok(ValidateCallbackResult::Invalid( + "Status cannot be reverted".to_string(), + )); + } + } + ApplicationStatus::Evaluated(_) => { + if !&original_status.is_submitted() { + return Ok(ValidateCallbackResult::Invalid( + "Status cannot be reverted".to_string(), + )); + } + } + ApplicationStatus::Claimed(_) => { + if !&original_status.is_evaluated() { + return Ok(ValidateCallbackResult::Invalid( + "Status cannot be reverted".to_string(), + )); + } + } + }; Ok(ValidateCallbackResult::Valid) } + pub fn validate_delete_application( _action: Delete, _original_action: EntryCreationAction, _original_application: Application, ) -> ExternResult { - Ok(ValidateCallbackResult::Invalid(String::from("Applications cannot be deleted"))) + Ok(ValidateCallbackResult::Invalid(String::from( + "Applications cannot be deleted", + ))) } pub fn validate_create_link_application_updates( _action: CreateLink, @@ -52,38 +155,31 @@ pub fn validate_create_link_application_updates( ) -> ExternResult { let action_hash = base_address .into_action_hash() - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("No action hash associated with link")) - ), - )?; + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "No action hash associated with link" + ))))?; let record = must_get_valid_record(action_hash)?; let _application: crate::Application = record .entry() .to_app_option() .map_err(|e| wasm_error!(e))? - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("Linked action must reference an entry")) - ), - )?; - let action_hash = target_address - .into_action_hash() - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("No action hash associated with link")) - ), - )?; + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "Linked action must reference an entry" + ))))?; + let action_hash = + target_address + .into_action_hash() + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "No action hash associated with link" + ))))?; let record = must_get_valid_record(action_hash)?; let _application: crate::Application = record .entry() .to_app_option() .map_err(|e| wasm_error!(e))? - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("Linked action must reference an entry")) - ), - )?; + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "Linked action must reference an entry" + ))))?; Ok(ValidateCallbackResult::Valid) } pub fn validate_delete_link_application_updates( @@ -93,11 +189,9 @@ pub fn validate_delete_link_application_updates( _target: AnyLinkableHash, _tag: LinkTag, ) -> ExternResult { - Ok( - ValidateCallbackResult::Invalid( - String::from("ApplicationUpdates links cannot be deleted"), - ), - ) + Ok(ValidateCallbackResult::Invalid(String::from( + "ApplicationUpdates links cannot be deleted", + ))) } pub fn validate_create_link_all_applications( _action: CreateLink, @@ -105,23 +199,20 @@ pub fn validate_create_link_all_applications( target_address: AnyLinkableHash, _tag: LinkTag, ) -> ExternResult { - let action_hash = target_address - .into_action_hash() - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("No action hash associated with link")) - ), - )?; + let action_hash = + target_address + .into_action_hash() + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "No action hash associated with link" + ))))?; let record = must_get_valid_record(action_hash)?; let _application: crate::Application = record .entry() .to_app_option() .map_err(|e| wasm_error!(e))? - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("Linked action must reference an entry")) - ), - )?; + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "Linked action must reference an entry" + ))))?; Ok(ValidateCallbackResult::Valid) } pub fn validate_delete_link_all_applications( @@ -139,23 +230,20 @@ pub fn validate_create_link_my_applications( target_address: AnyLinkableHash, _tag: LinkTag, ) -> ExternResult { - let action_hash = target_address - .into_action_hash() - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("No action hash associated with link")) - ), - )?; + let action_hash = + target_address + .into_action_hash() + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "No action hash associated with link" + ))))?; let record = must_get_valid_record(action_hash)?; let _application: crate::Application = record .entry() .to_app_option() .map_err(|e| wasm_error!(e))? - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("Linked action must reference an entry")) - ), - )?; + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "Linked action must reference an entry" + ))))?; Ok(ValidateCallbackResult::Valid) } pub fn validate_delete_link_my_applications( diff --git a/dnas/grant_pools/zomes/integrity/grants/src/evaluation_template.rs b/dnas/grant_pools/zomes/integrity/grants/src/evaluation_template.rs index a35523b..fd627b3 100644 --- a/dnas/grant_pools/zomes/integrity/grants/src/evaluation_template.rs +++ b/dnas/grant_pools/zomes/integrity/grants/src/evaluation_template.rs @@ -53,7 +53,7 @@ pub fn validate_create_evaluation_template( for criteria in weighted_criteria { if criteria.label.is_empty() { return Ok(ValidateCallbackResult::Invalid( - "Label can't be empty".to_string(), + "Label cannnot be empty".to_string(), )); } if criteria.weight == 0 { diff --git a/dnas/grant_pools/zomes/integrity/grants/src/grant_pool.rs b/dnas/grant_pools/zomes/integrity/grants/src/grant_pool.rs index 4b0a150..b35b829 100644 --- a/dnas/grant_pools/zomes/integrity/grants/src/grant_pool.rs +++ b/dnas/grant_pools/zomes/integrity/grants/src/grant_pool.rs @@ -69,6 +69,7 @@ pub fn validate_create_grant_pool( ))))?; Ok(ValidateCallbackResult::Valid) } + pub fn validate_update_grant_pool( _action: Update, _grant_pool: GrantPool, @@ -88,6 +89,7 @@ pub fn validate_delete_grant_pool( "Grant Pools cannot be deleted", ))) } + pub fn validate_create_link_time_period_to_grant_pools( _action: CreateLink, base_address: AnyLinkableHash, diff --git a/dnas/grant_pools/zomes/integrity/grants/src/grant_pool_outcome.rs b/dnas/grant_pools/zomes/integrity/grants/src/grant_pool_outcome.rs index 444912f..0e33c10 100644 --- a/dnas/grant_pools/zomes/integrity/grants/src/grant_pool_outcome.rs +++ b/dnas/grant_pools/zomes/integrity/grants/src/grant_pool_outcome.rs @@ -1,14 +1,16 @@ -use std::collections::BTreeMap; use hdi::prelude::*; +use std::collections::BTreeMap; + #[hdk_entry_helper] #[derive(Clone, PartialEq)] pub struct GrantPoolOutcome { pub grant_pool: ActionHash, - pub outcomes: BTreeMap>, + // K: ActionHash of Application, V: ActionHash of Evaluations + pub evaluations: BTreeMap>, pub coupon: Vec, } pub fn validate_create_grant_pool_outcome( - _action: EntryCreationAction, + action: EntryCreationAction, grant_pool_outcome: GrantPoolOutcome, ) -> ExternResult { let record = must_get_valid_record(grant_pool_outcome.grant_pool.clone())?; @@ -16,11 +18,25 @@ pub fn validate_create_grant_pool_outcome( .entry() .to_app_option() .map_err(|e| wasm_error!(e))? - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("Dependant action must be accompanied by an entry")) - ), - )?; + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "Dependant action must be accompanied by an entry" + ))))?; + + if record.signed_action.action().author() != action.author() { + return Ok(ValidateCallbackResult::Invalid( + "Only grant pool author can create an outcome".to_string(), + )); + } + + for (application, evaluations) in grant_pool_outcome.evaluations.clone() { + must_get_valid_record(application.clone())?; + for evaluation in evaluations { + must_get_valid_record(evaluation.clone())?; + } + } + + // TODO: tallying of funding is accurate and sums to expected amount using evm native types + Ok(ValidateCallbackResult::Valid) } pub fn validate_update_grant_pool_outcome( @@ -29,22 +45,18 @@ pub fn validate_update_grant_pool_outcome( _original_action: EntryCreationAction, _original_grant_pool_outcome: GrantPoolOutcome, ) -> ExternResult { - Ok( - ValidateCallbackResult::Invalid( - String::from("Grant Pool Outcomes cannot be updated"), - ), - ) + Ok(ValidateCallbackResult::Invalid(String::from( + "Grant Pool Outcomes cannot be updated", + ))) } pub fn validate_delete_grant_pool_outcome( _action: Delete, _original_action: EntryCreationAction, _original_grant_pool_outcome: GrantPoolOutcome, ) -> ExternResult { - Ok( - ValidateCallbackResult::Invalid( - String::from("Grant Pool Outcomes cannot be deleted"), - ), - ) + Ok(ValidateCallbackResult::Invalid(String::from( + "Grant Pool Outcomes cannot be deleted", + ))) } pub fn validate_create_link_grant_pool_to_grant_pool_outcomes( _action: CreateLink, @@ -54,38 +66,31 @@ pub fn validate_create_link_grant_pool_to_grant_pool_outcomes( ) -> ExternResult { let action_hash = base_address .into_action_hash() - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("No action hash associated with link")) - ), - )?; + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "No action hash associated with link" + ))))?; let record = must_get_valid_record(action_hash)?; let _grant_pool: crate::GrantPool = record .entry() .to_app_option() .map_err(|e| wasm_error!(e))? - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("Linked action must reference an entry")) - ), - )?; - let action_hash = target_address - .into_action_hash() - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("No action hash associated with link")) - ), - )?; + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "Linked action must reference an entry" + ))))?; + let action_hash = + target_address + .into_action_hash() + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "No action hash associated with link" + ))))?; let record = must_get_valid_record(action_hash)?; let _grant_pool_outcome: crate::GrantPoolOutcome = record .entry() .to_app_option() .map_err(|e| wasm_error!(e))? - .ok_or( - wasm_error!( - WasmErrorInner::Guest(String::from("Linked action must reference an entry")) - ), - )?; + .ok_or(wasm_error!(WasmErrorInner::Guest(String::from( + "Linked action must reference an entry" + ))))?; Ok(ValidateCallbackResult::Valid) } pub fn validate_delete_link_grant_pool_to_grant_pool_outcomes( @@ -95,9 +100,7 @@ pub fn validate_delete_link_grant_pool_to_grant_pool_outcomes( _target: AnyLinkableHash, _tag: LinkTag, ) -> ExternResult { - Ok( - ValidateCallbackResult::Invalid( - String::from("GrantPoolToGrantPoolOutcomes links cannot be deleted"), - ), - ) + Ok(ValidateCallbackResult::Invalid(String::from( + "GrantPoolToGrantPoolOutcomes links cannot be deleted", + ))) }