Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vstam1/simplifications #358

Merged
merged 7 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions pallets/funding/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ Basic flow of a project's lifecycle:
| Closing Auction Transition | After the [`Config::AuctionOpeningDuration`] has passed, the auction goes into closing mode thanks to [`on_initialize()`](Pallet::on_initialize) | [`AuctionClosing`](ProjectStatus::AuctionClosing) |
| Bid Submissions | Institutional and Professional users can continue bidding, but this time their bids will only be considered, if they managed to fall before the random ending block calculated at the end of the auction. | [`AuctionClosing`](ProjectStatus::AuctionClosing) |
| Community Funding Start | After the [`Config::AuctionClosingDuration`] has passed, the auction automatically. A final token price for the next rounds is calculated based on the accepted bids. | [`CommunityRound`](ProjectStatus::CommunityRound) |
| Funding Submissions | Retail investors can call the [`contribute()`](Pallet::contribute) extrinsic to buy tokens at the set price. | [`CommunityRound`](ProjectStatus::CommunityRound) |
| Remainder Funding Start | After the [`Config::CommunityFundingDuration`] has passed, the project is now open to token purchases from any user type | [`RemainderRound`](ProjectStatus::RemainderRound) |
| Funding Submissions | Retail investors can call the [`contribute()`](Pallet::contribute) extrinsic to buy tokens at the set price. | [`CommunityRound`](ProjectStatus::CommunityRound) | |
| Funding End | If all tokens were sold, or after the [`Config::RemainderFundingDuration`] has passed, the project automatically ends, and it is calculated if it reached its desired funding or not. | [`FundingEnded`](ProjectStatus::FundingEnded) |
| Evaluator Rewards | If the funding was successful, evaluators can claim their contribution token rewards with the [`TBD`]() extrinsic. If it failed, evaluators can either call the [`failed_evaluation_unbond_for()`](Pallet::failed_evaluation_unbond_for) extrinsic, or wait for the [`on_idle()`](Pallet::on_initialize) function, to return their funds | [`FundingEnded`](ProjectStatus::FundingEnded) |
| Bidder Rewards | If the funding was successful, bidders will call [`vested_contribution_token_bid_mint_for()`](Pallet::vested_contribution_token_bid_mint_for) to mint the contribution tokens they are owed, and [`vested_plmc_bid_unbond_for()`](Pallet::vested_plmc_bid_unbond_for) to unbond their PLMC, based on their current vesting schedule. | [`FundingEnded`](ProjectStatus::FundingEnded) |
Expand Down Expand Up @@ -89,8 +88,6 @@ on the KILT parachain, by a KYC/AML provider.
- `Projects`: Map of the assigned id, to the main information of a project.
- `ProjectsInfo`: Map of a project id, to some additional information required
for ensuring correctness of the protocol.
- `ProjectsToUpdate`: Map of a block number, to a vector of project ids. Used to
keep track of projects that need to be updated in on_initialize.
- `AuctionsInfo`: Double map linking a project-user to the bids they made.
- `EvaluationBonds`: Double map linking a project-user to the PLMC they bonded
in the evaluation round.
Expand Down
23 changes: 5 additions & 18 deletions pallets/funding/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ mod benchmarks {
);

