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..28b43edf2 100644
--- a/integration-tests/src/tests/ethereum_support.rs
+++ b/integration-tests/src/tests/ethereum_support.rs
@@ -1 +1,40 @@
+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 = 1;
+
+ // Values generated with `https://github.com/lrazovic/ethsigner`
+ let polimec_account_ss58 = polimec_runtime::SS58Converter::convert(polimec_account.clone());
+ let ethereum_account: [u8; 20] = hex!("796afe7b8933ee8cf337f17887e5c19b657f9ab8");
+ let signature: [u8; 65] = hex!("952e312ac892fefc7c69051521e78a3bc2727fbb495585bdb5fb77e662b8a3de2b1254058d824e85034710e338c2590e2f92d74ce3c60292ed25c7537d94ed621b");
+
+ PolimecNet::execute_with(|| {
+ assert_ok!(PolimecFunding::verify_receiving_account_signature(
+ &polimec_account,
+ project_id,
+ &Junction::AccountKey20 { network: None, key: ethereum_account },
+ signature,
+ ));
+ });
+
+ let polkadot_signature: [u8; 64] = hex!("32b486f3944c6345295777c84113c5339b786a6c1a4505ab876349e07a7938646b01aff5c7ceda542af794cde03c14eb255d905da8019aa7264fa1a766ab0188");
+ 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: None, 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..4f2e40c24 100644
--- a/integration-tests/src/tests/evaluator_slash_sideffects.rs
+++ b/integration-tests/src/tests/evaluator_slash_sideffects.rs
@@ -9,6 +9,7 @@ use polimec_common::USD_UNIT;
use polimec_runtime::PLMC;
use sp_arithmetic::Perquintill;
use sp_runtime::{FixedU128, MultiAddress::Id};
+use xcm::v4::Junction;
generate_accounts!(STASH, ALICE, BOB, CHARLIE, DAVE, ISSUER);
@@ -77,7 +78,11 @@ 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,
+ Junction::AccountId32 { network: Some(NetworkId::Polkadot), id: [0u8; 32] },
+ );
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 +97,11 @@ 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,
+ Junction::AccountId32 { network: Some(NetworkId::Polkadot), id: [0u8; 32] },
+ );
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 29b139cac..88cce7dba 100644
--- a/pallets/funding/src/functions/misc.rs
+++ b/pallets/funding/src/functions/misc.rs
@@ -486,16 +486,17 @@ impl Pallet {
signature_bytes: [u8; 65],
) -> DispatchResult {
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 { id: substrate_account, .. } => {
+ ensure!(
+ Self::verify_substrate_account(
+ signature_bytes,
+ *substrate_account,
+ polimec_account.clone(),
+ project_id
+ ),
+ Error::::BadReceiverAccountSignature
+ );
+ },
Junction::AccountKey20 { key: expected_ethereum_account, .. } => {
ensure!(
diff --git a/pallets/funding/src/instantiator/calculations.rs b/pallets/funding/src/instantiator/calculations.rs
index ebbaf9398..5963c8f90 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,55 @@ 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 polimec_account_ss58_string = T::SS58Conversion::convert(polimec_account.clone());
+ let nonce = self.execute(|| frame_system::Pallet::::account_nonce(polimec_account));
+ let message_to_sign =
+ crate::functions::misc::typed_data_v4::get_eip_712_message(&polimec_account_ss58_string, project_id, nonce);
+ let ecdsa_pair = ecdsa::Pair::from_string(seed_string, None).unwrap();
+ let signature = ecdsa_pair.sign_prehashed(&message_to_sign);
+ 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: None, 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_substrate_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..3c10d69dc 100644
--- a/pallets/funding/src/instantiator/traits.rs
+++ b/pallets/funding/src/instantiator/traits.rs
@@ -14,16 +14,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