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

Leo/restrict token audiance #258

Merged
merged 13 commits into from
Apr 25, 2024
2 changes: 1 addition & 1 deletion integration-tests/src/tests/defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub fn bounded_name() -> BoundedVec<u8, ConstU32<64>> {
pub fn bounded_symbol() -> BoundedVec<u8, ConstU32<64>> {
BoundedVec::try_from("CTEST".as_bytes().to_vec()).unwrap()
}
pub fn ipfs_hash() -> BoundedVec<u8, ConstU32<64>> {
pub fn ipfs_hash() -> BoundedVec<u8, ConstU32<96>> {
BoundedVec::try_from(IPFS_CID.as_bytes().to_vec()).unwrap()
}
pub fn default_weights() -> Vec<u8> {
Expand Down
1 change: 0 additions & 1 deletion pallets/dispenser/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
#[benchmarks]
mod benchmarks {
use super::*;

#[benchmark]
fn dispense() {
let caller: T::AccountId = whitelisted_caller();
Expand Down
8 changes: 4 additions & 4 deletions pallets/dispenser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use frame_support::traits::{
tokens::{currency::VestingSchedule, Balance},
Currency, ExistenceRequirement,
};
pub use polimec_common::credentials::{Did, EnsureOriginWithCredentials, InvestorType, UntrustedToken};
pub use polimec_common::credentials::{Cid, Did, EnsureOriginWithCredentials, InvestorType, UntrustedToken};
pub use sp_runtime::traits::Convert;

pub mod extensions;
Expand Down Expand Up @@ -77,7 +77,7 @@ pub mod pallet {
/// The Origin that can dispense funds from the dispenser. The Origin must contain a valid JWT token.
type InvestorOrigin: EnsureOriginWithCredentials<
<Self as frame_system::Config>::RuntimeOrigin,
Success = (AccountIdOf<Self>, Did, InvestorType),
Success = (AccountIdOf<Self>, Did, InvestorType, Cid),
>;

/// The period of time that the dispensed funds are locked. Used to calculate the
Expand Down Expand Up @@ -137,7 +137,7 @@ pub mod pallet {
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::feeless_if( | origin: &OriginFor<T>, jwt: &UntrustedToken | -> bool {
if let Ok((_, did, _)) = T::InvestorOrigin::ensure_origin(origin.clone(), jwt, T::VerifierPublicKey::get()) {
if let Ok((_, did, _, _)) = T::InvestorOrigin::ensure_origin(origin.clone(), jwt, T::VerifierPublicKey::get()) {
return Dispensed::<T>::get(did).is_none()
} else {
return false
Expand All @@ -146,7 +146,7 @@ pub mod pallet {
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::dispense())]
pub fn dispense(origin: OriginFor<T>, jwt: UntrustedToken) -> DispatchResultWithPostInfo {
let (who, did, _investor_type) =
let (who, did, _investor_type, _) =
T::InvestorOrigin::ensure_origin(origin, &jwt, T::VerifierPublicKey::get())?;
ensure!(Dispensed::<T>::get(&did).is_none(), Error::<T>::DispensedAlreadyToDid);

Expand Down
72 changes: 56 additions & 16 deletions pallets/funding/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ pub fn run_blocks_to_execute_next_transition<T: Config>(
mod benchmarks {
use super::*;
use itertools::Itertools;
use polimec_common_test_utils::generate_did_from_account;
use polimec_common_test_utils::{generate_did_from_account, get_mock_jwt_with_cid};

impl_benchmark_test_suite!(PalletFunding, crate::mock::new_test_ext(), crate::mock::TestRuntime);

Expand Down Expand Up @@ -384,7 +384,12 @@ mod benchmarks {
issuer.clone(),
ed * 2u64.into() + metadata_deposit + ct_treasury_account_deposit,
)]);
let jwt = get_mock_jwt(issuer.clone(), InvestorType::Institutional, generate_did_from_account(issuer.clone()));
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
InvestorType::Institutional,
generate_did_from_account(issuer.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);

#[extrinsic_call]
create_project(RawOrigin::Signed(issuer.clone()), jwt, project_metadata.clone());
Expand Down Expand Up @@ -419,7 +424,12 @@ mod benchmarks {

let project_metadata = default_project::<T>(issuer.clone());
let project_id = inst.create_new_project(project_metadata.clone(), issuer.clone());
let jwt = get_mock_jwt(issuer.clone(), InvestorType::Institutional, generate_did_from_account(issuer.clone()));
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
InvestorType::Institutional,
generate_did_from_account(issuer.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);

#[extrinsic_call]
remove_project(RawOrigin::Signed(issuer.clone()), jwt, project_id);
Expand Down Expand Up @@ -521,7 +531,12 @@ mod benchmarks {
policy_ipfs_cid: Some(BoundedVec::try_from(IPFS_CID.as_bytes().to_vec()).unwrap()),
};

let jwt = get_mock_jwt(issuer.clone(), InvestorType::Institutional, generate_did_from_account(issuer.clone()));
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
InvestorType::Institutional,
generate_did_from_account(issuer.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);

#[extrinsic_call]
edit_project(RawOrigin::Signed(issuer), jwt, project_id, project_metadata.clone());
Expand Down Expand Up @@ -553,13 +568,18 @@ mod benchmarks {
whitelist_account!(issuer);

let project_metadata = default_project::<T>(issuer.clone());
let project_id = inst.create_new_project(project_metadata, issuer.clone());
let project_id = inst.create_new_project(project_metadata.clone(), issuer.clone());

// start_evaluation fn will try to add an automatic transition 1 block after the last evaluation block
let block_number: BlockNumberFor<T> = inst.current_block() + T::EvaluationDuration::get() + One::one();
// fill the `ProjectsToUpdate` vectors from @ block_number to @ block_number+x, to benchmark all the failed insertion attempts
fill_projects_to_update::<T>(x, block_number);
let jwt = get_mock_jwt(issuer.clone(), InvestorType::Institutional, generate_did_from_account(issuer.clone()));
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
InvestorType::Institutional,
generate_did_from_account(issuer.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);
#[extrinsic_call]
start_evaluation(RawOrigin::Signed(issuer), jwt, project_id);

Expand Down Expand Up @@ -601,7 +621,7 @@ mod benchmarks {
whitelist_account!(issuer);

let project_metadata = default_project::<T>(issuer.clone());
let project_id = inst.create_evaluating_project(project_metadata, issuer.clone());
let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer.clone());

let evaluations = default_evaluations();
let plmc_for_evaluating = BenchInstantiator::<T>::calculate_evaluation_plmc_spent(evaluations.clone());
Expand All @@ -624,7 +644,12 @@ mod benchmarks {

fill_projects_to_update::<T>(x, insertion_block_number);

let jwt = get_mock_jwt(issuer.clone(), InvestorType::Institutional, generate_did_from_account(issuer.clone()));
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
InvestorType::Institutional,
generate_did_from_account(issuer.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);
#[extrinsic_call]
start_auction(RawOrigin::Signed(issuer), jwt, project_id);

Expand Down Expand Up @@ -656,7 +681,7 @@ mod benchmarks {
whitelist_account!(test_evaluator);

let project_metadata = default_project::<T>(issuer.clone());
let project_id = inst.create_evaluating_project(project_metadata, issuer);
let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer);

let existing_evaluation = UserToUSDBalance::new(test_evaluator.clone(), (200 * US_DOLLAR).into());
let extrinsic_evaluation = UserToUSDBalance::new(test_evaluator.clone(), (1_000 * US_DOLLAR).into());
Expand Down Expand Up @@ -684,10 +709,11 @@ mod benchmarks {
plmc_for_extrinsic_evaluation.clone(),
]);

let jwt = get_mock_jwt(
let jwt = get_mock_jwt_with_cid(
extrinsic_evaluation.account.clone(),
InvestorType::Institutional,
generate_did_from_account(extrinsic_evaluation.account.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);
#[extrinsic_call]
evaluate(
Expand Down Expand Up @@ -1037,10 +1063,11 @@ mod benchmarks {
total_usdt_locked,
) = bid_setup::<T>(x, y);

let jwt = get_mock_jwt(
let jwt = get_mock_jwt_with_cid(
original_extrinsic_bid.bidder.clone(),
InvestorType::Institutional,
generate_did_from_account(original_extrinsic_bid.bidder.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);
#[extrinsic_call]
bid(
Expand Down Expand Up @@ -1296,10 +1323,11 @@ mod benchmarks {
total_ct_sold,
) = contribution_setup::<T>(x, ends_round);

let jwt = get_mock_jwt(
let jwt = get_mock_jwt_with_cid(
extrinsic_contribution.contributor.clone(),
InvestorType::Retail,
generate_did_from_account(extrinsic_contribution.contributor.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);

#[extrinsic_call]
Expand Down Expand Up @@ -1346,10 +1374,11 @@ mod benchmarks {
total_ct_sold,
) = contribution_setup::<T>(x, ends_round);

let jwt = get_mock_jwt(
let jwt = get_mock_jwt_with_cid(
extrinsic_contribution.contributor.clone(),
InvestorType::Retail,
generate_did_from_account(extrinsic_contribution.contributor.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);

#[extrinsic_call]
Expand Down Expand Up @@ -1412,16 +1441,27 @@ mod benchmarks {
default_community_contributor_multipliers(),
);

let project_id =
inst.create_finished_project(project_metadata, issuer.clone(), evaluations, bids, contributions, vec![]);
let project_id = inst.create_finished_project(
project_metadata.clone(),
issuer.clone(),
evaluations,
bids,
contributions,
vec![],
);

inst.advance_time(One::one()).unwrap();

let current_block = inst.current_block();
let insertion_block_number: BlockNumberFor<T> = current_block + One::one();

fill_projects_to_update::<T>(x, insertion_block_number);
let jwt = get_mock_jwt(issuer.clone(), InvestorType::Institutional, generate_did_from_account(issuer.clone()));
let jwt = get_mock_jwt_with_cid(
issuer.clone(),
InvestorType::Institutional,
generate_did_from_account(issuer.clone()),
project_metadata.clone().policy_ipfs_cid.unwrap(),
);

#[extrinsic_call]
decide_project_outcome(RawOrigin::Signed(issuer), jwt, project_id, FundingOutcomeDecision::AcceptFunding);
Expand Down
28 changes: 26 additions & 2 deletions pallets/funding/src/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -961,8 +961,11 @@ impl<T: Config> Pallet<T> {
usd_amount: BalanceOf<T>,
did: Did,
investor_type: InvestorType,
whitelisted_policy: Cid,
) -> DispatchResultWithPostInfo {
// * Get variables *
let project_metadata = ProjectsMetadata::<T>::get(project_id)
.ok_or(Error::<T>::ProjectError(ProjectErrorReason::ProjectMetadataNotFound))?;
let mut project_details = ProjectsDetails::<T>::get(project_id)
.ok_or(Error::<T>::ProjectError(ProjectErrorReason::ProjectDetailsNotFound))?;
let now = <frame_system::Pallet<T>>::block_number();
Expand All @@ -973,8 +976,13 @@ impl<T: Config> Pallet<T> {
let evaluation_round_info = &mut project_details.evaluation_round_info;
let total_evaluations_count = EvaluationCounts::<T>::get(project_id);
let user_evaluations_count = Evaluations::<T>::iter_prefix((project_id, evaluator)).count() as u32;
let project_policy = project_metadata.policy_ipfs_cid.ok_or(Error::<T>::ImpossibleState)?;

// * Validity Checks *
ensure!(
project_policy == whitelisted_policy,
Error::<T>::ParticipationFailed(ParticipationError::PolicyMismatch)
);
ensure!(
usd_amount >= T::MinUsdPerEvaluation::get(),
Error::<T>::ParticipationFailed(ParticipationError::TooLow)
Expand Down Expand Up @@ -1077,12 +1085,13 @@ impl<T: Config> Pallet<T> {
funding_asset: AcceptedFundingAsset,
did: Did,
investor_type: InvestorType,
whitelisted_policy: Cid,
) -> DispatchResultWithPostInfo {
// * Get variables *
let project_details = ProjectsDetails::<T>::get(project_id)
.ok_or(Error::<T>::ProjectError(ProjectErrorReason::ProjectDetailsNotFound))?;
let project_metadata = ProjectsMetadata::<T>::get(project_id)
.ok_or(Error::<T>::ProjectError(ProjectErrorReason::ProjectMetadataNotFound))?;
let project_details = ProjectsDetails::<T>::get(project_id)
.ok_or(Error::<T>::ProjectError(ProjectErrorReason::ProjectDetailsNotFound))?;
let plmc_usd_price = T::PriceProvider::get_price(PLMC_FOREIGN_ID).ok_or(Error::<T>::PriceNotFound)?;

// Fetch current bucket details and other required info
Expand All @@ -1091,6 +1100,7 @@ impl<T: Config> Pallet<T> {
let now = <frame_system::Pallet<T>>::block_number();
let mut amount_to_bid = ct_amount;
let total_bids_for_project = BidCounts::<T>::get(project_id);
let project_policy = project_metadata.policy_ipfs_cid.ok_or(Error::<T>::ImpossibleState)?;

// User will spend at least this amount of USD for his bid(s). More if the bid gets split into different buckets
let min_total_ticket_size =
Expand All @@ -1114,6 +1124,10 @@ impl<T: Config> Pallet<T> {
};

// * Validity checks *
ensure!(
project_policy == whitelisted_policy,
Error::<T>::ParticipationFailed(ParticipationError::PolicyMismatch)
);
ensure!(
matches!(investor_type, InvestorType::Institutional | InvestorType::Professional),
DispatchError::from("Retail investors are not allowed to bid")
Expand Down Expand Up @@ -1297,6 +1311,7 @@ impl<T: Config> Pallet<T> {
asset: AcceptedFundingAsset,
did: Did,
investor_type: InvestorType,
whitelisted_policy: Cid,
) -> DispatchResultWithPostInfo {
let mut project_details = ProjectsDetails::<T>::get(project_id)
.ok_or(Error::<T>::ProjectError(ProjectErrorReason::ProjectDetailsNotFound))?;
Expand All @@ -1320,6 +1335,7 @@ impl<T: Config> Pallet<T> {
asset,
investor_type,
did,
whitelisted_policy,
)
}

Expand All @@ -1341,6 +1357,7 @@ impl<T: Config> Pallet<T> {
asset: AcceptedFundingAsset,
did: Did,
investor_type: InvestorType,
whitelisted_policy: Cid,
) -> DispatchResultWithPostInfo {
let mut project_details = ProjectsDetails::<T>::get(project_id)
.ok_or(Error::<T>::ProjectError(ProjectErrorReason::ProjectDetailsNotFound))?;
Expand All @@ -1364,6 +1381,7 @@ impl<T: Config> Pallet<T> {
asset,
investor_type,
did,
whitelisted_policy,
)
}

Expand All @@ -1377,6 +1395,7 @@ impl<T: Config> Pallet<T> {
funding_asset: AcceptedFundingAsset,
investor_type: InvestorType,
did: Did,
whitelisted_policy: Cid,
) -> DispatchResultWithPostInfo {
let project_metadata = ProjectsMetadata::<T>::get(project_id)
.ok_or(Error::<T>::ProjectError(ProjectErrorReason::ProjectMetadataNotFound))?;
Expand All @@ -1389,6 +1408,7 @@ impl<T: Config> Pallet<T> {
let plmc_usd_price = T::PriceProvider::get_price(PLMC_FOREIGN_ID).ok_or(Error::<T>::PriceNotFound)?;
let funding_asset_usd_price =
T::PriceProvider::get_price(funding_asset.to_assethub_id()).ok_or(Error::<T>::PriceNotFound)?;
let project_policy = project_metadata.policy_ipfs_cid.ok_or(Error::<T>::ImpossibleState)?;

let ticket_size = ct_usd_price.checked_mul_int(buyable_tokens).ok_or(Error::<T>::BadMath)?;
let contributor_ticket_size = match investor_type {
Expand All @@ -1411,6 +1431,10 @@ impl<T: Config> Pallet<T> {
InvestorType::Institutional => INSTITUTIONAL_MAX_MULTIPLIER,
};
// * Validity checks *
ensure!(
project_policy == whitelisted_policy,
Error::<T>::ParticipationFailed(ParticipationError::PolicyMismatch)
);
ensure!(
multiplier.into() <= max_multiplier && multiplier.into() > 0u8,
Error::<T>::ParticipationFailed(ParticipationError::ForbiddenMultiplier)
Expand Down
Loading