Skip to content

Commit

Permalink
eth compat. tests
Browse files Browse the repository at this point in the history
  • Loading branch information
JuaniRios committed Oct 24, 2024
1 parent 85c8505 commit 8a90f38
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 10 deletions.
40 changes: 40 additions & 0 deletions integration-tests/src/tests/ethereum_support.rs
Original file line number Diff line number Diff line change
@@ -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,
));
});
}
16 changes: 6 additions & 10 deletions pallets/funding/src/functions/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,16 +448,12 @@ impl<T: Config> Pallet<T> {
.ok_or(Error::<T>::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::<T>::BadReceiverAccountSignature)?;
let public = SrPublic::from_slice(id).map_err(|_| Error::<T>::BadReceiverAccountSignature)?;
ensure!(
signature.verify(message_bytes.as_slice(), &public),
Error::<T>::BadReceiverAccountSignature
);
},
Junction::AccountId32 { network, id } if *network == Some(NetworkId::Polkadot) => {
let signature = SrSignature::from_slice(&signature_bytes[..64])
.map_err(|_| Error::<T>::BadReceiverAccountSignature)?;
let public = SrPublic::from_slice(id).map_err(|_| Error::<T>::BadReceiverAccountSignature)?;
ensure!(signature.verify(message_bytes.as_slice(), &public), Error::<T>::BadReceiverAccountSignature);
},

Junction::AccountKey20 { network, key } if *network == Some(NetworkId::Ethereum { chain_id: 1 }) => {
let message_length = message_bytes.len().to_string().into_bytes();
Expand Down
46 changes: 46 additions & 0 deletions pallets/funding/src/instantiator/calculations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -795,4 +796,49 @@ impl<
T::CommunityRoundDuration::get() +
One::one()
}

pub fn eth_key_and_sig_from(
&mut self,
s: &str,
project_id: ProjectId,
polimec_account: AccountIdOf<T>,
) -> (Junction, [u8; 65]) {
let message_to_sign = self.execute(|| Pallet::<T>::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(s, None).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 };

(junction, signature_bytes)
}

// pub fn polkadot_key_and_sig_from(&self, s: &str, project_id: ProjectId, polimec_account: AccountIdOf<T>) -> (Junction, [u8; 65]) {
// let message_to_sign = self.execute(|| Pallet::<T>::get_message_to_sign(polimec_account, project_id)).unwrap();
// let message_to_sign = message_to_sign.into_bytes();
//
// let sr_pair = sr25519::Pair::from_seed(&[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: None, id: sr_pair.public().to_raw() };
// (junction, signature_bytes)
// }
}
31 changes: 31 additions & 0 deletions pallets/funding/src/tests/2_evaluation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,37 @@ mod evaluate_extrinsic {
pre_slash_treasury_balance + <TestRuntime as Config>::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 ethereum_account = [1u8; 20];

inst.execute(|| {
PolimecFunding::evaluate_with_receiving_account(
RuntimeOrigin::signed(EVALUATOR_1),
jwt,
project_id,
500 * USD_UNIT,
Junction::AccountKey20 { network: Ethereum { chain_id: 1 }, key: ethereum_account },
)
});
}

#[test]
fn evaluate_with_different_receiver_polkadot_account() {}
}

#[cfg(test)]
Expand Down
61 changes: 61 additions & 0 deletions pallets/funding/src/tests/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,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: None, 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
Expand Down

0 comments on commit 8a90f38

Please sign in to comment.