From e552785ddca465204b1ed3ef532340b467771077 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Rios Date: Thu, 24 Oct 2024 11:37:19 +0200 Subject: [PATCH] eth compat. tests --- Cargo.toml | 1 + integration-tests/Cargo.toml | 1 + integration-tests/src/tests/defaults.rs | 10 +- .../src/tests/ethereum_support.rs | 40 +++ .../src/tests/evaluator_slash_sideffects.rs | 4 +- pallets/funding/Cargo.toml | 8 +- pallets/funding/src/benchmarking.rs | 92 ++--- pallets/funding/src/functions/6_settlement.rs | 3 +- pallets/funding/src/functions/misc.rs | 16 +- .../funding/src/instantiator/calculations.rs | 76 ++++- .../src/instantiator/chain_interactions.rs | 85 +++-- pallets/funding/src/instantiator/traits.rs | 29 +- pallets/funding/src/instantiator/types.rs | 266 +++++++++++---- pallets/funding/src/lib.rs | 18 +- pallets/funding/src/tests/2_evaluation.rs | 97 +++++- pallets/funding/src/tests/3_auction.rs | 205 ++++++++---- pallets/funding/src/tests/4_contribution.rs | 191 ++++++++--- pallets/funding/src/tests/6_settlement.rs | 316 +++++++++++++++--- pallets/funding/src/tests/misc.rs | 106 ++++-- pallets/funding/src/tests/mod.rs | 143 +++++--- pallets/funding/src/tests/runtime_api.rs | 96 ++++-- pallets/funding/src/types.rs | 2 +- pallets/polimec-receiver/src/lib.rs | 16 +- polimec-common/common/src/lib.rs | 3 +- runtimes/polimec/Cargo.toml | 3 - 25 files changed, 1344 insertions(+), 483 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fc22a3638..8ca7f440d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -148,6 +148,7 @@ sp-authority-discovery = { version = "33.0.0", default-features = false } sp-consensus-babe = { version = "0.39.0", default-features = false } pallet-message-queue = { version = "38.0.0", default-features = false } sp-weights = { version = "31.0.0", default-features = false } +sp-application-crypto = {version = "37.0.0", default-features = false} # FRAME assets-common = { version = "0.14.0", default-features = false } diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 7856bb96a..595aa0149 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -102,6 +102,7 @@ std = [ "frame-metadata-hash-extension/std", "frame-support/std", "frame-system/std", + "hex/std", "itertools/use_std", "orml-oracle/std", "pallet-asset-tx-payment/std", diff --git a/integration-tests/src/tests/defaults.rs b/integration-tests/src/tests/defaults.rs index d58df5e42..2def4b508 100644 --- a/integration-tests/src/tests/defaults.rs +++ b/integration-tests/src/tests/defaults.rs @@ -15,7 +15,7 @@ // along with this program. If not, see . use crate::PolimecRuntime; use frame_support::BoundedVec; -pub use pallet_funding::instantiator::{BidParams, ContributionParams, UserToUSDBalance}; +pub use pallet_funding::instantiator::{BidParams, ContributionParams, EvaluationParams}; use pallet_funding::{ AcceptedFundingAsset, BiddingTicketSizes, ContributingTicketSizes, CurrencyMetadata, ParticipantsAccountType, ParticipationMode, PriceProviderOf, ProjectMetadata, ProjectMetadataOf, TicketSize, @@ -91,11 +91,11 @@ pub fn default_project_metadata(issuer: AccountId) -> ProjectMetadataOf Vec> { +pub fn default_evaluations() -> Vec> { vec![ - UserToUSDBalance::new(EVAL_1.into(), 500_000 * PLMC), - UserToUSDBalance::new(EVAL_2.into(), 250_000 * PLMC), - UserToUSDBalance::new(EVAL_3.into(), 320_000 * PLMC), + EvaluationParams::from((EVAL_1.into(), 500_000 * PLMC)), + EvaluationParams::from((EVAL_2.into(), 250_000 * PLMC)), + EvaluationParams::from((EVAL_3.into(), 320_000 * PLMC)), ] } pub fn default_bidders() -> Vec { diff --git a/integration-tests/src/tests/ethereum_support.rs b/integration-tests/src/tests/ethereum_support.rs index 8b1378917..9ecfee8cc 100644 --- a/integration-tests/src/tests/ethereum_support.rs +++ b/integration-tests/src/tests/ethereum_support.rs @@ -1 +1,41 @@ +use crate::*; +use hex_literal::hex; +use sp_runtime::traits::Convert; +generate_accounts!(ETH_BUYER); + +#[test] +fn test_hardcoded_signatures() { + let polimec_account: PolimecAccountId = ETH_BUYER.into(); + let project_id = 0; + + // Values generated with `https://github.com/lrazovic/ethsigner` + let polimec_account_ss58 = polimec_runtime::SS58Converter::convert(polimec_account.clone()); + dbg!(polimec_account_ss58); + let ethereum_account: [u8; 20] = hex!("FCAd0B19bB29D4674531d6f115237E16AfCE377c"); + let signature: [u8; 65] = hex!("4fa35369a2d654112d3fb419e24dc0d7d61b7e3f23936d6d4df0ac8608fa4530795971d4d1967da60853aa974ad57252a521f97bcd5a68ddea5f8959a5c60b471c"); + + PolimecNet::execute_with(|| { + assert_ok!(PolimecFunding::verify_receiving_account_signature( + &polimec_account, + project_id, + &Junction::AccountKey20 { network: Some(NetworkId::Ethereum { chain_id: 1 }), key: ethereum_account }, + signature, + )); + }); + + let polkadot_signature: [u8; 64] = hex!("7efee88bb61b74c91e6dc0ad48ea5b0118db77a579da8a8a753933d76cdc9e029c11f32a51b00fd3a1e3ce5b56cd1e275b179d4b195e7d527eebc60680291b81"); + let mut signature: [u8; 65] = [0u8; 65]; + signature[..64].copy_from_slice(polkadot_signature.as_slice()); + signature[64] = 0; + let polkadot_address: [u8; 32] = hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"); + + PolimecNet::execute_with(|| { + assert_ok!(PolimecFunding::verify_receiving_account_signature( + &polimec_account, + project_id, + &Junction::AccountId32 { network: Some(NetworkId::Polkadot), id: polkadot_address }, + signature, + )); + }); +} diff --git a/integration-tests/src/tests/evaluator_slash_sideffects.rs b/integration-tests/src/tests/evaluator_slash_sideffects.rs index 646a52263..8a1b4628a 100644 --- a/integration-tests/src/tests/evaluator_slash_sideffects.rs +++ b/integration-tests/src/tests/evaluator_slash_sideffects.rs @@ -77,7 +77,7 @@ fn evaluator_slash_reduces_vesting_schedules() { vesting_info_4 )); - let alice_evaluation = UserToUSDBalance::::new(alice.clone(), 35_000 * USD_UNIT); + let alice_evaluation = EvaluationParams::::new(alice.clone(), 35_000 * USD_UNIT); let alice_plmc_evaluated = inst.calculate_evaluation_plmc_spent(vec![alice_evaluation.clone()])[0].plmc_amount; let alice_slashed = slash_percent * alice_plmc_evaluated; @@ -92,7 +92,7 @@ fn evaluator_slash_reduces_vesting_schedules() { Id(bob.clone()), vesting_info_5 )); - let bob_evaluation = UserToUSDBalance::::new(bob.clone(), BOB_EVALUATION * USD_UNIT); + let bob_evaluation = EvaluationParams::::new(bob.clone(), BOB_EVALUATION * USD_UNIT); let bob_plmc_evaluated = inst.calculate_evaluation_plmc_spent(vec![bob_evaluation.clone()])[0].plmc_amount; let bob_slashed = slash_percent * bob_plmc_evaluated; diff --git a/pallets/funding/Cargo.toml b/pallets/funding/Cargo.toml index 97169261f..a0bcad723 100644 --- a/pallets/funding/Cargo.toml +++ b/pallets/funding/Cargo.toml @@ -48,6 +48,7 @@ frame-benchmarking = { workspace = true, optional = true } hex-literal.workspace = true k256.workspace = true hex.workspace = true +#sp-application-crypto.workspace = true # Used in the instantiator. itertools.workspace = true @@ -62,12 +63,14 @@ xcm-builder.workspace = true xcm-executor.workspace = true [features] -default = [ "std", "sp-core/serde" ] +default = [ "sp-core/serde", "std" ] std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "hex/std", "itertools/use_std", + "k256/std", "log/std", "on-slash-vesting/std", "pallet-assets/std", @@ -86,6 +89,7 @@ std = [ "serde/std", "sp-api/std", "sp-arithmetic/std", + "sp-core/full_crypto", "sp-core/std", "sp-io/std", "sp-runtime/std", @@ -93,8 +97,6 @@ std = [ "xcm-builder/std", "xcm-executor/std", "xcm/std", - "k256/std", - "hex/std", ] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/pallets/funding/src/benchmarking.rs b/pallets/funding/src/benchmarking.rs index 38801cbaf..710042f6c 100644 --- a/pallets/funding/src/benchmarking.rs +++ b/pallets/funding/src/benchmarking.rs @@ -85,7 +85,7 @@ where } } -pub fn default_evaluations() -> Vec> +pub fn default_evaluations() -> Vec> where ::Price: From, T::Hash: From, @@ -98,18 +98,18 @@ where let evaluation_target = threshold * funding_target; vec![ - UserToUSDBalance::new( + EvaluationParams::from(( account::>("evaluator_1", 0, 0), Percent::from_percent(35) * evaluation_target, - ), - UserToUSDBalance::new( + )), + EvaluationParams::from(( account::>("evaluator_2", 0, 0), Percent::from_percent(35) * evaluation_target, - ), - UserToUSDBalance::new( + )), + EvaluationParams::from(( account::>("evaluator_3", 0, 0), Percent::from_percent(35) * evaluation_target, - ), + )), ] } @@ -501,8 +501,8 @@ mod benchmarks { let project_metadata = default_project_metadata::(issuer.clone()); let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer, None); - let existing_evaluation = UserToUSDBalance::new(test_evaluator.clone(), (200 * USD_UNIT).into()); - let extrinsic_evaluation = UserToUSDBalance::new(test_evaluator.clone(), (1_000 * USD_UNIT).into()); + let existing_evaluation = EvaluationParams::from((test_evaluator.clone(), (200 * USD_UNIT).into())); + let extrinsic_evaluation = EvaluationParams::from((test_evaluator.clone(), (1_000 * USD_UNIT).into())); let existing_evaluations = vec![existing_evaluation; x as usize]; let plmc_for_existing_evaluations = inst.calculate_evaluation_plmc_spent(existing_evaluations.clone()); @@ -597,18 +597,18 @@ mod benchmarks { ::EvaluationSuccessThreshold::get() * project_details.fundraising_target_usd; // we only fund 50% of the minimum threshold for the evaluation round, since we want it to fail let evaluations = vec![ - UserToUSDBalance::new( + EvaluationParams::from(( account::>("evaluator_1", 0, 0), (Percent::from_percent(5) * evaluation_usd_target).into(), - ), - UserToUSDBalance::new( + )), + EvaluationParams::from(( account::>("evaluator_2", 0, 0), (Percent::from_percent(20) * evaluation_usd_target).into(), - ), - UserToUSDBalance::new( + )), + EvaluationParams::from(( account::>("evaluator_3", 0, 0), (Percent::from_percent(25) * evaluation_usd_target).into(), - ), + )), ]; let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone()); @@ -669,12 +669,12 @@ mod benchmarks { let project_id = inst.create_auctioning_project(project_metadata.clone(), issuer, None, evaluations); - let existing_bid = BidParams::new( + let existing_bid = BidParams::from(( bidder.clone(), (50 * CT_UNIT).into(), ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT, - ); + )); let existing_bids = vec![existing_bid; x as usize]; let existing_bids_post_bucketing = @@ -715,12 +715,12 @@ mod benchmarks { let current_bucket = Buckets::::get(project_id).unwrap(); // first lets bring the bucket to almost its limit with another bidder: assert!(new_bidder.clone() != bidder.clone()); - let bid_params = BidParams::new( + let bid_params = BidParams::from(( new_bidder.clone(), current_bucket.amount_left, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); maybe_filler_bid = Some(bid_params.clone()); let plmc_for_new_bidder = inst.calculate_auction_plmc_charged_with_given_price( &vec![bid_params.clone()], @@ -746,7 +746,7 @@ mod benchmarks { usdt_for_filler_bidder = usdt_for_new_bidder; } let extrinsic_bid = - BidParams::new(bidder.clone(), ct_amount, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT); + BidParams::from((bidder.clone(), ct_amount, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)); let original_extrinsic_bid = extrinsic_bid.clone(); let current_bucket = Buckets::::get(project_id).unwrap(); // we need to call this after bidding `x` amount of times, to get the latest bucket from storage @@ -927,34 +927,34 @@ mod benchmarks { // These bids will always be rejected, and will be made after the first bucket bid let rejected_bids = (0..y.saturating_sub(1)) .map(|i| { - BidParams::::new( + BidParams::::from(( account::>("bidder", 0, i), (min_bid_amount * CT_UNIT).into(), ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ) + )) }) .collect_vec(); all_bids.extend(rejected_bids.clone()); let already_accepted_bids_count = if y > 0 { // This one needs to fill the remaining with the bucket, so that all "accepted" bids will take the CT from a rejected one - let last_rejected_bid = BidParams::::new( + let last_rejected_bid = BidParams::::from(( account::>("bidder", 0, 420), auction_allocation - (min_bid_amount * CT_UNIT * (y as u128 - 1u128)), ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); all_bids.push(last_rejected_bid.clone()); // We first need to invalidate all rejected bids. // We do it by placing a bid of the whole auction allocation, i.e. 10 new bids - let allocation_bid = BidParams::::new( + let allocation_bid = BidParams::::from(( account::>("bidder", 0, y), auction_allocation, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); all_bids.push(allocation_bid); 10 @@ -964,12 +964,12 @@ mod benchmarks { let accepted_bids = (0..x.saturating_sub(already_accepted_bids_count)) .map(|i| { - BidParams::::new( + BidParams::::from(( account::>("bidder", 0, i), (min_bid_amount * CT_UNIT).into(), ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ) + )) }) .collect_vec(); all_bids.extend(accepted_bids.clone()); @@ -1054,12 +1054,12 @@ mod benchmarks { let price = inst.get_project_details(project_id).weighted_average_price.unwrap(); let contributions = vec![ - ContributionParams::new( + ContributionParams::from(( contributor.clone(), (50 * CT_UNIT).into(), ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT - ); + )); x as usize + 1 ]; @@ -1227,7 +1227,7 @@ mod benchmarks { inst.advance_time(1u32.into()); let issuer = account::>("issuer", 0, 0); - let evaluations: Vec> = default_evaluations::(); + let evaluations: Vec> = default_evaluations::(); let evaluator: AccountIdOf = evaluations[0].account.clone(); whitelist_account!(evaluator); @@ -1513,26 +1513,26 @@ mod benchmarks { let max_contributions = x - max_evaluations - max_bids; let participant_evaluations = (0..max_evaluations) - .map(|_| UserToUSDBalance::new(participant.clone(), (100 * USD_UNIT).into())) + .map(|_| EvaluationParams::from((participant.clone(), (100 * USD_UNIT).into()))) .collect_vec(); let participant_bids = (0..max_bids) .map(|_| { - BidParams::new( + BidParams::from(( participant.clone(), (500 * CT_UNIT).into(), ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ) + )) }) .collect_vec(); let participant_contributions = (0..max_contributions) .map(|_| { - ContributionParams::::new( + ContributionParams::::from(( participant.clone(), (10 * CT_UNIT).into(), ParticipationMode::Classic(1), AcceptedFundingAsset::USDT, - ) + )) }) .collect_vec(); @@ -1862,26 +1862,26 @@ mod benchmarks { let max_contributions = x - max_evaluations - max_bids; let participant_evaluations = (0..max_evaluations) - .map(|_| UserToUSDBalance::new(participant.clone(), (100 * USD_UNIT).into())) + .map(|_| EvaluationParams::from((participant.clone(), (100 * USD_UNIT).into()))) .collect_vec(); let participant_bids = (0..max_bids) .map(|_| { - BidParams::new( + BidParams::from(( participant.clone(), (500 * CT_UNIT).into(), ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ) + )) }) .collect_vec(); let participant_contributions = (0..max_contributions) .map(|_| { - ContributionParams::::new( + ContributionParams::::from(( participant.clone(), (10 * CT_UNIT).into(), ParticipationMode::Classic(1), AcceptedFundingAsset::USDT, - ) + )) }) .collect_vec(); @@ -1960,26 +1960,26 @@ mod benchmarks { let max_contributions = x - max_evaluations - max_bids; let participant_evaluations = (0..max_evaluations) - .map(|_| UserToUSDBalance::new(participant.clone(), (100 * USD_UNIT).into())) + .map(|_| EvaluationParams::from((participant.clone(), (100 * USD_UNIT).into()))) .collect_vec(); let participant_bids = (0..max_bids) .map(|_| { - BidParams::new( + BidParams::from(( participant.clone(), (500 * CT_UNIT).into(), ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ) + )) }) .collect_vec(); let participant_contributions = (0..max_contributions) .map(|_| { - ContributionParams::::new( + ContributionParams::::from(( participant.clone(), (10 * CT_UNIT).into(), ParticipationMode::Classic(1), AcceptedFundingAsset::USDT, - ) + )) }) .collect_vec(); diff --git a/pallets/funding/src/functions/6_settlement.rs b/pallets/funding/src/functions/6_settlement.rs index 9bb399bd9..d864675cf 100644 --- a/pallets/funding/src/functions/6_settlement.rs +++ b/pallets/funding/src/functions/6_settlement.rs @@ -487,8 +487,7 @@ impl Pallet { receiving_account: Junction, ) -> DispatchResult { UserMigrations::::try_mutate((project_id, origin), |maybe_migrations| -> DispatchResult { - let location_user = Location::new(0, receiving_account); - let migration_origin = MigrationOrigin { user: location_user, id, participation_type }; + let migration_origin = MigrationOrigin { user: receiving_account, id, participation_type }; let vesting_time: u64 = vesting_time.try_into().map_err(|_| Error::::BadMath)?; let migration_info: MigrationInfo = (ct_amount, vesting_time).into(); let migration = Migration::new(migration_origin, migration_info); diff --git a/pallets/funding/src/functions/misc.rs b/pallets/funding/src/functions/misc.rs index 974e6aa5f..2750b009c 100644 --- a/pallets/funding/src/functions/misc.rs +++ b/pallets/funding/src/functions/misc.rs @@ -448,16 +448,12 @@ impl Pallet { .ok_or(Error::::BadReceiverAccountSignature)?; let message_bytes = message_to_sign.into_bytes(); match receiver_account { - Junction::AccountId32 { network, id } => - if network.is_none() { - let signature = SrSignature::from_slice(&signature_bytes[..64]) - .map_err(|_| Error::::BadReceiverAccountSignature)?; - let public = SrPublic::from_slice(id).map_err(|_| Error::::BadReceiverAccountSignature)?; - ensure!( - signature.verify(message_bytes.as_slice(), &public), - Error::::BadReceiverAccountSignature - ); - }, + Junction::AccountId32 { network, id } if *network == Some(NetworkId::Polkadot) => { + let signature = SrSignature::from_slice(&signature_bytes[..64]) + .map_err(|_| Error::::BadReceiverAccountSignature)?; + let public = SrPublic::from_slice(id).map_err(|_| Error::::BadReceiverAccountSignature)?; + ensure!(signature.verify(message_bytes.as_slice(), &public), Error::::BadReceiverAccountSignature); + }, Junction::AccountKey20 { network, key } if *network == Some(NetworkId::Ethereum { chain_id: 1 }) => { let message_length = message_bytes.len().to_string().into_bytes(); diff --git a/pallets/funding/src/instantiator/calculations.rs b/pallets/funding/src/instantiator/calculations.rs index ebbaf9398..816ee0632 100644 --- a/pallets/funding/src/instantiator/calculations.rs +++ b/pallets/funding/src/instantiator/calculations.rs @@ -4,6 +4,7 @@ use crate::{MultiplierOf, ParticipationMode}; use core::cmp::Ordering; use itertools::GroupBy; use polimec_common::{ProvideAssetPrice, USD_DECIMALS}; +use sp_core::{ecdsa, hexdisplay::AsBytesRef, keccak_256, sr25519, Pair}; impl< T: Config, @@ -32,7 +33,7 @@ impl< pub fn calculate_evaluation_plmc_spent( &mut self, - evaluations: Vec>, + evaluations: Vec>, ) -> Vec> { let plmc_usd_price = self.execute(|| { >::get_decimals_aware_price(PLMC_FOREIGN_ID, USD_DECIMALS, PLMC_DECIMALS).unwrap() @@ -66,7 +67,7 @@ impl< while !amount_to_bid.is_zero() { let bid_amount = if amount_to_bid <= bucket.amount_left { amount_to_bid } else { bucket.amount_left }; output.push(( - BidParams { bidder: bid.bidder.clone(), amount: bid_amount, mode: bid.mode, asset: bid.asset }, + BidParams::from((bid.bidder.clone(), bid_amount, bid.mode, bid.asset)), bucket.current_price, )); bucket.update(bid_amount); @@ -312,12 +313,7 @@ impl< total_cts_left.saturating_reduce(bid.amount); filtered_bids.push(bid); } else if !total_cts_left.is_zero() { - filtered_bids.push(BidParams { - bidder: bid.bidder.clone(), - amount: total_cts_left, - mode: bid.mode, - asset: bid.asset, - }); + filtered_bids.push(BidParams::from((bid.bidder.clone(), total_cts_left, bid.mode, bid.asset))); total_cts_left = Zero::zero(); } } @@ -344,7 +340,7 @@ impl< pub fn calculate_total_plmc_locked_from_evaluations_and_remainder_contributions( &mut self, - evaluations: Vec>, + evaluations: Vec>, contributions: Vec>, price: PriceOf, slashed: bool, @@ -536,7 +532,7 @@ impl< project_metadata: ProjectMetadataOf, evaluators: Vec>, weights: Vec, - ) -> Vec> { + ) -> Vec> { let funding_target = project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); let evaluation_success_threshold = ::EvaluationSuccessThreshold::get(); // if we use just the threshold, then for big usd targets we lose the evaluation due to PLMC conversion errors in `evaluation_end` let usd_threshold = evaluation_success_threshold * funding_target * 2u128; @@ -564,7 +560,7 @@ impl< let ticket_size = Percent::from_percent(weight) * usd_amount; let token_amount = min_price.reciprocal().unwrap().saturating_mul_int(ticket_size); - BidParams::new(bidder, token_amount, mode, AcceptedFundingAsset::USDT) + BidParams::from((bidder, token_amount, mode, AcceptedFundingAsset::USDT)) }) .collect() } @@ -585,7 +581,7 @@ impl< zip(zip(weights, bidders), modes) .map(|((weight, bidder), mode)| { let token_amount = Percent::from_percent(weight) * total_ct_bid; - BidParams::new(bidder, token_amount, mode, AcceptedFundingAsset::USDT) + BidParams::from((bidder, token_amount, mode, AcceptedFundingAsset::USDT)) }) .collect() } @@ -603,7 +599,7 @@ impl< let ticket_size = Percent::from_percent(weight) * usd_amount; let token_amount = final_price.reciprocal().unwrap().saturating_mul_int(ticket_size); - ContributionParams::new(bidder, token_amount, mode, AcceptedFundingAsset::USDT) + ContributionParams::from((bidder, token_amount, mode, AcceptedFundingAsset::USDT)) }) .collect() } @@ -624,7 +620,7 @@ impl< zip(zip(weights, contributors), modes) .map(|((weight, contributor), mode)| { let token_amount = Percent::from_percent(weight) * total_ct_bought; - ContributionParams::new(contributor, token_amount, mode, AcceptedFundingAsset::USDT) + ContributionParams::from((contributor, token_amount, mode, AcceptedFundingAsset::USDT)) }) .collect() } @@ -795,4 +791,56 @@ impl< T::CommunityRoundDuration::get() + One::one() } + + #[cfg(feature = "std")] + pub fn eth_key_and_sig_from( + &mut self, + seed_string: &str, + project_id: ProjectId, + polimec_account: AccountIdOf, + ) -> (Junction, [u8; 65]) { + let message_to_sign = self.execute(|| Pallet::::get_message_to_sign(polimec_account, project_id)).unwrap(); + let message_to_sign = message_to_sign.into_bytes(); + let ecdsa_pair = ecdsa::Pair::from_string(seed_string, None).unwrap(); + let message_length = message_to_sign.len(); + let message_prefix = alloc::format!("\x19Ethereum Signed Message:\n{}", message_length).into_bytes(); + let expected_message = [&message_prefix[..], &message_to_sign[..]].concat(); + let signature = ecdsa_pair.sign_prehashed(&keccak_256(&expected_message)); + let mut signature_bytes = [0u8; 65]; + signature_bytes[..65].copy_from_slice(signature.as_bytes_ref()); + + match signature_bytes[64] { + 0x00 => signature_bytes[64] = 27, + 0x01 => signature_bytes[64] = 28, + _v => unreachable!("Recovery bit should be always either 0 or 1"), + } + + let compressed_public_key = ecdsa_pair.public().to_raw(); + let public_uncompressed = k256::ecdsa::VerifyingKey::from_sec1_bytes(&compressed_public_key).unwrap(); + let public_uncompressed_point = public_uncompressed.to_encoded_point(false).to_bytes(); + let derived_ethereum_account: [u8; 20] = + keccak_256(&public_uncompressed_point[1..])[12..32].try_into().unwrap(); + let junction = + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: derived_ethereum_account }; + + (junction, signature_bytes) + } + + #[cfg(feature = "std")] + pub fn dot_key_and_sig_from( + &mut self, + seed_string: &str, + project_id: ProjectId, + polimec_account: AccountIdOf, + ) -> (Junction, [u8; 65]) { + let message_to_sign = self.execute(|| Pallet::::get_message_to_sign(polimec_account, project_id)).unwrap(); + let message_to_sign = message_to_sign.into_bytes(); + + let sr_pair = sr25519::Pair::from_string(seed_string, None).unwrap(); + let signature = sr_pair.sign(&message_to_sign); + let mut signature_bytes = [0u8; 65]; + signature_bytes[..64].copy_from_slice(signature.as_bytes_ref()); + let junction = Junction::AccountId32 { network: Some(Polkadot), id: sr_pair.public().to_raw() }; + (junction, signature_bytes) + } } diff --git a/pallets/funding/src/instantiator/chain_interactions.rs b/pallets/funding/src/instantiator/chain_interactions.rs index 32a7c3cee..2fd3411d4 100644 --- a/pallets/funding/src/instantiator/chain_interactions.rs +++ b/pallets/funding/src/instantiator/chain_interactions.rs @@ -432,10 +432,10 @@ impl< pub fn evaluate_for_users( &mut self, project_id: ProjectId, - bonds: Vec>, + bonds: Vec>, ) -> DispatchResultWithPostInfo { let project_policy = self.get_project_metadata(project_id).policy_ipfs_cid.unwrap(); - for UserToUSDBalance { account, usd_amount } in bonds { + for EvaluationParams { account, usd_amount, receiving_account } in bonds { self.execute(|| { crate::Pallet::::do_evaluate( &account.clone(), @@ -443,7 +443,7 @@ impl< usd_amount, generate_did_from_account(account.clone()), project_policy.clone(), - Junction::AccountId32 { network: None, id: T::AccountId32Conversion::convert(account) }, + receiving_account, ) })?; } @@ -465,10 +465,7 @@ impl< did, investor_type: InvestorType::Institutional, whitelisted_policy: project_policy.clone(), - receiving_account: Junction::AccountId32 { - network: None, - id: T::AccountId32Conversion::convert(bid.bidder), - }, + receiving_account: bid.receiving_account, }; crate::Pallet::::do_bid(params) })?; @@ -498,10 +495,7 @@ impl< did, investor_type, whitelisted_policy: project_policy.clone(), - receiving_account: Junction::AccountId32 { - network: None, - id: T::AccountId32Conversion::convert(cont.contributor), - }, + receiving_account: cont.receiving_account, }; self.execute(|| crate::Pallet::::do_contribute(params))?; }, @@ -619,6 +613,7 @@ impl< amount, evaluation.id, ParticipationType::Evaluation, + evaluation.receiving_account, is_successful, ); } @@ -635,7 +630,15 @@ impl< let account = bid.bidder.clone(); assert_eq!(self.execute(|| { Bids::::iter_prefix_values((&project_id, &account)).count() }), 0); let amount: Balance = bid.final_ct_amount(); - self.assert_migration(project_id, account, amount, bid.id, ParticipationType::Bid, is_successful); + self.assert_migration( + project_id, + account, + amount, + bid.id, + ParticipationType::Bid, + bid.receiving_account, + is_successful, + ); } } @@ -656,6 +659,7 @@ impl< amount, contribution.id, ParticipationType::Contribution, + contribution.receiving_account, is_successful, ); } @@ -668,35 +672,28 @@ impl< amount: Balance, id: u32, participation_type: ParticipationType, + receiving_account: Junction, should_exist: bool, ) { - match (should_exist, self.execute(|| UserMigrations::::get((project_id, account.clone())))) { - // User has migrations, so we need to check if any matches our criteria - (_, Some((_, migrations))) => { - let maybe_migration = migrations.into_iter().find(|migration| { - let user = T::AccountId32Conversion::convert(account.clone()); - let location_user = Location::new(0,AccountId32 {network: None, id: user}); - matches!(&migration.origin, MigrationOrigin { user: m_user, id: m_id, participation_type: m_participation_type } if *m_user == location_user && *m_id == id && *m_participation_type == participation_type) - }); - match maybe_migration { - // Migration exists so we check if the amount is correct and if it should exist - Some(migration) => { - assert!(should_exist); - assert_close_enough!( - migration.info.contribution_token_amount, - amount, - Perquintill::from_percent(99u64) - ); - }, - - // Migration doesn't exist so we check if it should not exist - None => assert!(should_exist), - } - }, - // User does not have any migrations, so the migration should not exist - (false, None) => (), - (true, None) => panic!("No migration should have been found"), + let Some((_migration_status, user_migrations)) = + self.execute(|| UserMigrations::::get((project_id, account.clone()))) + else { + assert!(!should_exist); + return; }; + let expected_migration_origin = MigrationOrigin { user: receiving_account, id, participation_type }; + + let Some(migration) = + user_migrations.into_iter().find(|migration| migration.origin == expected_migration_origin) + else { + assert!(!should_exist); + return; + }; + assert_close_enough!( + migration.info.contribution_token_amount, + amount, + Perquintill::from_rational(999u64, 1000u64) + ); } pub fn create_new_project( @@ -738,7 +735,7 @@ impl< project_metadata: ProjectMetadataOf, issuer: AccountIdOf, maybe_did: Option, - evaluations: Vec>, + evaluations: Vec>, ) -> ProjectId { let project_id = self.create_evaluating_project(project_metadata, issuer.clone(), maybe_did); @@ -782,7 +779,7 @@ impl< project_metadata: ProjectMetadataOf, issuer: AccountIdOf, maybe_did: Option, - evaluations: Vec>, + evaluations: Vec>, bids: Vec>, ) -> ProjectId { let project_id = @@ -841,7 +838,7 @@ impl< project_metadata: ProjectMetadataOf, issuer: AccountIdOf, maybe_did: Option, - evaluations: Vec>, + evaluations: Vec>, bids: Vec>, contributions: Vec>, ) -> ProjectId { @@ -909,7 +906,7 @@ impl< project_metadata: ProjectMetadataOf, issuer: AccountIdOf, maybe_did: Option, - evaluations: Vec>, + evaluations: Vec>, bids: Vec>, community_contributions: Vec>, remainder_contributions: Vec>, @@ -1016,7 +1013,7 @@ impl< project_metadata: ProjectMetadataOf, issuer: AccountIdOf, maybe_did: Option, - evaluations: Vec>, + evaluations: Vec>, bids: Vec>, community_contributions: Vec>, remainder_contributions: Vec>, @@ -1043,7 +1040,7 @@ impl< status: ProjectStatus>, project_metadata: ProjectMetadataOf, issuer: AccountIdOf, - evaluations: Vec>, + evaluations: Vec>, bids: Vec>, community_contributions: Vec>, remainder_contributions: Vec>, diff --git a/pallets/funding/src/instantiator/traits.rs b/pallets/funding/src/instantiator/traits.rs index f75ca4056..3217c565c 100644 --- a/pallets/funding/src/instantiator/traits.rs +++ b/pallets/funding/src/instantiator/traits.rs @@ -1,5 +1,6 @@ use super::{Config, UserToPLMCBalance, Vec}; use crate::Balance; +// use itertools::Itertools; pub trait Deposits { fn existential_deposits(&self) -> Vec>; @@ -14,16 +15,34 @@ pub enum MergeOperation { Add, Subtract, } -pub trait AccountMerge: Accounts + Sized { +pub trait AccountMerge: + Clone + Accounts + Sized + IntoIterator + FromIterator +{ /// The inner type of the Vec implementing this Trait. - type Inner; - /// Merge accounts in the list based on the operation. + type Inner: PartialEq + Clone; + + fn get_account(inner: Self::Inner) -> Self::Account; + + /// Merge accounts in the list based on the operation. Only the first receiving account will be used for the merged map. fn merge_accounts(&self, ops: MergeOperation) -> Self; + /// Subtract amount of the matching accounts in the other list from the current list. /// If the account is not present in the current list, it is ignored. - fn subtract_accounts(&self, other_list: Self) -> Self; + fn subtract_accounts(&self, other_list: Self) -> Self { + let current_accounts = self.accounts(); + let filtered_list: Self = + other_list.into_iter().filter(|x| current_accounts.contains(&Self::get_account(x.clone()))).collect(); + let combined: Self = self.clone().into_iter().chain(filtered_list).collect(); + combined.merge_accounts(MergeOperation::Subtract) + } + + fn sum_accounts(&self, other_list: Self) -> Self { + let self_iter = self.clone().into_iter(); + let other_iter = other_list.into_iter(); - fn sum_accounts(&self, other_list: Self) -> Self; + let combined: Self = self_iter.chain(other_iter).collect(); + combined.merge_accounts(MergeOperation::Add) + } } pub trait Total { diff --git a/pallets/funding/src/instantiator/types.rs b/pallets/funding/src/instantiator/types.rs index 36bbc2146..167a7c0b8 100644 --- a/pallets/funding/src/instantiator/types.rs +++ b/pallets/funding/src/instantiator/types.rs @@ -17,7 +17,7 @@ pub struct TestProjectParams { pub expected_state: ProjectStatus>, pub metadata: ProjectMetadataOf, pub issuer: AccountIdOf, - pub evaluations: Vec>, + pub evaluations: Vec>, pub bids: Vec>, pub community_contributions: Vec>, pub remainder_contributions: Vec>, @@ -76,6 +76,10 @@ impl From<(AccountIdOf, Balance)> for UserToPLMCBalance { impl AccountMerge for Vec> { type Inner = UserToPLMCBalance; + fn get_account(inner: Self::Inner) -> Self::Account { + inner.account + } + fn merge_accounts(&self, ops: MergeOperation) -> Self { let mut btree = BTreeMap::new(); for UserToPLMCBalance { account, plmc_amount } in self.iter() { @@ -91,20 +95,6 @@ impl AccountMerge for Vec> { } btree.into_iter().map(|(account, plmc_amount)| UserToPLMCBalance::new(account, plmc_amount)).collect() } - - fn subtract_accounts(&self, other_list: Self) -> Self { - let current_accounts = self.accounts(); - let filtered_list = other_list.into_iter().filter(|x| current_accounts.contains(&x.account)).collect_vec(); - let mut new_list = self.clone(); - new_list.extend(filtered_list); - new_list.merge_accounts(MergeOperation::Subtract) - } - - fn sum_accounts(&self, mut other_list: Self) -> Self { - let mut output = self.clone(); - output.append(&mut other_list); - output.merge_accounts(MergeOperation::Add) - } } impl Total for Vec> { @@ -115,65 +105,94 @@ impl Total for Vec> { #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))] -pub struct UserToUSDBalance { +pub struct EvaluationParams { + pub account: AccountIdOf, + pub usd_amount: Balance, + pub receiving_account: Junction, +} +impl EvaluationParams { + pub fn new(account: AccountIdOf, usd_amount: Balance, receiving_account: Junction) -> Self { + EvaluationParams:: { account, usd_amount, receiving_account } + } +} +impl From<(AccountIdOf, Balance, Junction)> for EvaluationParams { + fn from((account, usd_amount, receiving_account): (AccountIdOf, Balance, Junction)) -> Self { + EvaluationParams::::new(account, usd_amount, receiving_account) + } +} +impl From<(AccountIdOf, Balance)> for EvaluationParams { + fn from((account, usd_amount): (AccountIdOf, Balance)) -> Self { + let receiving_account = Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(account.clone()), + }; + EvaluationParams::::new(account, usd_amount, receiving_account) + } +} +impl Accounts for Vec> { + type Account = AccountIdOf; + + fn accounts(&self) -> Vec { + let mut btree = BTreeSet::new(); + for EvaluationParams { account, usd_amount: _, receiving_account: _ } in self { + btree.insert(account.clone()); + } + btree.into_iter().collect_vec() + } +} + +#[derive(Clone, PartialEq)] +pub struct UserToUSDAmount { pub account: AccountIdOf, pub usd_amount: Balance, } -impl UserToUSDBalance { +impl UserToUSDAmount { pub fn new(account: AccountIdOf, usd_amount: Balance) -> Self { Self { account, usd_amount } } } -impl From<(AccountIdOf, Balance)> for UserToUSDBalance { +impl From<(AccountIdOf, Balance)> for UserToUSDAmount { fn from((account, usd_amount): (AccountIdOf, Balance)) -> Self { - UserToUSDBalance::::new(account, usd_amount) + UserToUSDAmount::::new(account, usd_amount) } } -impl Accounts for Vec> { +impl Accounts for Vec> { type Account = AccountIdOf; fn accounts(&self) -> Vec { let mut btree = BTreeSet::new(); - for UserToUSDBalance { account, usd_amount: _ } in self { + for UserToUSDAmount { account, usd_amount: _ } in self { btree.insert(account.clone()); } btree.into_iter().collect_vec() } } -impl AccountMerge for Vec> { - type Inner = UserToUSDBalance; +impl AccountMerge for Vec> { + type Inner = UserToUSDAmount; + + fn get_account(inner: Self::Inner) -> Self::Account { + inner.account + } fn merge_accounts(&self, ops: MergeOperation) -> Self { let mut btree = BTreeMap::new(); - for UserToUSDBalance { account, usd_amount } in self.iter() { + for UserToUSDAmount { account, usd_amount } in self.iter() { btree .entry(account.clone()) - .and_modify(|e: &mut Balance| { - *e = match ops { - MergeOperation::Add => e.saturating_add(*usd_amount), - MergeOperation::Subtract => e.saturating_sub(*usd_amount), - } + .and_modify(|stored_usd_amount: &mut Balance| match ops { + MergeOperation::Add => { + *stored_usd_amount = stored_usd_amount.saturating_add(*usd_amount); + }, + MergeOperation::Subtract => { + *stored_usd_amount = stored_usd_amount.saturating_sub(*usd_amount); + }, }) .or_insert(*usd_amount); } - btree.into_iter().map(|(account, usd_amount)| UserToUSDBalance::new(account, usd_amount)).collect() - } - - fn subtract_accounts(&self, other_list: Self) -> Self { - let current_accounts = self.accounts(); - let filtered_list = other_list.into_iter().filter(|x| current_accounts.contains(&x.account)).collect_vec(); - let mut new_list = self.clone(); - new_list.extend(filtered_list); - new_list.merge_accounts(MergeOperation::Subtract) - } - - fn sum_accounts(&self, mut other_list: Self) -> Self { - let mut output = self.clone(); - output.append(&mut other_list); - output.merge_accounts(MergeOperation::Add) + btree.into_iter().map(|(account, usd_amount)| UserToUSDAmount::new(account, usd_amount)).collect() } } -impl Total for Vec> { +impl Total for Vec> { fn total(&self) -> Balance { self.iter().map(|x| x.usd_amount).sum() } @@ -214,6 +233,10 @@ impl Accounts for Vec> { impl AccountMerge for Vec> { type Inner = UserToFundingAsset; + fn get_account(inner: Self::Inner) -> Self::Account { + inner.account + } + fn merge_accounts(&self, ops: MergeOperation) -> Self { let mut btree = BTreeMap::new(); for UserToFundingAsset { account, asset_amount, asset_id } in self.iter() { @@ -281,34 +304,93 @@ pub struct BidParams { pub amount: Balance, pub mode: ParticipationMode, pub asset: AcceptedFundingAsset, + pub receiving_account: Junction, } impl BidParams { - pub fn new(bidder: AccountIdOf, amount: Balance, mode: ParticipationMode, asset: AcceptedFundingAsset) -> Self { - Self { bidder, amount, mode, asset } - } - - pub fn new_with_defaults(bidder: AccountIdOf, amount: Balance) -> Self { - Self { bidder, amount, mode: ParticipationMode::Classic(1u8), asset: AcceptedFundingAsset::USDT } + pub fn new( + bidder: AccountIdOf, + amount: Balance, + mode: ParticipationMode, + asset: AcceptedFundingAsset, + receiving_account: Junction, + ) -> Self { + Self { bidder, amount, mode, asset, receiving_account } } } impl From<(AccountIdOf, Balance)> for BidParams { fn from((bidder, amount): (AccountIdOf, Balance)) -> Self { - Self { bidder, amount, mode: ParticipationMode::Classic(1u8), asset: AcceptedFundingAsset::USDT } + Self { + bidder: bidder.clone(), + amount, + mode: ParticipationMode::Classic(1u8), + asset: AcceptedFundingAsset::USDT, + receiving_account: Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(bidder.clone()), + }, + } } } impl From<(AccountIdOf, Balance, ParticipationMode)> for BidParams { fn from((bidder, amount, mode): (AccountIdOf, Balance, ParticipationMode)) -> Self { - Self { bidder, amount, mode, asset: AcceptedFundingAsset::USDT } + Self { + bidder: bidder.clone(), + amount, + mode, + asset: AcceptedFundingAsset::USDT, + receiving_account: Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(bidder.clone()), + }, + } + } +} +impl From<(AccountIdOf, Balance, AcceptedFundingAsset)> for BidParams { + fn from((bidder, amount, asset): (AccountIdOf, Balance, AcceptedFundingAsset)) -> Self { + Self { + bidder: bidder.clone(), + amount, + mode: ParticipationMode::Classic(1u8), + asset, + receiving_account: Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(bidder.clone()), + }, + } } } impl From<(AccountIdOf, Balance, ParticipationMode, AcceptedFundingAsset)> for BidParams { fn from((bidder, amount, mode, asset): (AccountIdOf, Balance, ParticipationMode, AcceptedFundingAsset)) -> Self { - Self { bidder, amount, mode, asset } + Self { + bidder: bidder.clone(), + amount, + mode, + asset, + receiving_account: Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(bidder.clone()), + }, + } } } -impl From<(AccountIdOf, Balance, AcceptedFundingAsset)> for BidParams { - fn from((bidder, amount, asset): (AccountIdOf, Balance, AcceptedFundingAsset)) -> Self { - Self { bidder, amount, mode: ParticipationMode::Classic(1u8), asset } +impl From<(AccountIdOf, Balance, AcceptedFundingAsset, Junction)> for BidParams { + fn from( + (bidder, amount, asset, receiving_account): (AccountIdOf, Balance, AcceptedFundingAsset, Junction), + ) -> Self { + Self { bidder, amount, mode: ParticipationMode::Classic(1u8), asset, receiving_account } + } +} +impl From<(AccountIdOf, Balance, ParticipationMode, AcceptedFundingAsset, Junction)> for BidParams { + fn from( + (bidder, amount, mode, asset, receiving_account): ( + AccountIdOf, + Balance, + ParticipationMode, + AcceptedFundingAsset, + Junction, + ), + ) -> Self { + Self { bidder, amount, mode, asset, receiving_account } } } impl From> for (AccountIdOf, AssetIdOf) { @@ -348,6 +430,7 @@ pub struct ContributionParams { pub amount: Balance, pub mode: ParticipationMode, pub asset: AcceptedFundingAsset, + pub receiving_account: Junction, } impl ContributionParams { pub fn new( @@ -355,29 +438,82 @@ impl ContributionParams { amount: Balance, mode: ParticipationMode, asset: AcceptedFundingAsset, + receiving_account: Junction, ) -> Self { - Self { contributor, amount, mode, asset } - } - - pub fn new_with_defaults(contributor: AccountIdOf, amount: Balance) -> Self { - Self { contributor, amount, mode: ParticipationMode::Classic(1u8), asset: AcceptedFundingAsset::USDT } + Self { contributor, amount, mode, asset, receiving_account } } } impl From<(AccountIdOf, Balance)> for ContributionParams { fn from((contributor, amount): (AccountIdOf, Balance)) -> Self { - Self { contributor, amount, mode: ParticipationMode::Classic(1u8), asset: AcceptedFundingAsset::USDT } + Self { + contributor: contributor.clone(), + amount, + mode: ParticipationMode::Classic(1u8), + asset: AcceptedFundingAsset::USDT, + receiving_account: Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(contributor.clone()), + }, + } } } impl From<(AccountIdOf, Balance, ParticipationMode)> for ContributionParams { fn from((contributor, amount, mode): (AccountIdOf, Balance, ParticipationMode)) -> Self { - Self { contributor, amount, mode, asset: AcceptedFundingAsset::USDT } + Self { + contributor: contributor.clone(), + amount, + mode, + asset: AcceptedFundingAsset::USDT, + receiving_account: Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(contributor.clone()), + }, + } } } impl From<(AccountIdOf, Balance, ParticipationMode, AcceptedFundingAsset)> for ContributionParams { fn from( (contributor, amount, mode, asset): (AccountIdOf, Balance, ParticipationMode, AcceptedFundingAsset), ) -> Self { - Self { contributor, amount, mode, asset } + Self { + contributor: contributor.clone(), + amount, + mode, + asset, + receiving_account: Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(contributor.clone()), + }, + } + } +} +impl From<(AccountIdOf, Balance, AcceptedFundingAsset)> for ContributionParams { + fn from((contributor, amount, asset): (AccountIdOf, Balance, AcceptedFundingAsset)) -> Self { + Self { + contributor: contributor.clone(), + amount, + mode: ParticipationMode::Classic(1u8), + asset, + receiving_account: Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(contributor.clone()), + }, + } + } +} +impl From<(AccountIdOf, Balance, ParticipationMode, AcceptedFundingAsset, Junction)> + for ContributionParams +{ + fn from( + (contributor, amount, mode, asset, receiving_account): ( + AccountIdOf, + Balance, + ParticipationMode, + AcceptedFundingAsset, + Junction, + ), + ) -> Self { + Self { contributor, amount, mode, asset, receiving_account } } } impl Accounts for Vec> { diff --git a/pallets/funding/src/lib.rs b/pallets/funding/src/lib.rs index f96c0bdbe..ef35d7478 100644 --- a/pallets/funding/src/lib.rs +++ b/pallets/funding/src/lib.rs @@ -759,8 +759,10 @@ pub mod pallet { let (account, did, _investor_type, whitelisted_policy) = T::InvestorOrigin::ensure_origin(origin, &jwt, T::VerifierPublicKey::get())?; - let receiving_account = - Junction::AccountId32 { network: None, id: T::AccountId32Conversion::convert(account.clone()) }; + let receiving_account = Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(account.clone()), + }; Self::do_evaluate(&account, project_id, usd_amount, did, whitelisted_policy, receiving_account) } @@ -811,8 +813,10 @@ pub mod pallet { let (bidder, did, investor_type, whitelisted_policy) = T::InvestorOrigin::ensure_origin(origin, &jwt, T::VerifierPublicKey::get())?; - let receiving_account = - Junction::AccountId32 { network: None, id: T::AccountId32Conversion::convert(bidder.clone()) }; + let receiving_account = Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(bidder.clone()), + }; let params = DoBidParams:: { bidder, @@ -901,8 +905,10 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { let (contributor, did, investor_type, whitelisted_policy) = T::InvestorOrigin::ensure_origin(origin, &jwt, T::VerifierPublicKey::get())?; - let receiving_account = - Junction::AccountId32 { network: None, id: T::AccountId32Conversion::convert(contributor.clone()) }; + let receiving_account = Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id: T::AccountId32Conversion::convert(contributor.clone()), + }; let params = DoContributeParams:: { contributor, project_id, diff --git a/pallets/funding/src/tests/2_evaluation.rs b/pallets/funding/src/tests/2_evaluation.rs index 444962df4..d83f34fcc 100644 --- a/pallets/funding/src/tests/2_evaluation.rs +++ b/pallets/funding/src/tests/2_evaluation.rs @@ -519,7 +519,7 @@ mod evaluate_extrinsic { let project_metadata = default_project_metadata(issuer); let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer, None); - let evaluation = UserToUSDBalance::new(EVALUATOR_1, 500 * USD_UNIT); + let evaluation = EvaluationParams::from((EVALUATOR_1, 500 * USD_UNIT)); let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); inst.mint_plmc_ed_if_required(necessary_plmc.accounts()); @@ -547,7 +547,7 @@ mod evaluate_extrinsic { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let project_metadata = default_project_metadata(ISSUER_1); let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); - let evaluation = UserToUSDBalance::new(EVALUATOR_1, 500 * USD_UNIT); + let evaluation = EvaluationParams::from((EVALUATOR_1, 500 * USD_UNIT)); let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); let plmc_existential_deposits = necessary_plmc.accounts().existential_deposits(); @@ -586,10 +586,7 @@ mod evaluate_extrinsic { early_usd_amount: evaluation.usd_amount, late_usd_amount: 0, when: 1, - receiving_account: Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(EVALUATOR_1), - }, + receiving_account: polkadot_junction!(EVALUATOR_1), }; assert_eq!(stored_evaluation, &expected_evaluation_item); }); @@ -601,7 +598,7 @@ mod evaluate_extrinsic { let issuer = ISSUER_1; let project_metadata = default_project_metadata(issuer); - let evaluation = UserToUSDBalance::new(EVALUATOR_4, 1_000_000 * USD_UNIT); + let evaluation = EvaluationParams::from((EVALUATOR_4, 1_000_000 * USD_UNIT)); let plmc_required = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); let frozen_amount = plmc_required[0].plmc_amount; @@ -690,6 +687,72 @@ mod evaluate_extrinsic { pre_slash_treasury_balance + ::EvaluatorSlash::get() * frozen_amount ); } + + #[test] + fn evaluate_on_ethereum_project() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + + let mut project_metadata = default_project_metadata(ISSUER_1); + project_metadata.participants_account_type = ParticipantsAccountType::Ethereum; + + let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); + let jwt = get_mock_jwt_with_cid( + EVALUATOR_1, + InvestorType::Retail, + generate_did_from_account(EVALUATOR_1), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + let (eth_acc, eth_sig) = inst.eth_key_and_sig_from("//EVALUATOR1", project_id, EVALUATOR_1); + + let plmc = + inst.calculate_evaluation_plmc_spent(vec![EvaluationParams::from((EVALUATOR_1, 500 * USD_UNIT))]); + inst.mint_plmc_ed_if_required(plmc.accounts()); + inst.mint_plmc_to(plmc.clone()); + + assert_ok!(inst.execute(|| { + PolimecFunding::evaluate_with_receiving_account( + RuntimeOrigin::signed(EVALUATOR_1), + jwt, + project_id, + 500 * USD_UNIT, + eth_acc, + eth_sig, + ) + })); + } + + #[test] + fn evaluate_with_different_receiver_polkadot_account() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + + let project_metadata = default_project_metadata(ISSUER_1); + + let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); + let jwt = get_mock_jwt_with_cid( + EVALUATOR_1, + InvestorType::Retail, + generate_did_from_account(EVALUATOR_1), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + let (dot_acc, dot_sig) = inst.dot_key_and_sig_from("//EVALUATOR1", project_id, EVALUATOR_1); + let plmc = + inst.calculate_evaluation_plmc_spent(vec![EvaluationParams::from((EVALUATOR_1, 500 * USD_UNIT))]); + inst.mint_plmc_ed_if_required(plmc.accounts()); + inst.mint_plmc_to(plmc.clone()); + + assert_ok!(inst.execute(|| { + PolimecFunding::evaluate_with_receiving_account( + RuntimeOrigin::signed(EVALUATOR_1), + jwt, + project_id, + 500 * USD_UNIT, + dot_acc, + dot_sig, + ) + })); + } } #[cfg(test)] @@ -750,7 +813,7 @@ mod evaluate_extrinsic { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let issuer = ISSUER_1; let project_metadata = default_project_metadata(issuer); - let evaluations = vec![UserToUSDBalance::new(EVALUATOR_1, 1000 * USD_UNIT)]; + let evaluations = vec![EvaluationParams::from((EVALUATOR_1, 1000 * USD_UNIT))]; let evaluating_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone()); let mut plmc_insufficient_existential_deposit = evaluating_plmc.accounts().existential_deposits(); @@ -770,9 +833,9 @@ mod evaluate_extrinsic { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let project_metadata = default_project_metadata(ISSUER_1); let evaluations = (0u32..::MaxEvaluationsPerProject::get()) - .map(|i| UserToUSDBalance::::new(i as u64 + 420, 100u128 * CT_UNIT)) + .map(|i| EvaluationParams::::from((i as u64 + 420, 100u128 * CT_UNIT))) .collect_vec(); - let failing_evaluation = UserToUSDBalance::new(EVALUATOR_1, 1000 * CT_UNIT); + let failing_evaluation = EvaluationParams::from((EVALUATOR_1, 1000 * CT_UNIT)); let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); @@ -798,9 +861,9 @@ mod evaluate_extrinsic { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let project_metadata = default_project_metadata(ISSUER_1); let evaluations = (0u32..::MaxEvaluationsPerUser::get()) - .map(|_| UserToUSDBalance::::new(EVALUATOR_1, 100u128 * USD_UNIT)) + .map(|_| EvaluationParams::::from((EVALUATOR_1, 100u128 * USD_UNIT))) .collect_vec(); - let failing_evaluation = UserToUSDBalance::new(EVALUATOR_1, 100 * USD_UNIT); + let failing_evaluation = EvaluationParams::from((EVALUATOR_1, 100 * USD_UNIT)); let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); @@ -829,7 +892,7 @@ mod evaluate_extrinsic { let project_metadata = default_project_metadata(issuer); let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer, None); - let evaluation = UserToUSDBalance::new(EVALUATOR_1, 500 * USD_UNIT); + let evaluation = EvaluationParams::from((EVALUATOR_1, 500 * USD_UNIT)); let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); let ed = necessary_plmc.accounts().existential_deposits(); @@ -868,6 +931,7 @@ mod evaluate_extrinsic { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let project_metadata = default_project_metadata(ISSUER_1); let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); + assert_err!( inst.execute(|| crate::Pallet::::do_evaluate( &(&ISSUER_1 + 1), @@ -875,10 +939,7 @@ mod evaluate_extrinsic { 500 * USD_UNIT, generate_did_from_account(ISSUER_1), project_metadata.clone().policy_ipfs_cid.unwrap(), - Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(ISSUER_1 + 1) - }, + polkadot_junction!(ISSUER_1 + 1) )), Error::::ParticipationToOwnProject ); @@ -891,7 +952,7 @@ mod evaluate_extrinsic { let project_metadata = default_project_metadata(issuer); let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer, None); - let evaluation = UserToUSDBalance::new(EVALUATOR_1, 500 * USD_UNIT); + let evaluation = EvaluationParams::from((EVALUATOR_1, 500 * USD_UNIT)); let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); inst.mint_plmc_ed_if_required(necessary_plmc.accounts()); diff --git a/pallets/funding/src/tests/3_auction.rs b/pallets/funding/src/tests/3_auction.rs index 889e6cb7d..dd208cc93 100644 --- a/pallets/funding/src/tests/3_auction.rs +++ b/pallets/funding/src/tests/3_auction.rs @@ -325,10 +325,7 @@ mod round_flow { did, investor_type, whitelisted_policy: project_metadata.clone().policy_ipfs_cid.unwrap(), - receiving_account: Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(BIDDER_1) - }, + receiving_account: polkadot_junction!(BIDDER_1) }), Error::::IncorrectRound ); @@ -355,12 +352,12 @@ mod bid_extrinsic { let mut evaluations = default_evaluations(); let evaluator_bidder = 69u64; let evaluation_amount = 420 * USD_UNIT; - let evaluator_bid = BidParams::new( + let evaluator_bid = BidParams::from(( evaluator_bidder, 600 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); evaluations.push((evaluator_bidder, evaluation_amount).into()); let project_id = inst.create_auctioning_project(project_metadata.clone(), issuer, None, evaluations); @@ -434,12 +431,24 @@ mod bid_extrinsic { let evaluations = default_evaluations(); - let usdt_bid = - BidParams::new(BIDDER_1, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT); - let usdc_bid = - BidParams::new(BIDDER_1, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDC); - let dot_bid = - BidParams::new(BIDDER_1, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::DOT); + let usdt_bid = BidParams::from(( + BIDDER_1, + 10_000 * CT_UNIT, + ParticipationMode::Classic(1u8), + AcceptedFundingAsset::USDT, + )); + let usdc_bid = BidParams::from(( + BIDDER_1, + 10_000 * CT_UNIT, + ParticipationMode::Classic(1u8), + AcceptedFundingAsset::USDC, + )); + let dot_bid = BidParams::from(( + BIDDER_1, + 10_000 * CT_UNIT, + ParticipationMode::Classic(1u8), + AcceptedFundingAsset::DOT, + )); let plmc_fundings = inst.calculate_auction_plmc_charged_with_given_price( &vec![usdt_bid.clone(), usdc_bid.clone(), dot_bid.clone()], @@ -686,7 +695,7 @@ mod bid_extrinsic { inst.create_auctioning_project(project_metadata.clone(), issuer, None, default_evaluations()); let bid = - BidParams::new(BIDDER_4, 500 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT); + BidParams::from((BIDDER_4, 500 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)); let plmc_required = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( &vec![bid.clone()], project_metadata.clone(), @@ -767,7 +776,7 @@ mod bid_extrinsic { inst.create_auctioning_project(project_metadata.clone(), issuer, None, default_evaluations()); let bid = - BidParams::new(BIDDER_4, 500 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT); + BidParams::from((BIDDER_4, 500 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT)); let plmc_required = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( &vec![bid.clone()], project_metadata.clone(), @@ -1176,6 +1185,85 @@ mod bid_extrinsic { assert_eq!(post_settlement_buyer_usdt, usdt_ed + USDT_PARTICIPATION + otm_usdt_fee); assert_eq!(issuer_funding_account, Zero::zero()); } + + #[test] + fn bid_on_ethereum_project() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + + let mut project_metadata = default_project_metadata(ISSUER_1); + project_metadata.participants_account_type = ParticipantsAccountType::Ethereum; + + let project_id = + inst.create_auctioning_project(project_metadata.clone(), ISSUER_1, None, default_eth_evaluations()); + let jwt = get_mock_jwt_with_cid( + BIDDER_1, + InvestorType::Professional, + generate_did_from_account(BIDDER_1), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + let (eth_acc, eth_sig) = inst.eth_key_and_sig_from("//BIDDER1", project_id, BIDDER_1); + let bid = BidParams::from((BIDDER_1, 500 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT)); + let mint_amount = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( + &vec![bid], + project_metadata.clone(), + None, + ); + inst.mint_funding_asset_ed_if_required(mint_amount.to_account_asset_map()); + inst.mint_funding_asset_to(mint_amount.clone()); + + assert_ok!(inst.execute(|| { + PolimecFunding::bid_with_receiving_account( + RuntimeOrigin::signed(BIDDER_1), + jwt, + project_id, + 500 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + eth_acc, + eth_sig, + ) + })); + } + + #[test] + fn bid_with_different_receiver_polkadot_account() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + + let project_metadata = default_project_metadata(ISSUER_1); + + let project_id = + inst.create_auctioning_project(project_metadata.clone(), ISSUER_1, None, default_evaluations()); + let jwt = get_mock_jwt_with_cid( + BIDDER_1, + InvestorType::Professional, + generate_did_from_account(BIDDER_1), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + let (dot_acc, dot_sig) = inst.dot_key_and_sig_from("//BIDDER1", project_id, BIDDER_1); + let bid = BidParams::from((BIDDER_1, 500 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT)); + let mint_amount = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( + &vec![bid], + project_metadata.clone(), + None, + ); + inst.mint_funding_asset_ed_if_required(mint_amount.to_account_asset_map()); + inst.mint_funding_asset_to(mint_amount.clone()); + + assert_ok!(inst.execute(|| { + PolimecFunding::bid_with_receiving_account( + RuntimeOrigin::signed(BIDDER_1), + jwt, + project_id, + 500 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + dot_acc, + dot_sig, + ) + })); + } } #[cfg(test)] @@ -1190,12 +1278,12 @@ mod bid_extrinsic { let mut evaluations = default_evaluations(); let evaluator_bidder = 69; let evaluation_amount = 420 * USD_UNIT; - let evaluator_bid = BidParams::new( + let evaluator_bid = BidParams::from(( evaluator_bidder, 600 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); evaluations.push((evaluator_bidder, evaluation_amount).into()); let project_id = inst.create_auctioning_project(project_metadata.clone(), issuer, None, evaluations); @@ -1224,12 +1312,12 @@ mod bid_extrinsic { let evaluator_bidder = 69; let evaluation_amount = 420 * USD_UNIT; - let evaluator_bid = BidParams::new( + let evaluator_bid = BidParams::from(( evaluator_bidder, 600 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); evaluations_1.push((evaluator_bidder, evaluation_amount).into()); let _project_id_1 = @@ -1296,10 +1384,7 @@ mod bid_extrinsic { did, investor_type, whitelisted_policy: project_metadata.clone().policy_ipfs_cid.unwrap(), - receiving_account: Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(BIDDER_2) - }, + receiving_account: polkadot_junction!(BIDDER_2) }), Error::::IncorrectRound ); @@ -1339,12 +1424,12 @@ mod bid_extrinsic { let remaining_ct = current_bucket.amount_left; // This bid should be split in 2, but the second one should fail, making the whole extrinsic fail and roll back storage - let failing_bid = BidParams::::new( + let failing_bid = BidParams::::from(( BIDDER_1, remaining_ct + 5000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); let plmc_for_failing_bid = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( &vec![failing_bid.clone()], project_metadata.clone(), @@ -1448,12 +1533,12 @@ mod bid_extrinsic { let remaining_ct = current_bucket.amount_left; // This bid should be split in 2, but the second one should fail, making the whole extrinsic fail and roll back storage - let failing_bid = BidParams::::new( + let failing_bid = BidParams::::from(( BIDDER_1, remaining_ct + 5000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); let plmc_for_failing_bid = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( &vec![failing_bid.clone()], project_metadata.clone(), @@ -1557,10 +1642,7 @@ mod bid_extrinsic { did: generate_did_from_account(BIDDER_1), investor_type: InvestorType::Professional, whitelisted_policy: project_metadata.clone().policy_ipfs_cid.unwrap(), - receiving_account: Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(BIDDER_1) - }, + receiving_account: polkadot_junction!(BIDDER_1) }), Error::::TooLow ); @@ -1577,10 +1659,7 @@ mod bid_extrinsic { did: generate_did_from_account(BIDDER_1), investor_type: InvestorType::Institutional, whitelisted_policy: project_metadata.clone().policy_ipfs_cid.unwrap(), - receiving_account: Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(BIDDER_2) - }, + receiving_account: polkadot_junction!(BIDDER_2) }), Error::::TooLow ); @@ -1648,10 +1727,7 @@ mod bid_extrinsic { did: generate_did_from_account(BIDDER_1), investor_type: InvestorType::Professional, whitelisted_policy: project_metadata.clone().policy_ipfs_cid.unwrap(), - receiving_account: Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(BIDDER_2) - }, + receiving_account: polkadot_junction!(BIDDER_2) })); }); let smallest_ct_amount_at_20k_usd = bucket_increase_price @@ -1671,10 +1747,7 @@ mod bid_extrinsic { did: generate_did_from_account(BIDDER_1), investor_type: InvestorType::Institutional, whitelisted_policy: project_metadata.clone().policy_ipfs_cid.unwrap(), - receiving_account: Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(BIDDER_3) - }, + receiving_account: polkadot_junction!(BIDDER_3) })); }); } @@ -1826,10 +1899,7 @@ mod bid_extrinsic { did: generate_did_from_account(ISSUER_1), investor_type: InvestorType::Professional, whitelisted_policy: project_metadata.clone().policy_ipfs_cid.unwrap(), - receiving_account: Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(ISSUER_1) - }, + receiving_account: polkadot_junction!(ISSUER_1) })), Error::::ParticipationToOwnProject ); @@ -1841,12 +1911,12 @@ mod bid_extrinsic { let project_metadata = default_project_metadata(ISSUER_1); let project_id = inst.create_auctioning_project(project_metadata.clone(), ISSUER_1, None, default_evaluations()); - let bids = [BidParams::::new( + let bids = [BidParams::::from(( BIDDER_1, 10_000, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDC, - )]; + ))]; let did = generate_did_from_account(bids[0].bidder); let investor_type = InvestorType::Institutional; @@ -1861,10 +1931,7 @@ mod bid_extrinsic { did, investor_type, whitelisted_policy: project_metadata.clone().policy_ipfs_cid.unwrap(), - receiving_account: Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(bids[0].bidder), - }, + receiving_account: polkadot_junction!(bids[0].bidder), }) }); frame_support::assert_err!(outcome, Error::::FundingAssetNotAccepted); @@ -2056,16 +2123,32 @@ mod end_auction_extrinsic { // We use multiplier > 1 so after settlement, only the refunds defined above are done. The rest will be done // through the linear release pallet - let bid_1 = - BidParams::new(BIDDER_1, 5000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT); - let bid_2 = - BidParams::new(BIDDER_2, 40_000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDC); - let bid_3 = - BidParams::new(BIDDER_1, 10_000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::DOT); - let bid_4 = - BidParams::new(BIDDER_3, 6000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT); + let bid_1 = BidParams::from(( + BIDDER_1, + 5000 * CT_UNIT, + ParticipationMode::Classic(5u8), + AcceptedFundingAsset::USDT, + )); + let bid_2 = BidParams::from(( + BIDDER_2, + 40_000 * CT_UNIT, + ParticipationMode::Classic(5u8), + AcceptedFundingAsset::USDC, + )); + let bid_3 = BidParams::from(( + BIDDER_1, + 10_000 * CT_UNIT, + ParticipationMode::Classic(5u8), + AcceptedFundingAsset::DOT, + )); + let bid_4 = BidParams::from(( + BIDDER_3, + 6000 * CT_UNIT, + ParticipationMode::Classic(5u8), + AcceptedFundingAsset::USDT, + )); let bid_5 = - BidParams::new(BIDDER_4, 2000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::DOT); + BidParams::from((BIDDER_4, 2000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::DOT)); // post bucketing, the bids look like this: // (BIDDER_1, 5k) - (BIDDER_2, 40k) - (BIDDER_1, 5k) - (BIDDER_1, 5k) - (BIDDER_3 - 5k) - (BIDDER_3 - 1k) - (BIDDER_4 - 2k) // | -------------------- 10USD ----------------------|---- 11 USD ---|---- 12 USD ----|----------- 13 USD -------------| diff --git a/pallets/funding/src/tests/4_contribution.rs b/pallets/funding/src/tests/4_contribution.rs index 8c17ba416..fb0f0275b 100644 --- a/pallets/funding/src/tests/4_contribution.rs +++ b/pallets/funding/src/tests/4_contribution.rs @@ -65,10 +65,8 @@ mod round_flow { #[test] fn contribution_round_ends_on_all_ct_sold_exact() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); - let bids = vec![ - BidParams::new_with_defaults(BIDDER_1, 40_000 * CT_UNIT), - BidParams::new_with_defaults(BIDDER_2, 10_000 * CT_UNIT), - ]; + let bids = + vec![BidParams::from((BIDDER_1, 40_000 * CT_UNIT)), BidParams::from((BIDDER_2, 10_000 * CT_UNIT))]; let project_id = inst.create_community_contributing_project( default_project_metadata(ISSUER_1), ISSUER_1, @@ -81,12 +79,12 @@ mod round_flow { let remaining_ct = inst.get_project_details(project_id).remaining_contribution_tokens; let ct_price = inst.get_project_details(project_id).weighted_average_price.expect("CT Price should exist"); - let contributions = vec![ContributionParams::new( + let contributions = vec![ContributionParams::from(( BOB, remaining_ct, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - )]; + ))]; let plmc_fundings = inst.calculate_contributed_plmc_spent(contributions.clone(), ct_price); let foreign_asset_fundings = inst.calculate_contributed_funding_asset_spent(contributions.clone(), ct_price); @@ -329,8 +327,8 @@ mod contribute_extrinsic { const BOB: AccountId = 42069; const CARL: AccountId = 420691; let mut evaluations = default_evaluations(); - let bob_evaluation: UserToUSDBalance = (BOB, 1337 * USD_UNIT).into(); - let carl_evaluation: UserToUSDBalance = (CARL, 1337 * USD_UNIT).into(); + let bob_evaluation: EvaluationParams = (BOB, 1337 * USD_UNIT).into(); + let carl_evaluation: EvaluationParams = (CARL, 1337 * USD_UNIT).into(); evaluations.push(bob_evaluation.clone()); evaluations.push(carl_evaluation.clone()); @@ -540,24 +538,24 @@ mod contribute_extrinsic { default_evaluations(), default_bids(), ); - let usdt_contribution = ContributionParams::new( + let usdt_contribution = ContributionParams::from(( BUYER_1, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); - let usdc_contribution = ContributionParams::new( + )); + let usdc_contribution = ContributionParams::from(( BUYER_2, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDC, - ); - let dot_contribution = ContributionParams::new( + )); + let dot_contribution = ContributionParams::from(( BUYER_3, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::DOT, - ); + )); let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); @@ -726,18 +724,18 @@ mod contribute_extrinsic { evaluations.push((BIDDER_4, 1337 * USD_UNIT).into()); let successful_bids = vec![ - BidParams::new( + BidParams::from(( BIDDER_1, 400_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - BidParams::new( + )), + BidParams::from(( BIDDER_2, 100_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), + )), ]; // This bids should fill the first bucket. @@ -834,12 +832,12 @@ mod contribute_extrinsic { ); let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); - let contribution = ContributionParams::new( + let contribution = ContributionParams::from(( BUYER_4, 500 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); let plmc_required = inst.calculate_contributed_plmc_spent(vec![contribution.clone()], wap); let frozen_amount = plmc_required[0].plmc_amount; @@ -916,12 +914,12 @@ mod contribute_extrinsic { ); let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); - let contribution = ContributionParams::new( + let contribution = ContributionParams::from(( BUYER_4, 500 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT, - ); + )); let plmc_required = inst.calculate_contributed_plmc_spent(vec![contribution.clone()], wap); let frozen_amount = plmc_required[0].plmc_amount; @@ -1008,20 +1006,20 @@ mod contribute_extrinsic { let mut evaluations = default_evaluations(); evaluations.push((participant, 100 * USD_UNIT).into()); let mut bids = default_bids(); - bids.push(BidParams::new( + bids.push(BidParams::from(( participant, 1000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - )); + ))); let community_contributions = default_community_contributions(); let mut remainder_contributions = default_remainder_contributions(); - remainder_contributions.push(ContributionParams::new( + remainder_contributions.push(ContributionParams::from(( participant, 10 * CT_UNIT, ParticipationMode::Classic(1), AcceptedFundingAsset::USDT, - )); + ))); let _project_id = inst.create_finished_project( project_metadata.clone(), @@ -1334,6 +1332,91 @@ mod contribute_extrinsic { assert_eq!(post_settlement_buyer_usdt, usdt_ed + USDT_PARTICIPATION + otm_usdt_fee); assert_eq!(issuer_funding_account, Zero::zero()); } + + #[test] + fn contribute_on_ethereum_project() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + + let mut project_metadata = default_project_metadata(ISSUER_1); + project_metadata.participants_account_type = ParticipantsAccountType::Ethereum; + + let project_id = inst.create_community_contributing_project( + project_metadata.clone(), + ISSUER_1, + None, + default_eth_evaluations(), + vec![], + ); + let jwt = get_mock_jwt_with_cid( + BUYER_1, + InvestorType::Professional, + generate_did_from_account(BUYER_1), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + let (eth_acc, eth_sig) = inst.eth_key_and_sig_from("//BUYER1", project_id, BUYER_1); + let contribution = + ContributionParams::from((BUYER_1, 500 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT)); + let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); + let mint_amount = inst.calculate_contributed_funding_asset_spent(vec![contribution], wap); + inst.mint_funding_asset_ed_if_required(mint_amount.to_account_asset_map()); + inst.mint_funding_asset_to(mint_amount.clone()); + + assert_ok!(inst.execute(|| { + PolimecFunding::contribute_with_receiving_account( + RuntimeOrigin::signed(BUYER_1), + jwt, + project_id, + 500 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + eth_acc, + eth_sig, + ) + })); + } + + #[test] + fn contribute_with_different_receiver_polkadot_account() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + + let project_metadata = default_project_metadata(ISSUER_1); + + let project_id = inst.create_community_contributing_project( + project_metadata.clone(), + ISSUER_1, + None, + default_evaluations(), + vec![], + ); + let jwt = get_mock_jwt_with_cid( + BUYER_1, + InvestorType::Professional, + generate_did_from_account(BUYER_1), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + let (dot_acc, dot_sig) = inst.dot_key_and_sig_from("//BUYER1", project_id, BUYER_1); + let bid = + ContributionParams::from((BUYER_1, 500 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT)); + let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); + let mint_amount = inst.calculate_contributed_funding_asset_spent(vec![bid], wap); + inst.mint_funding_asset_ed_if_required(mint_amount.to_account_asset_map()); + inst.mint_funding_asset_to(mint_amount.clone()); + + assert_ok!(inst.execute(|| { + PolimecFunding::contribute_with_receiving_account( + RuntimeOrigin::signed(BUYER_1), + jwt, + project_id, + 500 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + dot_acc, + dot_sig, + ) + })); + } } #[cfg(test)] @@ -1366,12 +1449,12 @@ mod contribute_extrinsic { let range = 0..::MaxContributionsPerUser::get(); let contributions: Vec> = range .map(|_| { - ContributionParams::new( + ContributionParams::from(( CONTRIBUTOR, token_amount, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ) + )) }) .collect(); @@ -1388,12 +1471,12 @@ mod contribute_extrinsic { assert!(inst.contribute_for_users(project_id, contributions).is_ok()); // Try to contribute again, but it should fail because the limit of contributions for a user-project was reached. - let over_limit_contribution = ContributionParams::new( + let over_limit_contribution = ContributionParams::from(( CONTRIBUTOR, token_amount, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); assert!(inst.contribute_for_users(project_id, vec![over_limit_contribution]).is_err()); // Check that the right amount of PLMC is bonded, and funding currency is transferred @@ -1449,10 +1532,7 @@ mod contribute_extrinsic { did: generate_did_from_account(ISSUER_1), investor_type: InvestorType::Institutional, whitelisted_policy: project_metadata.policy_ipfs_cid.unwrap(), - receiving_account: Junction::AccountId32 { - network: None, - id: ::AccountId32Conversion::convert(ISSUER_1) - }, + receiving_account: polkadot_junction!(ISSUER_1) })), Error::::ParticipationToOwnProject ); @@ -1465,20 +1545,25 @@ mod contribute_extrinsic { let mut evaluations = default_evaluations(); evaluations.push((BIDDER_2, 1337 * USD_UNIT).into()); let bids = vec![ - BidParams::new( + BidParams::from(( BIDDER_1, 400_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - BidParams::new(BIDDER_2, 50_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), + )), + BidParams::from(( + BIDDER_2, + 50_000 * CT_UNIT, + ParticipationMode::Classic(1u8), + AcceptedFundingAsset::USDT, + )), // Partially accepted bid. Only the 50k of the second bid will be accepted. - BidParams::new( + BidParams::from(( BIDDER_3, 100_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), + )), ]; let project_id = inst.create_community_contributing_project( @@ -1830,12 +1915,12 @@ mod contribute_extrinsic { generate_did_from_account(BUYER_1), project_metadata.clone().policy_ipfs_cid.unwrap(), ); - let contribution = ContributionParams::new( + let contribution = ContributionParams::from(( BUYER_1, 1_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); // 1 unit less native asset than needed @@ -1974,24 +2059,24 @@ mod contribute_extrinsic { }) .collect::>(); - let usdt_contribution = ContributionParams::new( + let usdt_contribution = ContributionParams::from(( BUYER_1, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); - let usdc_contribution = ContributionParams::new( + )); + let usdc_contribution = ContributionParams::from(( BUYER_2, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDC, - ); - let dot_contribution = ContributionParams::new( + )); + let dot_contribution = ContributionParams::from(( BUYER_3, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::DOT, - ); + )); let project_id_usdc = inst.create_community_contributing_project( project_metadata_usdc, @@ -2033,12 +2118,12 @@ mod contribute_extrinsic { let evaluator_contributor = 69; let evaluation_amount = 420 * USD_UNIT; - let evaluator_contribution = ContributionParams::new( + let evaluator_contribution = ContributionParams::from(( evaluator_contributor, 600 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ); + )); evaluations_1.push((evaluator_contributor, evaluation_amount).into()); let _project_id_1 = inst.create_community_contributing_project( @@ -2139,12 +2224,12 @@ mod contribute_extrinsic { ); let project_details = inst.get_project_details(project_id); let remaining_cts = project_details.remaining_contribution_tokens; - let glutton_contribution = ContributionParams::new( + let glutton_contribution = ContributionParams::from(( BUYER_1, remaining_cts, ParticipationMode::Classic(4u8), AcceptedFundingAsset::USDT, - ); + )); let wap = project_details.weighted_average_price.unwrap(); let plmc_mint = inst.calculate_contributed_plmc_spent(vec![glutton_contribution.clone()], wap); let funding_asset_mint = @@ -2155,12 +2240,12 @@ mod contribute_extrinsic { inst.mint_funding_asset_to(funding_asset_mint); inst.contribute_for_users(project_id, vec![glutton_contribution.clone()]).unwrap(); - let failing_contribution = ContributionParams::::new( + let failing_contribution = ContributionParams::::from(( BUYER_2, 1000 * CT_UNIT, ParticipationMode::Classic(1), AcceptedFundingAsset::USDT, - ); + )); let plmc_mint = inst.calculate_contributed_plmc_spent(vec![glutton_contribution.clone()], wap); let funding_asset_mint = inst.calculate_contributed_funding_asset_spent(vec![glutton_contribution.clone()], wap); diff --git a/pallets/funding/src/tests/6_settlement.rs b/pallets/funding/src/tests/6_settlement.rs index ec2711592..1ef52d6b5 100644 --- a/pallets/funding/src/tests/6_settlement.rs +++ b/pallets/funding/src/tests/6_settlement.rs @@ -40,6 +40,198 @@ mod round_flow { inst.assert_bids_migrations_created(project_id, bids, false); inst.assert_contributions_migrations_created(project_id, contributions, false); } + + #[test] + fn ethereum_project_can_be_settled() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + let mut project_metadata = default_project_metadata(ISSUER_1); + project_metadata.participants_account_type = ParticipantsAccountType::Ethereum; + + let evaluations = vec![ + EvaluationParams::from(( + EVALUATOR_1, + 500_000 * USD_UNIT, + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: [0u8; 20] }, + )), + EvaluationParams::from(( + EVALUATOR_2, + 250_000 * USD_UNIT, + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: [1u8; 20] }, + )), + EvaluationParams::from(( + EVALUATOR_3, + 300_000 * USD_UNIT, + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: [2u8; 20] }, + )), + ]; + let bids = vec![ + BidParams::from(( + BIDDER_1, + 120_000 * CT_UNIT, + ParticipationMode::Classic(3u8), + AcceptedFundingAsset::USDT, + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: [3u8; 20] }, + )), + BidParams::from(( + BIDDER_2, + 420_000 * CT_UNIT, + ParticipationMode::Classic(5u8), + AcceptedFundingAsset::USDT, + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: [4u8; 20] }, + )), + ]; + let community_contributions = vec![ + ContributionParams::from(( + BUYER_1, + 20_000 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: [5u8; 20] }, + )), + ContributionParams::from(( + BUYER_2, + 5_000 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: [6u8; 20] }, + )), + ]; + let remainder_contributions = vec![ + ContributionParams::from(( + EVALUATOR_2, + 10_000 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: [7u8; 20] }, + )), + ContributionParams::from(( + BIDDER_1, + 5_000 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: [8u8; 20] }, + )), + ContributionParams::from(( + BUYER_1, + 100 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: [9u8; 20] }, + )), + ]; + + let project_id = inst.create_settled_project( + project_metadata.clone(), + ISSUER_1, + None, + evaluations, + bids, + community_contributions, + remainder_contributions, + false, + ); + + let evaluations = inst.get_evaluations(project_id); + let bids = inst.get_bids(project_id); + let contributions = inst.get_contributions(project_id); + + inst.settle_project(project_id, true); + + assert_eq!( + inst.get_project_details(project_id).status, + ProjectStatus::SettlementFinished(FundingOutcome::Success) + ); + + inst.assert_evaluations_migrations_created(project_id, evaluations, true); + inst.assert_bids_migrations_created(project_id, bids, true); + inst.assert_contributions_migrations_created(project_id, contributions, true); + + let user_migrations = + inst.execute(|| UserMigrations::::iter_prefix((project_id,)).collect_vec()); + dbg!(user_migrations); + } + + #[test] + fn polkadot_project_with_different_receiving_accounts_can_be_settled() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + let mut project_metadata = default_project_metadata(ISSUER_1); + + let evaluations = vec![ + EvaluationParams::from((EVALUATOR_1, 500_000 * USD_UNIT, polkadot_junction!(EVALUATOR_1 + 420))), + EvaluationParams::from((EVALUATOR_2, 250_000 * USD_UNIT, polkadot_junction!([1u8; 32]))), + EvaluationParams::from((EVALUATOR_3, 300_000 * USD_UNIT, polkadot_junction!([2u8; 32]))), + ]; + let bids = vec![ + BidParams::from(( + BIDDER_1, + 120_000 * CT_UNIT, + ParticipationMode::Classic(3u8), + AcceptedFundingAsset::USDT, + polkadot_junction!([3u8; 32]), + )), + BidParams::from(( + BIDDER_2, + 420_000 * CT_UNIT, + ParticipationMode::Classic(5u8), + AcceptedFundingAsset::USDT, + polkadot_junction!([4u8; 32]), + )), + ]; + let community_contributions = vec![ + ContributionParams::from(( + BUYER_1, + 20_000 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + polkadot_junction!([5u8; 32]), + )), + ContributionParams::from(( + BUYER_2, + 5_000 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + polkadot_junction!([6u8; 32]), + )), + ]; + let remainder_contributions = vec![ + ContributionParams::from(( + EVALUATOR_2, + 10_000 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + polkadot_junction!([7u8; 32]), + )), + ContributionParams::from(( + BIDDER_1, + 5_000 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + polkadot_junction!([8u8; 32]), + )), + ContributionParams::from(( + BUYER_1, + 100 * CT_UNIT, + ParticipationMode::OTM, + AcceptedFundingAsset::USDT, + polkadot_junction!([9u8; 32]), + )), + ]; + + let project_id = inst.create_settled_project( + project_metadata.clone(), + ISSUER_1, + None, + evaluations, + bids, + community_contributions, + remainder_contributions, + true, + ); + assert_eq!( + inst.get_project_details(project_id).status, + ProjectStatus::SettlementFinished(FundingOutcome::Success) + ); + } } } @@ -154,9 +346,9 @@ mod settle_evaluation_extrinsic { ISSUER_1, None, vec![ - UserToUSDBalance::new(EVALUATOR_1, 500_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_2, 250_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_3, 320_000 * USD_UNIT), + EvaluationParams::from((EVALUATOR_1, 500_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_2, 250_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_3, 320_000 * USD_UNIT)), ], inst.generate_bids_from_total_ct_percent( project_metadata.clone(), @@ -239,7 +431,7 @@ mod settle_evaluation_extrinsic { let evals = vec![(EVALUATOR_1, EVAL_1_REWARD), (EVALUATOR_2, EVAL_2_REWARD), (EVALUATOR_3, EVAL_3_REWARD)]; - for (evaluator, expected_reward) in evals { + for (index, (evaluator, expected_reward)) in evals.into_iter().enumerate() { let evaluation_locked_plmc = inst.get_reserved_plmc_balance_for(evaluator, HoldReason::Evaluation.into()); let free_plmc = inst.get_free_plmc_balance_for(evaluator); @@ -253,7 +445,15 @@ mod settle_evaluation_extrinsic { assert_close_enough!(ct_rewarded, expected_reward, Perquintill::from_float(0.9999)); assert_eq!(inst.get_reserved_plmc_balance_for(evaluator, HoldReason::Evaluation.into()), 0); assert_eq!(inst.get_free_plmc_balance_for(evaluator), free_plmc + evaluation_locked_plmc); - inst.assert_migration(project_id, evaluator, expected_reward, 0, ParticipationType::Evaluation, true); + inst.assert_migration( + project_id, + evaluator, + expected_reward, + index as u32, + ParticipationType::Evaluation, + polkadot_junction!(evaluator), + true, + ); } } @@ -291,7 +491,7 @@ mod settle_evaluation_extrinsic { fn evaluation_round_failed() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let project_metadata = default_project_metadata(ISSUER_1); - let evaluation = UserToUSDBalance::new(EVALUATOR_1, 1_000 * USD_UNIT); + let evaluation = EvaluationParams::from((EVALUATOR_1, 1_000 * USD_UNIT)); let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); let evaluation_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); @@ -390,14 +590,14 @@ mod settle_bid_extrinsic { bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; let auction_allocation = project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; - let partial_amount_bid_params = BidParams::new( + let partial_amount_bid_params = BidParams::from(( BIDDER_1, auction_allocation, ParticipationMode::Classic(3u8), AcceptedFundingAsset::USDT, - ); + )); let lower_price_bid_params = - BidParams::new(BIDDER_2, 2000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::DOT); + BidParams::from((BIDDER_2, 2000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::DOT)); let bids = vec![partial_amount_bid_params.clone(), lower_price_bid_params.clone()]; let project_id = inst.create_finished_project( @@ -461,6 +661,7 @@ mod settle_bid_extrinsic { auction_allocation - 2000 * CT_UNIT, 0, ParticipationType::Bid, + polkadot_junction!(BIDDER_1), true, ); @@ -507,7 +708,15 @@ mod settle_bid_extrinsic { inst.assert_plmc_free_balance(BIDDER_2, expected_plmc_refund + ed); inst.assert_ct_balance(project_id, BIDDER_2, 2000 * CT_UNIT); - inst.assert_migration(project_id, BIDDER_2, 2000 * CT_UNIT, 1, ParticipationType::Bid, true); + inst.assert_migration( + project_id, + BIDDER_2, + 2000 * CT_UNIT, + 1, + ParticipationType::Bid, + polkadot_junction!(BIDDER_2), + true, + ); // Multiplier 5 should be unbonded no earlier than after 8.67 weeks (i.e. 436'867 blocks) let multiplier: MultiplierOf = @@ -540,12 +749,12 @@ mod settle_bid_extrinsic { bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; let auction_allocation = project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; - let no_refund_bid_params = BidParams::new( + let no_refund_bid_params = BidParams::from(( BIDDER_1, auction_allocation / 2, ParticipationMode::Classic(16u8), AcceptedFundingAsset::USDT, - ); + )); let project_id = inst.create_finished_project( project_metadata.clone(), @@ -583,7 +792,15 @@ mod settle_bid_extrinsic { inst.assert_plmc_free_balance(BIDDER_1, ed); inst.assert_ct_balance(project_id, BIDDER_1, auction_allocation / 2); - inst.assert_migration(project_id, BIDDER_1, auction_allocation / 2, 0, ParticipationType::Bid, true); + inst.assert_migration( + project_id, + BIDDER_1, + auction_allocation / 2, + 0, + ParticipationType::Bid, + polkadot_junction!(BIDDER_1), + true, + ); let hold_reason: RuntimeHoldReason = HoldReason::Participation.into(); let multiplier: MultiplierOf = no_refund_bid_params.mode.multiplier().try_into().ok().unwrap(); @@ -614,14 +831,14 @@ mod settle_bid_extrinsic { project_metadata.auction_round_allocation_percentage = Percent::from_percent(10); let auction_allocation = project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; - let partial_amount_bid_params = BidParams::new( + let partial_amount_bid_params = BidParams::from(( BIDDER_1, auction_allocation, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDC, - ); + )); let lower_price_bid_params = - BidParams::new(BIDDER_2, 2000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::DOT); + BidParams::from((BIDDER_2, 2000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::DOT)); let bids = vec![partial_amount_bid_params.clone(), lower_price_bid_params.clone()]; let project_id = inst.create_finished_project( @@ -664,7 +881,15 @@ mod settle_bid_extrinsic { inst.assert_plmc_free_balance(BIDDER_1, partial_amount_bid_stored.plmc_bond + ed); inst.assert_ct_balance(project_id, BIDDER_1, Zero::zero()); - inst.assert_migration(project_id, BIDDER_1, Zero::zero(), 0, ParticipationType::Bid, false); + inst.assert_migration( + project_id, + BIDDER_1, + Zero::zero(), + 0, + ParticipationType::Bid, + polkadot_junction!(BIDDER_1), + false, + ); inst.execute(|| { assert_noop!( @@ -700,7 +925,15 @@ mod settle_bid_extrinsic { inst.assert_plmc_free_balance(BIDDER_2, lower_price_bid_stored.plmc_bond + ed); inst.assert_ct_balance(project_id, BIDDER_2, Zero::zero()); - inst.assert_migration(project_id, BIDDER_2, Zero::zero(), 1, ParticipationType::Bid, false); + inst.assert_migration( + project_id, + BIDDER_2, + Zero::zero(), + 1, + ParticipationType::Bid, + polkadot_junction!(BIDDER_2), + false, + ); inst.execute(|| { assert_noop!( @@ -718,8 +951,12 @@ mod settle_bid_extrinsic { let mut project_metadata = default_project_metadata(ISSUER_1); project_metadata.participation_currencies = bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; - let no_refund_bid_params = - BidParams::new(BIDDER_1, 500 * CT_UNIT, ParticipationMode::Classic(16u8), AcceptedFundingAsset::USDT); + let no_refund_bid_params = BidParams::from(( + BIDDER_1, + 500 * CT_UNIT, + ParticipationMode::Classic(16u8), + AcceptedFundingAsset::USDT, + )); let project_id = inst.create_finished_project( project_metadata.clone(), @@ -778,18 +1015,18 @@ mod settle_bid_extrinsic { bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; let auction_allocation = project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; - let rejected_bid_params = BidParams::new( + let rejected_bid_params = BidParams::from(( BIDDER_1, auction_allocation, ParticipationMode::Classic(4u8), AcceptedFundingAsset::USDT, - ); - let accepted_bid_params = BidParams::new( + )); + let accepted_bid_params = BidParams::from(( BIDDER_2, auction_allocation, ParticipationMode::Classic(1u8), AcceptedFundingAsset::DOT, - ); + )); let bids = vec![rejected_bid_params.clone(), accepted_bid_params.clone()]; let project_id = inst.create_community_contributing_project( @@ -846,18 +1083,18 @@ mod settle_bid_extrinsic { bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; let auction_allocation = project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; - let rejected_bid_params = BidParams::new( + let rejected_bid_params = BidParams::from(( BIDDER_1, auction_allocation, ParticipationMode::Classic(4u8), AcceptedFundingAsset::USDT, - ); - let accepted_bid_params = BidParams::new( + )); + let accepted_bid_params = BidParams::from(( BIDDER_2, auction_allocation, ParticipationMode::Classic(1u8), AcceptedFundingAsset::DOT, - ); + )); let bids = vec![rejected_bid_params.clone(), accepted_bid_params.clone()]; let project_id = inst.create_finished_project( @@ -918,18 +1155,18 @@ mod settle_bid_extrinsic { project_metadata.auction_round_allocation_percentage = Percent::from_percent(10); let auction_allocation = project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; - let rejected_bid_params = BidParams::new( + let rejected_bid_params = BidParams::from(( BIDDER_1, auction_allocation, ParticipationMode::Classic(4u8), AcceptedFundingAsset::USDT, - ); - let accepted_bid_params = BidParams::new( + )); + let accepted_bid_params = BidParams::from(( BIDDER_2, auction_allocation, ParticipationMode::Classic(1u8), AcceptedFundingAsset::DOT, - ); + )); let bids = vec![rejected_bid_params.clone(), accepted_bid_params.clone()]; let project_id = inst.create_finished_project( @@ -1047,12 +1284,12 @@ mod settle_contribution_extrinsic { let usdt_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); let project_metadata = default_project_metadata(ISSUER_1); - let contribution = ContributionParams::::new( + let contribution = ContributionParams::::from(( BUYER_1, 1000 * CT_UNIT, ParticipationMode::Classic(2), AcceptedFundingAsset::USDT, - ); + )); let project_id = inst.create_finished_project( project_metadata.clone(), @@ -1100,6 +1337,7 @@ mod settle_contribution_extrinsic { stored_contribution.ct_amount, 0, ParticipationType::Contribution, + polkadot_junction!(BUYER_1), true, ); @@ -1134,18 +1372,18 @@ mod settle_contribution_extrinsic { default_community_contributor_modes(), ); - let contribution_mul_1 = ContributionParams::::new( + let contribution_mul_1 = ContributionParams::::from(( BUYER_6, 1000 * CT_UNIT, ParticipationMode::Classic(1), AcceptedFundingAsset::USDT, - ); - let contribution_mul_2 = ContributionParams::::new( + )); + let contribution_mul_2 = ContributionParams::::from(( BUYER_7, 1000 * CT_UNIT, ParticipationMode::Classic(2), AcceptedFundingAsset::USDT, - ); + )); community_contributions.push(contribution_mul_1); @@ -1228,6 +1466,7 @@ mod settle_contribution_extrinsic { stored_contribution.ct_amount, 5, ParticipationType::Contribution, + polkadot_junction!(BUYER_6), false, ); @@ -1274,6 +1513,7 @@ mod settle_contribution_extrinsic { stored_contribution.ct_amount, 6, ParticipationType::Contribution, + polkadot_junction!(BUYER_7), false, ); } diff --git a/pallets/funding/src/tests/misc.rs b/pallets/funding/src/tests/misc.rs index 6536016bf..a4e59e761 100644 --- a/pallets/funding/src/tests/misc.rs +++ b/pallets/funding/src/tests/misc.rs @@ -97,11 +97,11 @@ mod helper_functions { ); let evaluations = vec![ - UserToUSDBalance::::new(EVALUATOR_1, USD_AMOUNT_1), - UserToUSDBalance::::new(EVALUATOR_2, USD_AMOUNT_2), - UserToUSDBalance::::new(EVALUATOR_3, USD_AMOUNT_3), - UserToUSDBalance::::new(EVALUATOR_4, USD_AMOUNT_4), - UserToUSDBalance::::new(EVALUATOR_5, USD_AMOUNT_5), + EvaluationParams::::from((EVALUATOR_1, USD_AMOUNT_1)), + EvaluationParams::::from((EVALUATOR_2, USD_AMOUNT_2)), + EvaluationParams::::from((EVALUATOR_3, USD_AMOUNT_3)), + EvaluationParams::::from((EVALUATOR_4, USD_AMOUNT_4)), + EvaluationParams::::from((EVALUATOR_5, USD_AMOUNT_5)), ]; let expected_plmc_spent = vec![ @@ -140,11 +140,16 @@ mod helper_functions { const CT_AMOUNT_4: u128 = 6000 * CT_UNIT; const CT_AMOUNT_5: u128 = 2000 * CT_UNIT; - let bid_1 = BidParams::new(BIDDER_1, CT_AMOUNT_1, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT); - let bid_2 = BidParams::new(BIDDER_2, CT_AMOUNT_2, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT); - let bid_3 = BidParams::new(BIDDER_1, CT_AMOUNT_3, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT); - let bid_4 = BidParams::new(BIDDER_3, CT_AMOUNT_4, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT); - let bid_5 = BidParams::new(BIDDER_4, CT_AMOUNT_5, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT); + let bid_1 = + BidParams::from((BIDDER_1, CT_AMOUNT_1, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)); + let bid_2 = + BidParams::from((BIDDER_2, CT_AMOUNT_2, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)); + let bid_3 = + BidParams::from((BIDDER_1, CT_AMOUNT_3, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)); + let bid_4 = + BidParams::from((BIDDER_3, CT_AMOUNT_4, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)); + let bid_5 = + BidParams::from((BIDDER_4, CT_AMOUNT_5, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)); // post bucketing, the bids look like this: // (BIDDER_1, 5k) - (BIDDER_2, 40k) - (BIDDER_1, 5k) - (BIDDER_1, 5k) - (BIDDER_3 - 5k) - (BIDDER_3 - 1k) - (BIDDER_4 - 2k) @@ -285,36 +290,36 @@ mod helper_functions { ); let contributions = vec![ - ContributionParams::new( + ContributionParams::from(( CONTRIBUTOR_1, TOKEN_AMOUNT_1, ParticipationMode::Classic(MULTIPLIER_1), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( CONTRIBUTOR_2, TOKEN_AMOUNT_2, ParticipationMode::Classic(MULTIPLIER_2), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( CONTRIBUTOR_3, TOKEN_AMOUNT_3, ParticipationMode::Classic(MULTIPLIER_3), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( CONTRIBUTOR_4, TOKEN_AMOUNT_4, ParticipationMode::Classic(MULTIPLIER_4), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( CONTRIBUTOR_5, TOKEN_AMOUNT_5, ParticipationMode::Classic(MULTIPLIER_5), AcceptedFundingAsset::USDT, - ), + )), ]; let expected_plmc_spent = vec![ @@ -351,6 +356,67 @@ mod helper_functions { assert_close_enough!(expected, calculated, Perquintill::from_float(0.999)); } } + + #[test] + fn get_message_to_sign() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + let account = 69u64; + let project_id = 4u32; + let message_to_sign = inst.execute(|| PolimecFunding::get_message_to_sign(account, project_id)).unwrap(); + + const EXPECTED_MESSAGE: &str = + "polimec account: 57qWuK1HShHMA5o1TX7Q6Xhino5iNwf9qgiSBdkQZMNYddKs - project id: 4 - nonce: 0"; + assert_eq!(&message_to_sign, EXPECTED_MESSAGE); + } + + #[test] + fn verify_receiving_account_signature() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + let message_to_sign = inst.execute(|| PolimecFunding::get_message_to_sign(BUYER_1, 1)).unwrap(); + let message_to_sign = message_to_sign.into_bytes(); + + // Polkadot verification + let sr_pair = sr25519::Pair::from_seed_slice(&[69u8; 32]).unwrap(); + let signature = sr_pair.sign(&message_to_sign); + let mut signature_bytes = [0u8; 65]; + signature_bytes[..64].copy_from_slice(signature.as_bytes_ref()); + let junction = Junction::AccountId32 { network: Some(Polkadot), id: sr_pair.public().to_raw() }; + assert_ok!(inst.execute(|| PolimecFunding::verify_receiving_account_signature( + &BUYER_1, + 1, + &junction, + signature_bytes + ))); + + // Ethereum verification + let ecdsa_pair = ecdsa::Pair::from_seed_slice(&[69u8; 32]).unwrap(); + let message_length = message_to_sign.len(); + let message_prefix = format!("\x19Ethereum Signed Message:\n{}", message_length).into_bytes(); + let expected_message = [&message_prefix[..], &message_to_sign[..]].concat(); + let signature = ecdsa_pair.sign_prehashed(&keccak_256(&expected_message)); + let mut signature_bytes = [0u8; 65]; + signature_bytes[..65].copy_from_slice(signature.as_bytes_ref()); + + match signature_bytes[64] { + 0x00 => signature_bytes[64] = 27, + 0x01 => signature_bytes[64] = 28, + _v => unreachable!("Recovery bit should be always either 0 or 1"), + } + + let compressed_public_key = ecdsa_pair.public().to_raw(); + let public_uncompressed = k256::ecdsa::VerifyingKey::from_sec1_bytes(&compressed_public_key).unwrap(); + let public_uncompressed_point = public_uncompressed.to_encoded_point(false).to_bytes(); + let derived_ethereum_account: [u8; 20] = + keccak_256(&public_uncompressed_point[1..])[12..32].try_into().unwrap(); + let junction = + Junction::AccountKey20 { network: Some(Ethereum { chain_id: 1 }), key: derived_ethereum_account }; + assert_ok!(inst.execute(|| PolimecFunding::verify_receiving_account_signature( + &BUYER_1, + 1, + &junction, + signature_bytes + ))); + } } // logic of small functions that extrinsics use to process data or interact with storage diff --git a/pallets/funding/src/tests/mod.rs b/pallets/funding/src/tests/mod.rs index ee13c0ff3..e34bd83a9 100644 --- a/pallets/funding/src/tests/mod.rs +++ b/pallets/funding/src/tests/mod.rs @@ -179,132 +179,155 @@ pub mod defaults { ] } - pub fn default_evaluations() -> Vec> { + pub fn default_evaluations() -> Vec> { vec![ - UserToUSDBalance::new(EVALUATOR_1, 500_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_2, 250_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_3, 320_000 * USD_UNIT), + EvaluationParams::from((EVALUATOR_1, 500_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_2, 250_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_3, 320_000 * USD_UNIT)), ] } - pub fn knowledge_hub_evaluations() -> Vec> { + pub fn default_eth_evaluations() -> Vec> { vec![ - UserToUSDBalance::new(EVALUATOR_1, 75_000 * USDT_UNIT), - UserToUSDBalance::new(EVALUATOR_2, 65_000 * USDT_UNIT), - UserToUSDBalance::new(EVALUATOR_3, 60_000 * USDT_UNIT), + EvaluationParams::new( + EVALUATOR_1, + 500_000 * USD_UNIT, + Junction::AccountKey20 { network: Some(NetworkId::Ethereum { chain_id: 1 }), key: [0u8; 20] }, + ), + EvaluationParams::new( + EVALUATOR_2, + 250_000 * USD_UNIT, + Junction::AccountKey20 { network: Some(NetworkId::Ethereum { chain_id: 1 }), key: [1u8; 20] }, + ), + EvaluationParams::new( + EVALUATOR_3, + 320_000 * USD_UNIT, + Junction::AccountKey20 { network: Some(NetworkId::Ethereum { chain_id: 1 }), key: [2u8; 20] }, + ), + ] + } + + pub fn knowledge_hub_evaluations() -> Vec> { + vec![ + EvaluationParams::from((EVALUATOR_1, 75_000 * USDT_UNIT)), + EvaluationParams::from((EVALUATOR_2, 65_000 * USDT_UNIT)), + EvaluationParams::from((EVALUATOR_3, 60_000 * USDT_UNIT)), ] } - pub fn default_failing_evaluations() -> Vec> { - vec![UserToUSDBalance::new(EVALUATOR_1, 3_000 * USD_UNIT), UserToUSDBalance::new(EVALUATOR_2, 1_000 * USD_UNIT)] + pub fn default_failing_evaluations() -> Vec> { + vec![ + EvaluationParams::from((EVALUATOR_1, 3_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_2, 1_000 * USD_UNIT)), + ] } pub fn default_bids() -> Vec> { vec![ - BidParams::new(BIDDER_1, 400_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), - BidParams::new(BIDDER_2, 50_000 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT), + BidParams::from((BIDDER_1, 400_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)), + BidParams::from((BIDDER_2, 50_000 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT)), ] } pub fn knowledge_hub_bids() -> Vec> { // This should reflect the bidding currency, which currently is USDT vec![ - BidParams::new(BIDDER_1, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), - BidParams::new(BIDDER_2, 20_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), - BidParams::new(BIDDER_3, 20_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), - BidParams::new(BIDDER_4, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), - BidParams::new(BIDDER_5, 5_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), - BidParams::new(BIDDER_6, 5_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), + BidParams::from((BIDDER_1, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)), + BidParams::from((BIDDER_2, 20_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)), + BidParams::from((BIDDER_3, 20_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)), + BidParams::from((BIDDER_4, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)), + BidParams::from((BIDDER_5, 5_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)), + BidParams::from((BIDDER_6, 5_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)), ] } pub fn default_community_contributions() -> Vec> { vec![ - ContributionParams::new( + ContributionParams::from(( BUYER_1, 50_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( BUYER_2, 130_000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new(BUYER_3, 30_000 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT), - ContributionParams::new( + )), + ContributionParams::from((BUYER_3, 30_000 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT)), + ContributionParams::from(( BUYER_4, 210_000 * CT_UNIT, ParticipationMode::Classic(3u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new(BUYER_5, 10_000 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT), + )), + ContributionParams::from((BUYER_5, 10_000 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT)), ] } pub fn default_remainder_contributions() -> Vec> { vec![ - ContributionParams::new( + ContributionParams::from(( EVALUATOR_2, 20_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( BUYER_2, 5_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new(BIDDER_1, 30_000 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT), + )), + ContributionParams::from((BIDDER_1, 30_000 * CT_UNIT, ParticipationMode::OTM, AcceptedFundingAsset::USDT)), ] } pub fn knowledge_hub_buys() -> Vec> { vec![ - ContributionParams::new( + ContributionParams::from(( BUYER_1, 4_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( BUYER_2, 2_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( BUYER_3, 2_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( BUYER_4, 5_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( BUYER_5, 30_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( BUYER_6, 5_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new( + )), + ContributionParams::from(( BUYER_7, 2_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), + )), ] } @@ -528,3 +551,33 @@ pub fn create_finished_project_with_usd_raised( (inst, project_id) } + +macro_rules! polkadot_junction { + // Case 1: Explicit `[u8; 32]` literal with 32 values + ([ $($byte:literal),* ]) => {{ + let id: [u8; 32] = [$($byte),*]; + Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id, + } + }}; + + // Case 2: Repeated syntax `[value; 32]` + ([ $byte:literal ; 32 ]) => {{ + let id: [u8; 32] = [$byte; 32]; + Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id, + } + }}; + + // Case 3: Variable or expression + ($account:expr) => {{ + let id: [u8; 32] = ::AccountId32Conversion::convert($account); + Junction::AccountId32 { + network: Some(NetworkId::Polkadot), + id, + } + }}; +} +use polkadot_junction; diff --git a/pallets/funding/src/tests/runtime_api.rs b/pallets/funding/src/tests/runtime_api.rs index a65d15972..2aed7363e 100644 --- a/pallets/funding/src/tests/runtime_api.rs +++ b/pallets/funding/src/tests/runtime_api.rs @@ -6,11 +6,11 @@ use sp_runtime::bounded_vec; fn top_evaluations() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let evaluations = vec![ - UserToUSDBalance::new(EVALUATOR_1, 500_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_2, 250_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_3, 320_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_4, 1_000_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_1, 1_000 * USD_UNIT), + EvaluationParams::from((EVALUATOR_1, 500_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_2, 250_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_3, 320_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_4, 1_000_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_1, 1_000 * USD_UNIT)), ]; let project_id = inst.create_auctioning_project(default_project_metadata(ISSUER_1), ISSUER_1, None, evaluations); @@ -646,24 +646,34 @@ fn get_message_to_sign_by_receiving_account() { fn get_next_vesting_schedule_merge_candidates() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let evaluations = vec![ - UserToUSDBalance::new(EVALUATOR_1, 500_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_2, 250_000 * USD_UNIT), - UserToUSDBalance::new(BIDDER_1, 320_000 * USD_UNIT), + EvaluationParams::from((EVALUATOR_1, 500_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_2, 250_000 * USD_UNIT)), + EvaluationParams::from((BIDDER_1, 320_000 * USD_UNIT)), ]; let bids = vec![ - BidParams::new(BIDDER_1, 50_000 * CT_UNIT, ParticipationMode::Classic(10u8), AcceptedFundingAsset::USDT), - BidParams::new(BIDDER_1, 400_000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT), - BidParams::new(BIDDER_2, 50_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), + BidParams::from((BIDDER_1, 50_000 * CT_UNIT, ParticipationMode::Classic(10u8), AcceptedFundingAsset::USDT)), + BidParams::from((BIDDER_1, 400_000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT)), + BidParams::from((BIDDER_2, 50_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)), ]; let remaining_contributions = vec![ - ContributionParams::new(BIDDER_1, 1_000 * CT_UNIT, ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT), - ContributionParams::new( + ContributionParams::from(( + BIDDER_1, + 1_000 * CT_UNIT, + ParticipationMode::Classic(5u8), + AcceptedFundingAsset::USDT, + )), + ContributionParams::from(( BIDDER_1, 15_000 * CT_UNIT, ParticipationMode::Classic(10u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new(BIDDER_1, 100 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), + )), + ContributionParams::from(( + BIDDER_1, + 100 * CT_UNIT, + ParticipationMode::Classic(1u8), + AcceptedFundingAsset::USDT, + )), ]; let project_id = inst.create_finished_project( @@ -937,7 +947,7 @@ fn get_funding_asset_min_max_amounts() { }) .unwrap(); let contribution = - ContributionParams::new(BUYER_1, required_ct, ParticipationMode::OTM, AcceptedFundingAsset::USDC); + ContributionParams::from((BUYER_1, required_ct, ParticipationMode::OTM, AcceptedFundingAsset::USDC)); let usdc_to_mint = inst.calculate_contributed_funding_asset_spent(vec![contribution.clone()], min_price); inst.mint_funding_asset_ed_if_required(usdc_to_mint.to_account_asset_map()); inst.mint_funding_asset_to(usdc_to_mint); @@ -970,45 +980,65 @@ fn all_project_participations_by_did() { let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); let evaluations = vec![ - UserToUSDBalance::new(EVALUATOR_1, 500_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_2, 250_000 * USD_UNIT), - UserToUSDBalance::new(EVALUATOR_3, 320_000 * USD_UNIT), + EvaluationParams::from((EVALUATOR_1, 500_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_2, 250_000 * USD_UNIT)), + EvaluationParams::from((EVALUATOR_3, 320_000 * USD_UNIT)), ]; let bids = vec![ - BidParams::new(BIDDER_1, 400_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), - BidParams::new(BIDDER_2, 50_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), + BidParams::from((BIDDER_1, 400_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)), + BidParams::from((BIDDER_2, 50_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT)), ]; let community_contributions = vec![ - ContributionParams::new(BUYER_1, 50_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), - ContributionParams::new( + ContributionParams::from(( + BUYER_1, + 50_000 * CT_UNIT, + ParticipationMode::Classic(1u8), + AcceptedFundingAsset::USDT, + )), + ContributionParams::from(( BUYER_2, 130_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new(BUYER_3, 30_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), - ContributionParams::new( + )), + ContributionParams::from(( + BUYER_3, + 30_000 * CT_UNIT, + ParticipationMode::Classic(1u8), + AcceptedFundingAsset::USDT, + )), + ContributionParams::from(( BUYER_4, 210_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new(BUYER_5, 10_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), + )), + ContributionParams::from(( + BUYER_5, + 10_000 * CT_UNIT, + ParticipationMode::Classic(1u8), + AcceptedFundingAsset::USDT, + )), ]; let remainder_contributions = vec![ - ContributionParams::new( + ContributionParams::from(( EVALUATOR_2, 20_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), - ContributionParams::new(BUYER_2, 5_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT), - ContributionParams::new( + )), + ContributionParams::from(( + BUYER_2, + 5_000 * CT_UNIT, + ParticipationMode::Classic(1u8), + AcceptedFundingAsset::USDT, + )), + ContributionParams::from(( BIDDER_1, 30_000 * CT_UNIT, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, - ), + )), ]; let evaluations_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone()); diff --git a/pallets/funding/src/types.rs b/pallets/funding/src/types.rs index 55976cde2..11999e890 100644 --- a/pallets/funding/src/types.rs +++ b/pallets/funding/src/types.rs @@ -837,7 +837,7 @@ pub mod inner { match self { // This project expects users to submit a 32 byte account, and sign it with SR25519 crypto ParticipantsAccountType::Polkadot => - matches!(junction, Junction::AccountId32 { network, .. } if network.is_none()), + matches!(junction, Junction::AccountId32 { network, .. } if network == &Some(NetworkId::Polkadot)), // This project expects users to submit a 20 byte account, and sign it with ECDSA secp256k1 crypto ParticipantsAccountType::Ethereum => matches!(junction, Junction::AccountKey20 { network, .. } if network == &Some(NetworkId::Ethereum {chain_id: 1})), diff --git a/pallets/polimec-receiver/src/lib.rs b/pallets/polimec-receiver/src/lib.rs index d9f5cc9dd..bb86f16b5 100644 --- a/pallets/polimec-receiver/src/lib.rs +++ b/pallets/polimec-receiver/src/lib.rs @@ -34,7 +34,7 @@ pub mod pallet { use polkadot_parachain_primitives::primitives::{Id as ParaId, Sibling}; use sp_runtime::traits::{AccountIdConversion, Convert}; use sp_std::prelude::*; - use xcm::v4::{Junction::AccountId32, Location}; + use xcm::v4::{Junction::AccountId32}; type MomentOf = <::Vesting as VestingSchedule<::AccountId>>::Moment; @@ -64,7 +64,7 @@ pub mod pallet { pub type ExecutedMigrations = StorageNMap< _, ( - NMapKey, + NMapKey, NMapKey, NMapKey, ), @@ -113,12 +113,12 @@ pub mod pallet { .. } in migrations.inner().iter() { - let user_32 = match user.unpack() { - (0, [AccountId32 { id, .. }]) => Ok(*id), - _ => Err(Error::::NoneValue), - }?; + let user_32 = match user { + AccountId32 { id, .. } => *id, + _ => return Err(Error::::NoneValue.into()), + }; - if ExecutedMigrations::::get((&user, &participation_type, &id)) { + if ExecutedMigrations::::get((&user_32, &participation_type, &id)) { Self::deposit_event(Event::DuplicatedMigrationSkipped { migration: migration.clone() }); continue; } @@ -135,7 +135,7 @@ pub mod pallet { T::MigrationInfoToPerBlockBalance::convert(migration.info.clone()), T::GenesisMoment::get(), )?; - ExecutedMigrations::::insert((&user, &participation_type, &id), true); + ExecutedMigrations::::insert((&user_32, &participation_type, &id), true); Self::deposit_event(Event::MigrationExecuted { migration: migration.clone() }); } diff --git a/polimec-common/common/src/lib.rs b/polimec-common/common/src/lib.rs index 83e74d40b..a86093a05 100644 --- a/polimec-common/common/src/lib.rs +++ b/polimec-common/common/src/lib.rs @@ -107,10 +107,11 @@ pub trait ReleaseSchedule { pub mod migration_types { #[allow(clippy::wildcard_imports)] use super::*; + use xcm::v4::Junction; #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct MigrationOrigin { - pub user: Location, + pub user: Junction, pub id: u32, pub participation_type: ParticipationType, } diff --git a/runtimes/polimec/Cargo.toml b/runtimes/polimec/Cargo.toml index 8319ac5e4..d5318a6bd 100644 --- a/runtimes/polimec/Cargo.toml +++ b/runtimes/polimec/Cargo.toml @@ -110,9 +110,6 @@ parachains-common.workspace = true # ORML orml-oracle.workspace = true -# Migration utilities -# array-bytes = { workspace = true, default-features = false } - [features] default = [ "std" ] fast-mode = [ "shared-configuration/fast-mode" ]