From 94eac8601a0fb535c153b6a43e4b6654498d9827 Mon Sep 17 00:00:00 2001 From: didiermis Date: Thu, 20 Oct 2022 11:39:45 -0500 Subject: [PATCH 1/9] Fix validation for do_execute_transactions when a builder sends a drawdown to submitted status --- pallets/proxy-financial/src/functions.rs | 17 +++++++++++------ pallets/proxy-financial/src/lib.rs | 2 ++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/pallets/proxy-financial/src/functions.rs b/pallets/proxy-financial/src/functions.rs index f77ac9a1..c9bd6acb 100644 --- a/pallets/proxy-financial/src/functions.rs +++ b/pallets/proxy-financial/src/functions.rs @@ -877,9 +877,9 @@ impl Pallet { project_id: [u8;32], drawdown_id: [u8;32], ) -> DispatchResult { - //ensure admin permissions + //ensure admin permissions Self::is_superuser(admin.clone(), &Self::get_global_scope(), ProxyRole::Administrator.id())?; - + // Get drawdown data & ensure drawdown exists let drawdown_data = DrawdownsInfo::::get(drawdown_id).ok_or(Error::::DrawdownNotFound)?; @@ -1001,11 +1001,16 @@ impl Pallet { //Ensure drawdown exists so helper private functions doesn't need to check it ensure!(DrawdownsInfo::::contains_key(drawdown_id), Error::::DrawdownNotFound); - // Ensure transactions are not empty if submit is true - if submit == false { - ensure!(!transactions.is_empty(), Error::::EmptyTransactions); + // Ensure transactions are not empty + match submit { + true => { + ensure!(TransactionsByDrawdown::::contains_key(project_id, drawdown_id), Error::::NoTransactionsToSubmit); + }, + false => { + ensure!(!transactions.is_empty(), Error::::EmptyTransactions); + }, } - + //Todo: create custom error to replace nonevalue error for transaction in transactions { match transaction.3 { diff --git a/pallets/proxy-financial/src/lib.rs b/pallets/proxy-financial/src/lib.rs index 8c5d17e0..3c43b6d3 100644 --- a/pallets/proxy-financial/src/lib.rs +++ b/pallets/proxy-financial/src/lib.rs @@ -417,6 +417,8 @@ pub mod pallet { UserRoleRequired, /// Can not delete a user if the user is assigned to a project UserHasAssignedProjects, + /// Can not send a drawdown to submitted status if it has no transactions + NoTransactionsToSubmit, } From 192e790f9dba930cd9a9e181bfa3362d2ab66094 Mon Sep 17 00:00:00 2001 From: didiermis Date: Fri, 21 Oct 2022 11:00:13 -0500 Subject: [PATCH 2/9] Add fields description & feedback in DrawdownData structure used for bulkuploads --- pallets/proxy-financial/src/types.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pallets/proxy-financial/src/types.rs b/pallets/proxy-financial/src/types.rs index 7dfa5d15..e238a7c1 100644 --- a/pallets/proxy-financial/src/types.rs +++ b/pallets/proxy-financial/src/types.rs @@ -107,6 +107,8 @@ pub struct DrawdownData { pub total_amount: u64, pub status: DrawdownStatus, pub documents: Option>, + pub description: Option, + pub feedback: Option, pub created_date: u64, pub close_date: u64, } From 8819b91a595c4c5191a8a1996b8542fc664dfcda Mon Sep 17 00:00:00 2001 From: didiermis Date: Fri, 21 Oct 2022 12:57:07 -0500 Subject: [PATCH 3/9] Add initial flow for bulkupload where the admin sends the transactions directly to approved --- pallets/proxy-financial/src/functions.rs | 128 +++++++++++++++++++---- pallets/proxy-financial/src/lib.rs | 35 ++++++- 2 files changed, 142 insertions(+), 21 deletions(-) diff --git a/pallets/proxy-financial/src/functions.rs b/pallets/proxy-financial/src/functions.rs index c9bd6acb..fc0a2f16 100644 --- a/pallets/proxy-financial/src/functions.rs +++ b/pallets/proxy-financial/src/functions.rs @@ -416,6 +416,9 @@ impl Pallet { )?; }, CUDAction::Delete => { + // Ensure admin cannot delete himself + ensure!(user.0 != admin, Error::::AdministatorsCannotDeleteThemselves); + Self::do_delete_user( user.0.clone() )?; @@ -789,6 +792,8 @@ impl Pallet { total_amount: 0, status: DrawdownStatus::default(), documents: None, + description: None, + feedback: None, created_date: timestamp, close_date: 0, }; @@ -876,6 +881,13 @@ impl Pallet { admin: T::AccountId, project_id: [u8;32], drawdown_id: [u8;32], + transactions: Option, // expenditure_id + Option, // amount + Option>, //Documents + CUDAction, // Action + Option<[u8;32]>, // transaction_id + ), T::MaxRegistrationsAtTime>>, ) -> DispatchResult { //ensure admin permissions Self::is_superuser(admin.clone(), &Self::get_global_scope(), ProxyRole::Administrator.id())?; @@ -886,25 +898,65 @@ impl Pallet { // Ensure drawdown is in submitted status ensure!(drawdown_data.status == DrawdownStatus::Submitted, Error::::DrawdownIsNotInSubmittedStatus); - // Get drawdown transactions - let drawdown_transactions = TransactionsByDrawdown::::try_get(project_id, drawdown_id).map_err(|_| Error::::DrawdownNotFound)?; + // Match drawdown type + match drawdown_data.drawdown_type { + DrawdownType::EB5 => { + // Ensure drawdown has transactions + ensure!(>::contains_key(project_id, drawdown_id), Error::::DrawdownHasNoTransactions); + + // Get drawdown transactions + let drawdown_transactions = TransactionsByDrawdown::::try_get(project_id, drawdown_id).map_err(|_| Error::::DrawdownNotFound)?; + + // Update each transaction status to approved + for transaction_id in drawdown_transactions { + // Get transaction data + let transaction_data = TransactionsInfo::::get(transaction_id).ok_or(Error::::TransactionNotFound)?; + + // Ensure transaction is in submitted status + ensure!(transaction_data.status == TransactionStatus::Submitted, Error::::TransactionIsNotInSubmittedStatus); + + // Update transaction status to approved + >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { + let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; + transaction_data.status = TransactionStatus::Approved; + Ok(()) + })?; + } + + }, + _ => { + // Ensure transactions is some + let mod_transactions = transactions.ok_or(Error::::NoTransactionsProvidedForBulkUpload)?; - // Update each transaction status to approved - for transaction_id in drawdown_transactions { - // Get transaction data - let transaction_data = TransactionsInfo::::get(transaction_id).ok_or(Error::::TransactionNotFound)?; + // Create transactions + for transaction in mod_transactions { + // Create transaction + Self::do_create_transaction( + project_id, + drawdown_id, + transaction.0.ok_or(Error::::ExpenditureIdRequired)?, + transaction.1.ok_or(Error::::AmountRequired)?, + transaction.2, + )?; + } - // Ensure transaction is in submitted status - ensure!(transaction_data.status == TransactionStatus::Submitted, Error::::TransactionIsNotInSubmittedStatus); + // Get drawdown transactions + let drawdown_transactions = TransactionsByDrawdown::::try_get(project_id, drawdown_id).map_err(|_| Error::::DrawdownNotFound)?; - // Update transaction status to approved - >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { - let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; - transaction_data.status = TransactionStatus::Approved; - Ok(()) - })?; + // Update each transaction status to approved + for transaction_id in drawdown_transactions { + // Update transaction status to approved + >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { + let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; + transaction_data.status = TransactionStatus::Approved; + Ok(()) + })?; + } + + }, } + // Update drawdown status >::try_mutate::<_,_,DispatchError,_>(drawdown_id, |drawdown_data| { let drawdown_data = drawdown_data.as_mut().ok_or(Error::::DrawdownNotFound)?; @@ -960,7 +1012,7 @@ impl Pallet { let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; transaction_data.feedback = Some(field_description); Ok(()) - })?; + }).map_err(|_| Error::::TransactionNotFound)?; } } @@ -1010,7 +1062,7 @@ impl Pallet { ensure!(!transactions.is_empty(), Error::::EmptyTransactions); }, } - + //Todo: create custom error to replace nonevalue error for transaction in transactions { match transaction.3 { @@ -1193,7 +1245,45 @@ impl Pallet { Ok(()) } + // B U L K U P L O A D T R A N S A C T I O N S + + pub fn do_bulk_upload( + _user: T::AccountId, //TODO: Remove underscore when permissions are implemented + project_id: [u8;32], + drawdown_id: [u8;32], + description: FieldDescription, + total_amount: u64, + documents: Documents, + ) -> DispatchResult { + // TODO: Ensure builder permissions + // Ensure project is not completed + Self::is_project_completed(project_id)?; + + // Ensure drawdown is not completed + Self::is_drawdown_editable(drawdown_id)?; + + // Ensure amount is valid + Self::is_amount_valid(total_amount)?; + + // Ensure documents is not empty + ensure!(!documents.is_empty(), Error::::DocumentsIsEmpty); + + // Ensure description is not empty + ensure!(!description.is_empty(), Error::::BulkUploadDescriptionRequired); + + // Mutate drawdown data + >::try_mutate::<_,_,DispatchError,_>(drawdown_id, |drawdown_data| { + let mod_drawdown_data = drawdown_data.as_mut().ok_or(Error::::DrawdownNotFound)?; + mod_drawdown_data.total_amount = total_amount; + mod_drawdown_data.description = Some(description); + mod_drawdown_data.documents = Some(documents); + mod_drawdown_data.status = DrawdownStatus::Submitted; + Ok(()) + })?; + + Ok(()) + } // H E L P E R S // -------------------------------------------------------------------------------------------- @@ -1448,7 +1538,7 @@ impl Pallet { fn is_project_completed( project_id: [u8;32], ) -> DispatchResult { - // Get project data + // Get project data & ensure project exists let project_data = ProjectsInfo::::get(project_id).ok_or(Error::::ProjectNotFound)?; // Ensure project is completed @@ -1461,10 +1551,10 @@ impl Pallet { fn is_drawdown_editable( drawdown_id: [u8;32], ) -> DispatchResult { - // Get drawdown data + // Get drawdown data & ensure drawdown exists let drawdown_data = DrawdownsInfo::::get(drawdown_id).ok_or(Error::::DrawdownNotFound)?; - // Ensure transaction is in draft or rejected status + // Ensure drawdown is in draft or rejected status // Match drawdown status match drawdown_data.status { DrawdownStatus::Draft => { diff --git a/pallets/proxy-financial/src/lib.rs b/pallets/proxy-financial/src/lib.rs index 3c43b6d3..ae2737a4 100644 --- a/pallets/proxy-financial/src/lib.rs +++ b/pallets/proxy-financial/src/lib.rs @@ -415,11 +415,18 @@ pub mod pallet { UserNameRequired, /// User role is required UserRoleRequired, + /// Amount is required + AmountRequired, /// Can not delete a user if the user is assigned to a project UserHasAssignedProjects, /// Can not send a drawdown to submitted status if it has no transactions NoTransactionsToSubmit, - + /// Bulk upload description is required + BulkUploadDescriptionRequired, + /// Administator can not delete themselves + AdministatorsCannotDeleteThemselves, + /// No transactions were provided for bulk upload + NoTransactionsProvidedForBulkUpload, } @@ -645,10 +652,17 @@ pub mod pallet { origin: OriginFor, project_id: [u8;32], drawdown_id: [u8;32], + transactions: Option, // expenditure_id + Option, // amount + Option>, //Documents + CUDAction, // Action + Option<[u8;32]>, // transaction_id + ), T::MaxRegistrationsAtTime>>, ) -> DispatchResult { let who = ensure_signed(origin)?; // origin need to be an admin - Self::do_approve_drawdown(who, project_id, drawdown_id) + Self::do_approve_drawdown(who, project_id, drawdown_id, transactions) } /// Reject a drawdown @@ -670,6 +684,23 @@ pub mod pallet { Self::do_reject_drawdown(who, project_id, drawdown_id, feedback) } + /// Bulk upload drawdowns + /// + /// This extrinsic is called by the builder + #[transactional] + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn bulkupload( + origin: OriginFor, + project_id: [u8;32], + drawdown_id: [u8;32], + description: FieldDescription, + total_amount: u64, + documents: Documents, + ) -> DispatchResult { + let who = ensure_signed(origin)?; // origin need to be a builder + + Self::do_bulk_upload(who, project_id, drawdown_id, description, total_amount, documents) + } From 5f4a57bd947cf33e01152fbbfa797050429b1e18 Mon Sep 17 00:00:00 2001 From: didiermis Date: Mon, 24 Oct 2022 12:21:04 -0500 Subject: [PATCH 4/9] Add feedback flow when a bulkupload is rejected --- pallets/proxy-financial/src/functions.rs | 82 +++++++++++++++--------- pallets/proxy-financial/src/lib.rs | 4 ++ 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/pallets/proxy-financial/src/functions.rs b/pallets/proxy-financial/src/functions.rs index fc0a2f16..d3cbf978 100644 --- a/pallets/proxy-financial/src/functions.rs +++ b/pallets/proxy-financial/src/functions.rs @@ -985,43 +985,67 @@ impl Pallet { // Ensure drawdown is in submitted status ensure!(drawdown_data.status == DrawdownStatus::Submitted, Error::::DrawdownIsNotInSubmittedStatus); - // Get drawdown transactions - let drawdown_transactions = TransactionsByDrawdown::::try_get(project_id, drawdown_id).map_err(|_| Error::::DrawdownNotFound)?; + match drawdown_data.drawdown_type { + DrawdownType::EB5 => { + // Ensure drawdown has transactions + ensure!(>::contains_key(project_id, drawdown_id), Error::::DrawdownHasNoTransactions); + + // Get drawdown transactions + let drawdown_transactions = TransactionsByDrawdown::::try_get(project_id, drawdown_id).map_err(|_| Error::::DrawdownNotFound)?; - // Update each transaction status to rejected - for transaction_id in drawdown_transactions { - // Get transaction data - let transaction_data = TransactionsInfo::::get(transaction_id).ok_or(Error::::TransactionNotFound)?; + // Update each transaction status to rejected + for transaction_id in drawdown_transactions { + // Get transaction data + let transaction_data = TransactionsInfo::::get(transaction_id).ok_or(Error::::TransactionNotFound)?; - // Ensure transaction is in submitted status - ensure!(transaction_data.status == TransactionStatus::Submitted, Error::::TransactionIsNotInSubmittedStatus); + // Ensure transaction is in submitted status + ensure!(transaction_data.status == TransactionStatus::Submitted, Error::::TransactionIsNotInSubmittedStatus); - // Update transaction status to rejected - >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { - let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; - transaction_data.status = TransactionStatus::Rejected; + // Update transaction status to rejected + >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { + let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; + transaction_data.status = TransactionStatus::Rejected; + Ok(()) + })?; + } + + // Update feedback if provided + if let Some(mod_feedback) = feedback.clone() { + for (transaction_id, field_description) in mod_feedback { + // Update transaction feedback + >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { + let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; + transaction_data.feedback = Some(field_description); + Ok(()) + }).map_err(|_| Error::::TransactionNotFound)?; + } + } + + // Update drawdown status + >::try_mutate::<_,_,DispatchError,_>(drawdown_id, |drawdown_data| { + let drawdown_data = drawdown_data.as_mut().ok_or(Error::::DrawdownNotFound)?; + drawdown_data.status = DrawdownStatus::Rejected; Ok(()) })?; - } + + }, + _ => { + // Ensure feedback is some + let mod_feedback = feedback.clone().ok_or(Error::::NoFeedbackProvidedForBulkUpload)?; + + // Ensure for bulkupload feedback provided len == 1 + ensure!(mod_feedback.len() == 1, Error::::FeedbackProvidedForBulkUploadShouldBeOne); - // Update feedback if provided - if let Some(mod_feedback) = feedback { - for (transaction_id, field_description) in mod_feedback { - // Update transaction feedback - >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { - let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; - transaction_data.feedback = Some(field_description); + // Update feedback for bulkupload. + >::try_mutate::<_,_,DispatchError,_>(drawdown_id, |drawdown_data| { + let drawdown_data = drawdown_data.as_mut().ok_or(Error::::DrawdownNotFound)?; + drawdown_data.feedback = Some(mod_feedback[0].1.clone()); + drawdown_data.status = DrawdownStatus::Rejected; Ok(()) - }).map_err(|_| Error::::TransactionNotFound)?; - } - } + })?; - // Update drawdown status - >::try_mutate::<_,_,DispatchError,_>(drawdown_id, |drawdown_data| { - let drawdown_data = drawdown_data.as_mut().ok_or(Error::::DrawdownNotFound)?; - drawdown_data.status = DrawdownStatus::Rejected; - Ok(()) - })?; + }, + } Ok(()) } diff --git a/pallets/proxy-financial/src/lib.rs b/pallets/proxy-financial/src/lib.rs index ae2737a4..3301113a 100644 --- a/pallets/proxy-financial/src/lib.rs +++ b/pallets/proxy-financial/src/lib.rs @@ -427,6 +427,10 @@ pub mod pallet { AdministatorsCannotDeleteThemselves, /// No transactions were provided for bulk upload NoTransactionsProvidedForBulkUpload, + /// No feedback was provided for bulk upload + NoFeedbackProvidedForBulkUpload, + /// Feedback provided for bulk upload should be one + FeedbackProvidedForBulkUploadShouldBeOne, } From 09c87b41a7afb887ad54a9128819751eb24f9505 Mon Sep 17 00:00:00 2001 From: didiermis Date: Mon, 24 Oct 2022 14:23:39 -0500 Subject: [PATCH 5/9] Update extrinsic & helper function names --- pallets/proxy-financial/src/functions.rs | 2 +- pallets/proxy-financial/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pallets/proxy-financial/src/functions.rs b/pallets/proxy-financial/src/functions.rs index d3cbf978..e2894488 100644 --- a/pallets/proxy-financial/src/functions.rs +++ b/pallets/proxy-financial/src/functions.rs @@ -1271,7 +1271,7 @@ impl Pallet { // B U L K U P L O A D T R A N S A C T I O N S - pub fn do_bulk_upload( + pub fn do_up_bulk_upload( _user: T::AccountId, //TODO: Remove underscore when permissions are implemented project_id: [u8;32], drawdown_id: [u8;32], diff --git a/pallets/proxy-financial/src/lib.rs b/pallets/proxy-financial/src/lib.rs index 3301113a..b8cdae5f 100644 --- a/pallets/proxy-financial/src/lib.rs +++ b/pallets/proxy-financial/src/lib.rs @@ -693,7 +693,7 @@ pub mod pallet { /// This extrinsic is called by the builder #[transactional] #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] - pub fn bulkupload( + pub fn up_bulkupload( origin: OriginFor, project_id: [u8;32], drawdown_id: [u8;32], @@ -703,7 +703,7 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; // origin need to be a builder - Self::do_bulk_upload(who, project_id, drawdown_id, description, total_amount, documents) + Self::do_up_bulk_upload(who, project_id, drawdown_id, description, total_amount, documents) } From 0e7a5242634707f240828daf07e55c8d63926ee1 Mon Sep 17 00:00:00 2001 From: didiermis Date: Tue, 25 Oct 2022 09:22:25 -0500 Subject: [PATCH 6/9] Update flow for each drawdown type: EB5, Construction Loan & Developer Equity. Fix 155. Fix 218 --- pallets/proxy-financial/src/functions.rs | 290 +++++++++-------------- pallets/proxy-financial/src/lib.rs | 96 +++++++- 2 files changed, 208 insertions(+), 178 deletions(-) diff --git a/pallets/proxy-financial/src/functions.rs b/pallets/proxy-financial/src/functions.rs index e2894488..0272e886 100644 --- a/pallets/proxy-financial/src/functions.rs +++ b/pallets/proxy-financial/src/functions.rs @@ -835,15 +835,18 @@ impl Pallet { Ok(()) } - fn do_submit_drawdown( + pub fn do_submit_drawdown( + _user: T::AccountId, //TODO: remove underscore when user permissions are implemented project_id: [u8;32], drawdown_id: [u8;32], ) -> DispatchResult { - // Get drawdown data & ensure drawdown exists - let drawdown_data = DrawdownsInfo::::get(drawdown_id).ok_or(Error::::DrawdownNotFound)?; + //TODO: Ensure builder permissions + + // Ensure project exists & is not completed + Self::is_project_completed(project_id)?; - // Ensure drawdown is in draft or rejected status - ensure!(drawdown_data.status == DrawdownStatus::Draft || drawdown_data.status == DrawdownStatus::Rejected, Error::::CannotSubmitDrawdown); + // Check if drawdown exists & is editable + Self::is_drawdown_editable(drawdown_id)?; // Ensure drawdown has transactions ensure!(>::contains_key(project_id, drawdown_id), Error::::DrawdownHasNoTransactions); @@ -874,6 +877,9 @@ impl Pallet { Ok(()) })?; + //Event + Self::deposit_event(Event::DrawdownSubmitted(drawdown_id)); + Ok(()) } @@ -881,13 +887,6 @@ impl Pallet { admin: T::AccountId, project_id: [u8;32], drawdown_id: [u8;32], - transactions: Option, // expenditure_id - Option, // amount - Option>, //Documents - CUDAction, // Action - Option<[u8;32]>, // transaction_id - ), T::MaxRegistrationsAtTime>>, ) -> DispatchResult { //ensure admin permissions Self::is_superuser(admin.clone(), &Self::get_global_scope(), ProxyRole::Administrator.id())?; @@ -898,65 +897,28 @@ impl Pallet { // Ensure drawdown is in submitted status ensure!(drawdown_data.status == DrawdownStatus::Submitted, Error::::DrawdownIsNotInSubmittedStatus); - // Match drawdown type - match drawdown_data.drawdown_type { - DrawdownType::EB5 => { - // Ensure drawdown has transactions - ensure!(>::contains_key(project_id, drawdown_id), Error::::DrawdownHasNoTransactions); - - // Get drawdown transactions - let drawdown_transactions = TransactionsByDrawdown::::try_get(project_id, drawdown_id).map_err(|_| Error::::DrawdownNotFound)?; - - // Update each transaction status to approved - for transaction_id in drawdown_transactions { - // Get transaction data - let transaction_data = TransactionsInfo::::get(transaction_id).ok_or(Error::::TransactionNotFound)?; - - // Ensure transaction is in submitted status - ensure!(transaction_data.status == TransactionStatus::Submitted, Error::::TransactionIsNotInSubmittedStatus); - - // Update transaction status to approved - >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { - let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; - transaction_data.status = TransactionStatus::Approved; - Ok(()) - })?; - } - - }, - _ => { - // Ensure transactions is some - let mod_transactions = transactions.ok_or(Error::::NoTransactionsProvidedForBulkUpload)?; - - // Create transactions - for transaction in mod_transactions { - // Create transaction - Self::do_create_transaction( - project_id, - drawdown_id, - transaction.0.ok_or(Error::::ExpenditureIdRequired)?, - transaction.1.ok_or(Error::::AmountRequired)?, - transaction.2, - )?; - } + // Ensure drawdown has transactions + ensure!(>::contains_key(project_id, drawdown_id), Error::::DrawdownHasNoTransactions); + + // Get drawdown transactions + let drawdown_transactions = TransactionsByDrawdown::::try_get(project_id, drawdown_id).map_err(|_| Error::::DrawdownNotFound)?; - // Get drawdown transactions - let drawdown_transactions = TransactionsByDrawdown::::try_get(project_id, drawdown_id).map_err(|_| Error::::DrawdownNotFound)?; + // Update each transaction status to approved + for transaction_id in drawdown_transactions { + // Get transaction data + let transaction_data = TransactionsInfo::::get(transaction_id).ok_or(Error::::TransactionNotFound)?; - // Update each transaction status to approved - for transaction_id in drawdown_transactions { - // Update transaction status to approved - >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { - let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; - transaction_data.status = TransactionStatus::Approved; - Ok(()) - })?; - } + // Ensure transaction is in submitted status + ensure!(transaction_data.status == TransactionStatus::Submitted, Error::::TransactionIsNotInSubmittedStatus); - }, + // Update transaction status to approved + >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { + let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; + transaction_data.status = TransactionStatus::Approved; + Ok(()) + })?; } - // Update drawdown status >::try_mutate::<_,_,DispatchError,_>(drawdown_id, |drawdown_data| { let drawdown_data = drawdown_data.as_mut().ok_or(Error::::DrawdownNotFound)?; @@ -967,14 +929,18 @@ impl Pallet { // Generate the next drawdown Self::do_create_drawdown(project_id, drawdown_data.drawdown_type, drawdown_data.drawdown_number + 1)?; + // Event + Self::deposit_event(Event::DrawdownApproved(drawdown_id)); Ok(()) } + pub fn do_reject_drawdown( admin: T::AccountId, project_id: [u8;32], drawdown_id: [u8;32], - feedback: Option>, + transactions_feedback: Option>, + drawdown_feedback: Option>, ) -> DispatchResult { //ensure admin permissions Self::is_superuser(admin.clone(), &Self::get_global_scope(), ProxyRole::Administrator.id())?; @@ -985,68 +951,67 @@ impl Pallet { // Ensure drawdown is in submitted status ensure!(drawdown_data.status == DrawdownStatus::Submitted, Error::::DrawdownIsNotInSubmittedStatus); - match drawdown_data.drawdown_type { - DrawdownType::EB5 => { - // Ensure drawdown has transactions - ensure!(>::contains_key(project_id, drawdown_id), Error::::DrawdownHasNoTransactions); - - // Get drawdown transactions - let drawdown_transactions = TransactionsByDrawdown::::try_get(project_id, drawdown_id).map_err(|_| Error::::DrawdownNotFound)?; - - // Update each transaction status to rejected - for transaction_id in drawdown_transactions { - // Get transaction data - let transaction_data = TransactionsInfo::::get(transaction_id).ok_or(Error::::TransactionNotFound)?; - - // Ensure transaction is in submitted status - ensure!(transaction_data.status == TransactionStatus::Submitted, Error::::TransactionIsNotInSubmittedStatus); - - // Update transaction status to rejected - >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { - let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; - transaction_data.status = TransactionStatus::Rejected; - Ok(()) - })?; - } + // Ensure drawdown has transactions + ensure!(>::contains_key(project_id, drawdown_id), Error::::DrawdownHasNoTransactions); + + // Get drawdown transactions + let drawdown_transactions = TransactionsByDrawdown::::try_get(project_id, drawdown_id).map_err(|_| Error::::DrawdownNotFound)?; - // Update feedback if provided - if let Some(mod_feedback) = feedback.clone() { - for (transaction_id, field_description) in mod_feedback { - // Update transaction feedback - >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { - let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; - transaction_data.feedback = Some(field_description); - Ok(()) - }).map_err(|_| Error::::TransactionNotFound)?; - } - } + // Update each transaction status to rejected + for transaction_id in drawdown_transactions { + // Get transaction data + let transaction_data = TransactionsInfo::::get(transaction_id).ok_or(Error::::TransactionNotFound)?; + + // Ensure transaction is in submitted status + ensure!(transaction_data.status == TransactionStatus::Submitted, Error::::TransactionIsNotInSubmittedStatus); - // Update drawdown status - >::try_mutate::<_,_,DispatchError,_>(drawdown_id, |drawdown_data| { - let drawdown_data = drawdown_data.as_mut().ok_or(Error::::DrawdownNotFound)?; - drawdown_data.status = DrawdownStatus::Rejected; + // Update transaction status to rejected + >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { + let transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; + transaction_data.status = TransactionStatus::Rejected; Ok(()) })?; - + } + + // Match drawdown type in order to provide a feedback + match drawdown_data.drawdown_type { + DrawdownType::EB5 => { + // Ensure transactions_feedback is some + let mod_transactions_feedback = transactions_feedback.ok_or(Error::::EB5FeebackMissing)?; + + for (transaction_id, field_description) in mod_transactions_feedback { + // Update transaction feedback + >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_info| { + let transaction_data = transaction_info.as_mut().ok_or(Error::::TransactionNotFound)?; + transaction_data.feedback = Some(field_description); + Ok(()) + }).map_err(|_| Error::::TransactionNotFound)?; + } + }, _ => { - // Ensure feedback is some - let mod_feedback = feedback.clone().ok_or(Error::::NoFeedbackProvidedForBulkUpload)?; - - // Ensure for bulkupload feedback provided len == 1 - ensure!(mod_feedback.len() == 1, Error::::FeedbackProvidedForBulkUploadShouldBeOne); + // Ensure drawdown_feedback is some + let mod_drawdown_feedback = drawdown_feedback.clone().ok_or(Error::::NoFeedbackProvidedForBulkUpload)?; // Update feedback for bulkupload. >::try_mutate::<_,_,DispatchError,_>(drawdown_id, |drawdown_data| { let drawdown_data = drawdown_data.as_mut().ok_or(Error::::DrawdownNotFound)?; - drawdown_data.feedback = Some(mod_feedback[0].1.clone()); - drawdown_data.status = DrawdownStatus::Rejected; + drawdown_data.feedback = Some(mod_drawdown_feedback[0].clone()); Ok(()) })?; - }, } + // Update drawdown status + >::try_mutate::<_,_,DispatchError,_>(drawdown_id, |drawdown_data| { + let drawdown_data = drawdown_data.as_mut().ok_or(Error::::DrawdownNotFound)?; + drawdown_data.status = DrawdownStatus::Rejected; + Ok(()) + })?; + + //Event + Self::deposit_event(Event::DrawdownRejected(drawdown_id)); + Ok(()) } @@ -1054,7 +1019,6 @@ impl Pallet { // T R A N S A C T I O N S // -------------------------------------------------------------------------------------------- // For now transactions functions are private, but in the future they may be public - pub fn do_execute_transactions( _user: T::AccountId, //TODO: remove underscore when permissions are implemented project_id: [u8;32], @@ -1066,28 +1030,22 @@ impl Pallet { CUDAction, // Action Option<[u8;32]>, // transaction_id ), T::MaxRegistrationsAtTime>, - submit: bool, ) -> DispatchResult { // Check permissions here so helper private functions doesn't need to check it // TODO: Ensure admin & builder permissions - // Ensure project exists so helper private functions doesn't need to check it - ensure!(ProjectsInfo::::contains_key(project_id), Error::::ProjectNotFound); + // Ensure project exists & is not completed so helper private functions doesn't need to check it + Self::is_project_completed(project_id)?; //Ensure drawdown exists so helper private functions doesn't need to check it ensure!(DrawdownsInfo::::contains_key(drawdown_id), Error::::DrawdownNotFound); // Ensure transactions are not empty - match submit { - true => { - ensure!(TransactionsByDrawdown::::contains_key(project_id, drawdown_id), Error::::NoTransactionsToSubmit); - }, - false => { - ensure!(!transactions.is_empty(), Error::::EmptyTransactions); - }, - } + ensure!(!transactions.is_empty(), Error::::EmptyTransactions); + + // Ensure if drawdown is editable + Self::is_drawdown_editable(drawdown_id)?; - //Todo: create custom error to replace nonevalue error for transaction in transactions { match transaction.3 { CUDAction::Create => { @@ -1095,8 +1053,8 @@ impl Pallet { Self::do_create_transaction( project_id, drawdown_id, - transaction.0.ok_or(Error::::NoneValue)?, - transaction.1.ok_or(Error::::NoneValue)?, + transaction.0.ok_or(Error::::ExpenditureIdRequired)?, + transaction.1.ok_or(Error::::AmountRequired)?, transaction.2, )?; }, @@ -1118,14 +1076,9 @@ impl Pallet { } - // Update total amount of the drawdown + // Update total amount for the given drawdown Self::do_calculate_drawdown_total_amount(project_id, drawdown_id)?; - // If submit is true, submit drawdown to be approved - if submit == true { - Self::do_submit_drawdown(project_id, drawdown_id)?; - } - Self::deposit_event(Event::TransactionsCompleted); Ok(()) } @@ -1137,11 +1090,6 @@ impl Pallet { amount: u64, documents: Option>, ) -> DispatchResult { - // TODO:Ensure builder permissions - - // Ensure drawdown exists - ensure!(DrawdownsInfo::::contains_key(drawdown_id), Error::::DrawdownNotFound); - // Ensure amount is valid Self::is_amount_valid(amount)?; @@ -1205,20 +1153,11 @@ impl Pallet { // Get timestamp let timestamp = Self::get_timestamp_in_milliseconds().ok_or(Error::::TimestampError)?; - - // Ensure transaction is not completed - Self::is_transaction_editable(transaction_id)?; // Try mutate transaction data >::try_mutate::<_,_,DispatchError,_>(transaction_id, |transaction_data| { let mod_transaction_data = transaction_data.as_mut().ok_or(Error::::TransactionNotFound)?; - // Ensure project is not completed - Self::is_project_completed(mod_transaction_data.project_id)?; - - // Ensure drawdown is not completed - Self::is_drawdown_editable(mod_transaction_data.drawdown_id)?; - // Ensure expenditure exists ensure!(ExpendituresInfo::::contains_key(mod_transaction_data.expenditure_id), Error::::ExpenditureNotFound); @@ -1245,9 +1184,6 @@ impl Pallet { // Ensure transaction exists and get transaction data let transaction_data = TransactionsInfo::::get(transaction_id).ok_or(Error::::TransactionNotFound)?; - // Ensure project is not completed - Self::is_project_completed(transaction_data.project_id)?; - // Ensure drawdown is not completed ensure!(Self::is_drawdown_editable(transaction_data.drawdown_id).is_ok(), Error::::DrawdownIsAlreadyCompleted); @@ -1578,17 +1514,33 @@ impl Pallet { // Get drawdown data & ensure drawdown exists let drawdown_data = DrawdownsInfo::::get(drawdown_id).ok_or(Error::::DrawdownNotFound)?; - // Ensure drawdown is in draft or rejected status - // Match drawdown status - match drawdown_data.status { - DrawdownStatus::Draft => { - return Ok(()) - }, - DrawdownStatus::Rejected => { - return Ok(()) + // Match drawdown type + match drawdown_data.drawdown_type { + DrawdownType::EB5 => { + // Match drawdown status + // Ensure drawdown is in draft or rejected status + match drawdown_data.status { + DrawdownStatus::Draft => { + return Ok(()) + }, + DrawdownStatus::Rejected => { + return Ok(()) + }, + _ => { + return Err(Error::::CannotEditDrawdown.into()); + } + } }, _ => { - return Err(Error::::CannotEditDrawdown.into()); + // Match drawdown status + match drawdown_data.status { + DrawdownStatus::Approved => { + return Err(Error::::CannotEditDrawdown.into()); + }, + _ => { + return Ok(()) + }, + } } } } @@ -1603,14 +1555,11 @@ impl Pallet { // Ensure transaction is in draft or rejected status // Match transaction status match transaction_data.status { - TransactionStatus::Draft => { - return Ok(()) - }, - TransactionStatus::Rejected => { - return Ok(()) + TransactionStatus::Approved => { + return Err(Error::::CannotEditTransaction.into()); }, _ => { - return Err(Error::::CannotEditTransaction.into()); + return Ok(()) } } } @@ -1703,10 +1652,7 @@ impl Pallet { Ok(()) })?; - Ok(()) + Ok(()) } - - - -} \ No newline at end of file +} diff --git a/pallets/proxy-financial/src/lib.rs b/pallets/proxy-financial/src/lib.rs index b8cdae5f..f904d648 100644 --- a/pallets/proxy-financial/src/lib.rs +++ b/pallets/proxy-financial/src/lib.rs @@ -277,6 +277,12 @@ pub mod pallet { UsersExecuted, /// Assign users extrinsic was completed successfully UsersAssignationExecuted([u8;32]), + /// Drawdown was submitted successfully + DrawdownSubmitted([u8;32]), + /// Drawdown was approved successfully + DrawdownApproved([u8;32]), + /// Drawdown was rejected successfully + DrawdownRejected([u8;32]), } @@ -431,6 +437,10 @@ pub mod pallet { NoFeedbackProvidedForBulkUpload, /// Feedback provided for bulk upload should be one FeedbackProvidedForBulkUploadShouldBeOne, + /// Bulkupdate param is missed to execute a bulkupload drawdown + BulkUpdateIsRequired, + /// NO feedback for EN5 drawdown was provided + EB5FeebackMissing, } @@ -631,18 +641,46 @@ pub mod pallet { origin: OriginFor, project_id: [u8;32], drawdown_id: [u8;32], - transactions: BoundedVec<( + transactions: Option, // expenditure_id Option, // amount Option>, //Documents CUDAction, // Action Option<[u8;32]>, // transaction_id - ), T::MaxRegistrationsAtTime>, + ), T::MaxRegistrationsAtTime>>, submit: bool, ) -> DispatchResult { let who = ensure_signed(origin)?; // origin need to be an admin + + match submit{ + false => { + // Do execute transactions + Self::do_execute_transactions( + who, + project_id, + drawdown_id, + transactions.ok_or(Error::::EmptyTransactions)?, + ) + }, + true => { + // Check if there's transactions to execute + if let Some(transactions) = transactions { + // Do execute transactions + Self::do_execute_transactions( + who.clone(), + project_id, + drawdown_id, + transactions, + )?; + } + + // Do submit drawdown + Self::do_submit_drawdown(who, project_id, drawdown_id) + // - ensure drawdown has transactions + //ensure!(TransactionsByDrawdown::::contains_key(project_id, drawdown_id), Error::::NoTransactionsToSubmit); + }, + } - Self::do_execute_transactions(who, project_id, drawdown_id, transactions, submit) } /// Approve a drawdown @@ -656,6 +694,7 @@ pub mod pallet { origin: OriginFor, project_id: [u8;32], drawdown_id: [u8;32], + bulkupdate: Option, transactions: Option, // expenditure_id Option, // amount @@ -666,7 +705,51 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; // origin need to be an admin - Self::do_approve_drawdown(who, project_id, drawdown_id, transactions) + // Match bulkupdate + match bulkupdate { + Some(approval) => { + // Execute bulkupload flow (construction loan & developer equity) + match approval { + false => { + // 1. Do execute transactions + Self::do_execute_transactions( + who.clone(), + project_id, + drawdown_id, + transactions.ok_or(Error::::EmptyTransactions)?, + )?; + + // 2. Do submit drawdown + Self::do_submit_drawdown(who, project_id, drawdown_id) + + }, + true => { + // 1.Execute transactions if provided + if let Some(transactions) = transactions { + // Do execute transactions + Self::do_execute_transactions( + who.clone(), + project_id, + drawdown_id, + transactions, + )?; + + // 2. Submit drawdown + Self::do_submit_drawdown(who.clone(), project_id, drawdown_id)?; + } + + // 3. Approve drawdown + Self::do_approve_drawdown(who, project_id, drawdown_id) + }, + } + + }, + None => { + // Execute normal flow (EB5) + Self::do_approve_drawdown(who, project_id, drawdown_id) + } + } + } /// Reject a drawdown @@ -681,11 +764,12 @@ pub mod pallet { origin: OriginFor, project_id: [u8;32], drawdown_id: [u8;32], - feedback: Option>, + transactions_feedback: Option>, + drawdown_feedback: Option>, ) -> DispatchResult { let who = ensure_signed(origin)?; // origin need to be an admin - Self::do_reject_drawdown(who, project_id, drawdown_id, feedback) + Self::do_reject_drawdown(who, project_id, drawdown_id, transactions_feedback, drawdown_feedback) } /// Bulk upload drawdowns From 521d7ee112d1f5a0f7fef42f3c5c769b5fd77a13 Mon Sep 17 00:00:00 2001 From: didiermis Date: Tue, 25 Oct 2022 11:11:54 -0500 Subject: [PATCH 7/9] Add a kill_storage extrinsic. Fix 195 --- pallets/proxy-financial/src/lib.rs | 34 +++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/pallets/proxy-financial/src/lib.rs b/pallets/proxy-financial/src/lib.rs index f904d648..979ff2a9 100644 --- a/pallets/proxy-financial/src/lib.rs +++ b/pallets/proxy-financial/src/lib.rs @@ -123,7 +123,7 @@ pub mod pallet { #[pallet::getter(fn global_scope)] pub(super) type GlobalScope = StorageValue< _, - [u8;32], // Value gobal scope id + [u8;32], // Value global scope id ValueQuery >; @@ -790,6 +790,38 @@ pub mod pallet { Self::do_up_bulk_upload(who, project_id, drawdown_id, description, total_amount, documents) } + /// Kill all the stored data. + /// + /// This function is used to kill ALL the stored data. + /// Use it with caution! + /// + /// ### Parameters: + /// - `origin`: The user who performs the action. + /// + /// ### Considerations: + /// - This function is only available to the `admin` with sudo access. + #[transactional] + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn kill_storage( + origin: OriginFor, + ) -> DispatchResult{ + T::RemoveOrigin::ensure_origin(origin.clone())?; + let _ = >::kill(); + let _ = >::clear(1000, None); + let _ = >::clear(1000, None); + let _ = >::clear(1000, None); + let _ = >::clear(1000, None); + let _ = >::clear(1000, None); + let _ = >::clear(1000, None); + let _ = >::clear(1000, None); + let _ = >::clear(1000, None); + let _ = >::clear(1000, None); + let _ = >::clear(1000, None); + + T::Rbac::remove_pallet_storage(Self::pallet_id())?; + Ok(()) + } + // /// Testing extrinsic From 1b42541a1c2f9946aeef0a5138a1207471e12438 Mon Sep 17 00:00:00 2001 From: didiermis Date: Tue, 25 Oct 2022 12:21:13 -0500 Subject: [PATCH 8/9] Add optional field inflation_rate into ProjectData structure --- pallets/proxy-financial/src/types.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pallets/proxy-financial/src/types.rs b/pallets/proxy-financial/src/types.rs index e238a7c1..1b00fe2e 100644 --- a/pallets/proxy-financial/src/types.rs +++ b/pallets/proxy-financial/src/types.rs @@ -23,6 +23,7 @@ pub struct ProjectData { pub image: CID, pub address: FieldName, pub status: ProjectStatus, + pub inflation_rate: Option, pub creation_date: u64, pub completion_date: u64, pub registration_date: u64, From a9aeda21f8f68e1368eec59ae51f9030c3913afa Mon Sep 17 00:00:00 2001 From: didiermis Date: Tue, 25 Oct 2022 15:59:20 -0500 Subject: [PATCH 9/9] Add flow for inflation adjustment. Multiple actions allowed at a time for different projects. Fix 196 --- pallets/proxy-financial/src/functions.rs | 48 +++++++++++++++++++++++- pallets/proxy-financial/src/lib.rs | 23 ++++++++++-- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/pallets/proxy-financial/src/functions.rs b/pallets/proxy-financial/src/functions.rs index 0272e886..6bb82ae2 100644 --- a/pallets/proxy-financial/src/functions.rs +++ b/pallets/proxy-financial/src/functions.rs @@ -141,6 +141,7 @@ impl Pallet { image, address, status: ProjectStatus::default(), + inflation_rate: None, registration_date: timestamp, creation_date, completion_date, @@ -840,7 +841,7 @@ impl Pallet { project_id: [u8;32], drawdown_id: [u8;32], ) -> DispatchResult { - //TODO: Ensure builder permissions + //TODO: Ensure builder & admin permissions // Ensure project exists & is not completed Self::is_project_completed(project_id)?; @@ -1245,6 +1246,51 @@ impl Pallet { Ok(()) } + // I N F L A T I O N A D J U S T M E N T + // -------------------------------------------------------------------------------------------- + pub fn do_execute_inflation_adjustment( + admin: T::AccountId, + projects: BoundedVec<([u8;32], Option, CUDAction), T::MaxRegistrationsAtTime>, + ) -> DispatchResult { + // Ensure admin permissions + Self::is_superuser(admin.clone(), &Self::get_global_scope(), ProxyRole::Administrator.id())?; + + // Ensure projects is not empty + ensure!(!projects.is_empty(), Error::::ProjectsIsEmpty); + + // Match each CUD action + for project in projects { + // Ensure project exists + ensure!(ProjectsInfo::::contains_key(project.0), Error::::ProjectNotFound); + match project.2 { + // Delete need: project_id + CUDAction::Delete => { + // Mutate project data + >::try_mutate::<_,_,DispatchError,_>(project.0, |project_info| { + let mod_project_data = project_info.as_mut().ok_or(Error::::ProjectNotFound)?; + mod_project_data.inflation_rate = None; + Ok(()) + })?; + }, + // Creation & Update need: project_id, inflation_rate + _ => { + // Mutate project data + + // Ensure inflation rate is provided + let inflation_rate = project.1.ok_or(Error::::InflationRateRequired)?; + + >::try_mutate::<_,_,DispatchError,_>(project.0, |project_info| { + let mod_project_data = project_info.as_mut().ok_or(Error::::ProjectNotFound)?; + mod_project_data.inflation_rate = Some(inflation_rate); + Ok(()) + })?; + }, + } + } + + Ok(()) + } + // H E L P E R S // -------------------------------------------------------------------------------------------- diff --git a/pallets/proxy-financial/src/lib.rs b/pallets/proxy-financial/src/lib.rs index 979ff2a9..b97679d7 100644 --- a/pallets/proxy-financial/src/lib.rs +++ b/pallets/proxy-financial/src/lib.rs @@ -441,6 +441,10 @@ pub mod pallet { BulkUpdateIsRequired, /// NO feedback for EN5 drawdown was provided EB5FeebackMissing, + /// Inflation rate extrinsic is missing an array of changes + ProjectsIsEmpty, + /// Inflation rate was not provided + InflationRateRequired, } @@ -676,8 +680,6 @@ pub mod pallet { // Do submit drawdown Self::do_submit_drawdown(who, project_id, drawdown_id) - // - ensure drawdown has transactions - //ensure!(TransactionsByDrawdown::::contains_key(project_id, drawdown_id), Error::::NoTransactionsToSubmit); }, } @@ -790,6 +792,21 @@ pub mod pallet { Self::do_up_bulk_upload(who, project_id, drawdown_id, description, total_amount, documents) } + /// Modify inflation rate + /// + /// projects: project_id, inflation_rate, CUDAction + #[transactional] + #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] + pub fn inflation_rate( + origin: OriginFor, + projects: BoundedVec<([u8;32], Option, CUDAction), T::MaxRegistrationsAtTime>, + ) -> DispatchResult { + let who = ensure_signed(origin)?; // origin need to be a builder + + Self::do_execute_inflation_adjustment(who, projects) + } + + /// Kill all the stored data. /// /// This function is used to kill ALL the stored data. @@ -822,8 +839,6 @@ pub mod pallet { Ok(()) } - - // /// Testing extrinsic // #[transactional] // #[pallet::weight(10_000 + T::DbWeight::get().writes(1))]