-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy path2_evaluation.rs
160 lines (142 loc) · 5.76 KB
/
2_evaluation.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#[allow(clippy::wildcard_imports)]
use super::*;
use polimec_common::ProvideAssetPrice;
impl<T: Config> Pallet<T> {
/// Start the evaluation round of a project. This is how the raise is started.
#[transactional]
pub fn do_start_evaluation(caller: AccountIdOf<T>, project_id: ProjectId) -> DispatchResultWithPostInfo {
// * 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)?;
// * Validity checks *
ensure!(project_details.issuer_account == caller, Error::<T>::NotIssuer);
ensure!(!project_details.is_frozen, Error::<T>::ProjectAlreadyFrozen);
ensure!(project_metadata.policy_ipfs_cid.is_some(), Error::<T>::CidNotProvided);
// * Update storage *
project_details.is_frozen = true;
// * Transition Round *
Self::transition_project(
project_id,
project_details,
ProjectStatus::Application,
ProjectStatus::EvaluationRound,
Some(T::EvaluationRoundDuration::get()),
false,
)?;
Ok(PostDispatchInfo { actual_weight: None, pays_fee: Pays::No })
}
/// End the evaluation round of a project, and start the auction round.
#[transactional]
pub fn do_end_evaluation(project_id: ProjectId) -> DispatchResult {
// * Get variables *
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() * 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
return if is_funded {
ProjectsInAuctionRound::<T>::insert(project_id, ());
Self::transition_project(
project_id,
project_details,
ProjectStatus::EvaluationRound,
ProjectStatus::AuctionRound,
Some(T::AuctionRoundDuration::get()),
false,
)
// Unsuccessful path
} else {
let issuer_did = project_details.issuer_did.clone();
DidWithActiveProjects::<T>::set(issuer_did, None);
Self::transition_project(
project_id,
project_details,
ProjectStatus::EvaluationRound,
ProjectStatus::FundingFailed,
None,
false,
)
}
}
/// Place an evaluation on a project
#[transactional]
pub fn do_evaluate(
evaluator: &AccountIdOf<T>,
project_id: ProjectId,
usd_amount: Balance,
did: Did,
whitelisted_policy: Cid,
receiving_account: Junction,
) -> 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 = <T as Config>::BlockNumberProvider::current_block_number();
let evaluation_id = NextEvaluationId::<T>::get();
let plmc_usd_price =
<PriceProviderOf<T>>::get_decimals_aware_price(Location::here(), USD_DECIMALS, PLMC_DECIMALS)
.ok_or(Error::<T>::PriceNotFound)?;
let early_evaluation_reward_threshold_usd =
T::EvaluationSuccessThreshold::get() * project_details.fundraising_target_usd;
let evaluation_round_info = &mut project_details.evaluation_round_info;
let project_policy = project_metadata.policy_ipfs_cid.ok_or(Error::<T>::ImpossibleState)?;
let project_metadata = ProjectsMetadata::<T>::get(project_id).ok_or(Error::<T>::ProjectDetailsNotFound)?;
// * Validity Checks *
ensure!(project_policy == whitelisted_policy, Error::<T>::PolicyMismatch);
ensure!(usd_amount >= T::MinUsdPerEvaluation::get(), Error::<T>::TooLow);
ensure!(project_details.issuer_did != did, Error::<T>::ParticipationToOwnProject);
ensure!(project_details.status == ProjectStatus::EvaluationRound, Error::<T>::IncorrectRound);
ensure!(
project_details.round_duration.started(now) && !project_details.round_duration.ended(now),
Error::<T>::IncorrectRound
);
ensure!(
project_metadata.participants_account_type.junction_is_supported(&receiving_account),
Error::<T>::UnsupportedReceiverAccountJunction
);
let plmc_bond = plmc_usd_price
.reciprocal()
.ok_or(Error::<T>::BadMath)?
.checked_mul_int(usd_amount)
.ok_or(Error::<T>::BadMath)?;
let previous_total_evaluation_bonded_usd = evaluation_round_info.total_bonded_usd;
let remaining_bond_to_reach_threshold =
early_evaluation_reward_threshold_usd.saturating_sub(previous_total_evaluation_bonded_usd);
let early_usd_amount = if usd_amount <= remaining_bond_to_reach_threshold {
usd_amount
} else {
remaining_bond_to_reach_threshold
};
let late_usd_amount = usd_amount.checked_sub(early_usd_amount).ok_or(Error::<T>::BadMath)?;
let new_evaluation = EvaluationInfoOf::<T> {
id: evaluation_id,
did: did.clone(),
project_id,
evaluator: evaluator.clone(),
original_plmc_bond: plmc_bond,
current_plmc_bond: plmc_bond,
early_usd_amount,
late_usd_amount,
when: now,
receiving_account,
};
T::NativeCurrency::hold(&HoldReason::Evaluation.into(), evaluator, plmc_bond)?;
Evaluations::<T>::insert((project_id, evaluator, evaluation_id), new_evaluation);
NextEvaluationId::<T>::set(evaluation_id.saturating_add(One::one()));
evaluation_round_info.total_bonded_usd = evaluation_round_info.total_bonded_usd.saturating_add(usd_amount);
evaluation_round_info.total_bonded_plmc = evaluation_round_info.total_bonded_plmc.saturating_add(plmc_bond);
ProjectsDetails::<T>::insert(project_id, project_details);
// * Emit events *
Self::deposit_event(Event::Evaluation {
project_id,
evaluator: evaluator.clone(),
id: evaluation_id,
plmc_amount: plmc_bond,
});
Ok(())
}
}