diff --git a/fplus-lib/src/core/application/lifecycle.rs b/fplus-lib/src/core/application/lifecycle.rs index 3ab29c1..f652dfc 100644 --- a/fplus-lib/src/core/application/lifecycle.rs +++ b/fplus-lib/src/core/application/lifecycle.rs @@ -46,25 +46,31 @@ impl LifeCycle { /// Change Application state to Proposal from Governance Review /// Actor input is the actor who is changing the state - pub fn finish_governance_review(&self, actor: String, current_allocation_id: String) -> Self { - LifeCycle { + pub fn finish_governance_review(&self, actor: String, current_allocation_id: String) -> Result { + let new_lifecycle = LifeCycle { state: AppState::ReadyToSign, validated_by: actor, validated_at: Utc::now().to_string(), updated_at: Utc::now().to_string(), active_request: Some(current_allocation_id), ..self.clone() - } + }; + + new_lifecycle.validate()?; + Ok(new_lifecycle) } - pub fn sign_grant_datacap_proposal(&self, validated_by: &str) -> Self { - LifeCycle { + pub fn sign_grant_datacap_proposal(&self, validated_by: &str) -> Result { + let new_lifecycle = LifeCycle { state: AppState::StartSignDatacap, updated_at: Utc::now().to_string(), validated_by: validated_by.into(), validated_at: Utc::now().to_string(), ..self.clone() - } + }; + + new_lifecycle.validate()?; + Ok(new_lifecycle) } pub fn update_lifecycle_after_sign( @@ -154,4 +160,38 @@ impl LifeCycle { ..self.clone() } } + + pub fn validate(&self) -> Result<(), String> { + if self.client_on_chain_address.is_empty() { + return Err("Client on-chain address is required".to_string()); + } + if self.multisig_address.is_empty() { + return Err("Multisig address is required".to_string()); + } + + match self.state { + AppState::Granted | AppState::StartSignDatacap => { + if self.validated_by.is_empty() { + return Err("Validated by is required for Granted/StartSignDatacap state".to_string()); + } + if self.validated_at.is_empty() { + return Err("Validated at is required for Granted/StartSignDatacap state".to_string()); + } + } + AppState::ReadyToSign => { + if self.validated_by.is_empty() { + return Err("Validated by is required for ReadyToSign state".to_string()); + } + if self.validated_at.is_empty() { + return Err("Validated at is required for ReadyToSign state".to_string()); + } + if self.active_request.is_none() || self.active_request.as_ref().unwrap().is_empty() { + return Err("Active request ID is required for ReadyToSign state".to_string()); + } + } + _ => {} + } + + Ok(()) + } } diff --git a/fplus-lib/src/core/application/mod.rs b/fplus-lib/src/core/application/mod.rs index c85472d..f146e84 100644 --- a/fplus-lib/src/core/application/mod.rs +++ b/fplus-lib/src/core/application/mod.rs @@ -124,21 +124,25 @@ impl file::ApplicationFile { sps_change_request: &SpsChangeRequest, app_state: &AppState, request_id: &String, - ) -> Self { - let new_life_cycle = - self.lifecycle - .clone() - .update_lifecycle_after_sign(app_state, validated_by, request_id); + ) -> Result { + let new_life_cycle = self.lifecycle + .clone() + .update_lifecycle_after_sign(app_state, validated_by, request_id)?; + let sps_change_requests = self .allowed_sps .clone() .unwrap_or_default() .add_change_request(sps_change_request); - Self { + + let new_app = Self { lifecycle: new_life_cycle, allowed_sps: Some(sps_change_requests), ..self.clone() - } + }; + + new_app.validate()?; + Ok(new_app) } pub fn update_changing_sps_request( @@ -212,6 +216,20 @@ impl file::ApplicationFile { ..self.clone() } } + pub fn validate(&self) -> Result<(), String> { + self.lifecycle.validate()?; + + match self.lifecycle.state { + AppState::ReadyToSign | AppState::StartSignDatacap | AppState::Granted => { + if self.allocation.0.is_empty() { + return Err("Allocations are required for this state".to_string()); + } + } + _ => {} + } + + Ok(()) + } } impl std::str::FromStr for file::ApplicationFile { diff --git a/fplus-lib/src/core/mod.rs b/fplus-lib/src/core/mod.rs index 7245b42..39e200a 100644 --- a/fplus-lib/src/core/mod.rs +++ b/fplus-lib/src/core/mod.rs @@ -4463,6 +4463,17 @@ _The initial issue can be edited in order to solve the request of the verifier. Ok(application_file) } + + pub fn reached_total_datacap(self) -> Self { + let empty = "".to_string(); + + LifeCycle { + is_active: false, + updated_at: Utc::now().to_string(), + active_request: Some(empty), + ..self + } + } } #[derive(Serialize, Deserialize, Debug)]