#[extrinsic_call]
community_contribute(
contribute(
RawOrigin::Signed(extrinsic_contribution.contributor.clone()),
jwt,
project_id,
Expand Down Expand Up @@ -1344,7 +1344,7 @@ mod benchmarks {
);

#[extrinsic_call]
community_contribute(
contribute(
RawOrigin::Signed(extrinsic_contribution.contributor.clone()),
jwt,
project_id,
Expand Down Expand Up @@ -1435,11 +1435,6 @@ mod benchmarks {
let maybe_transition =
inst.get_update_block(project_id, &UpdateType::ProjectDecision(FundingOutcomeDecision::AcceptFunding));
assert!(maybe_transition.is_some());

// Events
frame_system::Pallet::<T>::assert_last_event(
Event::ProjectOutcomeDecided { project_id, decision: FundingOutcomeDecision::AcceptFunding }.into(),
);
}

#[benchmark]
Expand Down Expand Up @@ -2109,13 +2104,13 @@ mod benchmarks {

#[block]
{
Pallet::<T>::do_end_auction_closing(project_id).unwrap();
Pallet::<T>::do_end_auction(project_id).unwrap();
}

// * validity checks *
// Storage
let stored_details = ProjectsDetails::<T>::get(project_id).unwrap();
assert_eq!(stored_details.status, ProjectStatus::CalculatingWAP);
assert_eq!(stored_details.status, ProjectStatus::CommunityRound);
assert!(
stored_details.phase_transition_points.random_closing_ending.unwrap() <
stored_details.phase_transition_points.auction_closing.end().unwrap()
Expand Down Expand Up @@ -2311,7 +2306,6 @@ mod benchmarks {
// * validity checks *
// Storage
let stored_details = ProjectsDetails::<T>::get(project_id).unwrap();
assert_eq!(stored_details.status, ProjectStatus::RemainderRound);

// Events
frame_system::Pallet::<T>::assert_last_event(
Expand Down Expand Up @@ -2362,7 +2356,6 @@ mod benchmarks {
);

let project_details = inst.get_project_details(project_id);
assert_eq!(project_details.status, ProjectStatus::RemainderRound);
let last_funding_block = project_details.phase_transition_points.remainder.end().unwrap();

frame_system::Pallet::<T>::set_block_number(last_funding_block + 1u32.into());
Expand Down Expand Up @@ -2421,7 +2414,6 @@ mod benchmarks {
);

let project_details = inst.get_project_details(project_id);
assert_eq!(project_details.status, ProjectStatus::RemainderRound);
let last_funding_block = project_details.phase_transition_points.remainder.end().unwrap();

frame_system::Pallet::<T>::set_block_number(last_funding_block + 1u32.into());
Expand All @@ -2436,7 +2428,7 @@ mod benchmarks {

// * validity checks *
let project_details = inst.get_project_details(project_id);
assert_eq!(project_details.status, ProjectStatus::AwaitingProjectDecision);

assert_eq!(project_details.evaluation_round_info.evaluators_outcome, EvaluatorsOutcome::Slashed)
}
#[benchmark]
Expand Down Expand Up @@ -2481,7 +2473,6 @@ mod benchmarks {
);

let project_details = inst.get_project_details(project_id);
assert_eq!(project_details.status, ProjectStatus::RemainderRound);
let last_funding_block = project_details.phase_transition_points.remainder.end().unwrap();

frame_system::Pallet::<T>::set_block_number(last_funding_block + 1u32.into());
Expand All @@ -2496,7 +2487,6 @@ mod benchmarks {

// * validity checks *
let project_details = inst.get_project_details(project_id);
assert_eq!(project_details.status, ProjectStatus::AwaitingProjectDecision);
assert_eq!(project_details.evaluation_round_info.evaluators_outcome, EvaluatorsOutcome::Unchanged)
}
#[benchmark]
Expand Down Expand Up @@ -2559,7 +2549,6 @@ mod benchmarks {
);

let project_details = inst.get_project_details(project_id);
assert_eq!(project_details.status, ProjectStatus::RemainderRound);
let last_funding_block = project_details.phase_transition_points.remainder.end().unwrap();

frame_system::Pallet::<T>::set_block_number(last_funding_block + 1u32.into());
Expand Down Expand Up @@ -2616,8 +2605,6 @@ mod benchmarks {
vec![],
);

assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::AwaitingProjectDecision);

#[block]
{
Pallet::<T>::do_project_decision(project_id, FundingOutcomeDecision::AcceptFunding).unwrap();
Expand Down
6 changes: 2 additions & 4 deletions pallets/funding/src/functions/1_application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ impl<T: Config> Pallet<T> {
}
let total_allocation_size = project_metadata.total_allocation_size;

// * Calculate new variables *
let now = <frame_system::Pallet<T>>::block_number();

let fundraising_target =
project_metadata.minimum_price.checked_mul_int(total_allocation_size).ok_or(Error::<T>::BadMath)?;

Expand All @@ -36,7 +33,8 @@ impl<T: Config> Pallet<T> {
weighted_average_price: None,
fundraising_target_usd: fundraising_target,
status: ProjectStatus::Application,
phase_transition_points: PhaseTransitionPoints::new(now),
round_duration: BlockNumberPair::new(None, None),
random_end_block: None,
remaining_contribution_tokens: project_metadata.total_allocation_size,
funding_amount_reached_usd: BalanceOf::<T>::zero(),
evaluation_round_info: EvaluationRoundInfoOf::<T> {
Expand Down
130 changes: 33 additions & 97 deletions pallets/funding/src/functions/2_evaluation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ impl<T: Config> Pallet<T> {
///
/// # Storage access
/// * [`ProjectsDetails`] - Checking and updating the round status, transition points and freezing the project.
/// * [`ProjectsToUpdate`] - Scheduling the project for automatic transition by on_initialize later on.
///
/// # Success path
/// The project information is found, its round status was in Application round, and It's not yet frozen.
Expand All @@ -19,49 +18,28 @@ impl<T: Config> Pallet<T> {
/// Users will pond PLMC for this project, and when the time comes, the project will be transitioned
/// to the next round by `on_initialize` using [`do_evaluation_end`](Self::do_evaluation_end)
#[transactional]
pub fn do_start_evaluation(caller: AccountIdOf<T>, project_id: ProjectId) -> DispatchResultWithPostInfo {
pub fn do_start_evaluation(caller: AccountIdOf<T>, project_id: ProjectId) -> DispatchResult {
// * Get variables *
let project_metadata = ProjectsMetadata::<T>::get(project_id).ok_or(Error::<T>::ProjectMetadataNotFound)?;
let mut project_details = ProjectsDetails::<T>::get(project_id).ok_or(Error::<T>::ProjectDetailsNotFound)?;
let now = <frame_system::Pallet<T>>::block_number();


// * Validity checks *
ensure!(project_details.issuer_account == caller, Error::<T>::NotIssuer);
ensure!(project_details.status == ProjectStatus::Application, Error::<T>::IncorrectRound);
ensure!(!project_details.is_frozen, Error::<T>::ProjectAlreadyFrozen);
ensure!(project_metadata.policy_ipfs_cid.is_some(), Error::<T>::CidNotProvided);

// * Calculate new variables *
let evaluation_end_block = now.saturating_add(T::EvaluationDuration::get()).saturating_sub(One::one());
project_details.phase_transition_points.application.update(None, Some(now));
project_details.phase_transition_points.evaluation.update(Some(now), Some(evaluation_end_block));
project_details.is_frozen = true;
project_details.status = ProjectStatus::EvaluationRound;


// * Update storage *
ProjectsDetails::<T>::insert(project_id, project_details);
let actual_insertion_attempts = match Self::add_to_update_store(
evaluation_end_block + 1u32.into(),
(&project_id, UpdateType::EvaluationEnd),
) {
Ok(insertions) => insertions,
Err(insertions) =>
return Err(DispatchErrorWithPostInfo {
post_info: PostDispatchInfo {
actual_weight: Some(WeightInfoOf::<T>::start_evaluation(insertions)),
pays_fee: Pays::Yes,
},
error: Error::<T>::TooManyInsertionAttempts.into(),
}),
};

// * Emit events *
Self::deposit_event(Event::ProjectPhaseTransition { project_id, phase: ProjectPhases::Evaluation });

Ok(PostDispatchInfo {
actual_weight: Some(WeightInfoOf::<T>::start_evaluation(actual_insertion_attempts)),
pays_fee: Pays::Yes,
})
project_details.is_frozen = true;

// * Transition Round *
Self::transition_project(
project_id,
project_details,
ProjectStatus::Application,
ProjectStatus::EvaluationRound,
T::EvaluationDuration::get(),
false,
)
}

/// Called automatically by on_initialize.
Expand Down Expand Up @@ -93,83 +71,41 @@ impl<T: Config> Pallet<T> {
/// * Bonding failed - `on_idle` at some point checks for failed evaluation projects, and
/// unbonds the evaluators funds.
#[transactional]
pub fn do_evaluation_end(project_id: ProjectId) -> DispatchResultWithPostInfo {
pub fn do_evaluation_end(project_id: ProjectId) -> DispatchResult {
// * Get variables *
let mut project_details = ProjectsDetails::<T>::get(project_id).ok_or(Error::<T>::ProjectDetailsNotFound)?;
let now = <frame_system::Pallet<T>>::block_number();
let evaluation_end_block =
project_details.phase_transition_points.evaluation.end().ok_or(Error::<T>::TransitionPointNotSet)?;
let fundraising_target_usd = project_details.fundraising_target_usd;

// * Validity checks *
ensure!(project_details.status == ProjectStatus::EvaluationRound, Error::<T>::IncorrectRound);
ensure!(now > evaluation_end_block, Error::<T>::TooEarlyForRound);
let project_details = ProjectsDetails::<T>::get(project_id).ok_or(Error::<T>::ProjectDetailsNotFound)?;

// * Calculate new variables *
let usd_total_amount_bonded = project_details.evaluation_round_info.total_bonded_usd;
let evaluation_target_usd = <T as Config>::EvaluationSuccessThreshold::get() * fundraising_target_usd;

let auction_initialize_period_start_block = now;
let auction_initialize_period_end_block = auction_initialize_period_start_block
.saturating_add(T::AuctionInitializePeriodDuration::get())
.saturating_sub(One::one());
let evaluation_target_usd = <T as Config>::EvaluationSuccessThreshold::get() * project_details.fundraising_target_usd;

// Check which logic path to follow
let is_funded = usd_total_amount_bonded >= evaluation_target_usd;

// * Branch in possible project paths *
// Successful path
if is_funded {
// * Update storage *
project_details
.phase_transition_points
.auction_initialize_period
.update(Some(auction_initialize_period_start_block), Some(auction_initialize_period_end_block));
project_details.status = ProjectStatus::AuctionInitializePeriod;
ProjectsDetails::<T>::insert(project_id, project_details);
let insertion_attempts = match Self::add_to_update_store(
auction_initialize_period_end_block + 1u32.into(),
(&project_id, UpdateType::AuctionOpeningStart),
) {
Ok(insertions) => insertions,
Err(_insertions) => return Err(Error::<T>::TooManyInsertionAttempts.into()),
};

// * Emit events *
Self::deposit_event(Event::ProjectPhaseTransition {
project_id,
phase: ProjectPhases::AuctionInitializePeriod,
});

return Ok(PostDispatchInfo {
actual_weight: Some(WeightInfoOf::<T>::end_evaluation_success(insertion_attempts)),
pays_fee: Pays::Yes,
});

return Self::transition_project(
project_id,
project_details,
ProjectStatus::EvaluationRound,
ProjectStatus::AuctionInitializePeriod,
T::AuctionInitializePeriodDuration::get(),
false,
)
// Unsuccessful path
} else {
// * Update storage *

project_details.status = ProjectStatus::FundingFailed;
ProjectsDetails::<T>::insert(project_id, project_details.clone());
let issuer_did = project_details.issuer_did.clone();
DidWithActiveProjects::<T>::set(issuer_did, None);

let insertion_attempts =
match Self::add_to_update_store(now + One::one(), (&project_id, UpdateType::StartSettlement)) {
Ok(insertions) => insertions,
Err(_insertions) => return Err(Error::<T>::TooManyInsertionAttempts.into()),
};

// * Emit events *
Self::deposit_event(Event::ProjectPhaseTransition {
// * Update storage *
return Self::transition_project(
project_id,
phase: ProjectPhases::FundingFinalization(ProjectOutcome::EvaluationFailed),
});
return Ok(PostDispatchInfo {
actual_weight: Some(WeightInfoOf::<T>::end_evaluation_failure(insertion_attempts)),
pays_fee: Pays::Yes,
});
project_details,
ProjectStatus::EvaluationRound,
ProjectStatus::FundingFailed,
One::one(),
false,
)
}
}

Expand Down
Loading