add support for partial claims of governance shares
Signed-off-by: Uncle Stinky <uncle.stinky@ghostchain.io>
This commit is contained in:
parent
fde1f68dc0
commit
d3b926cd47
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ghost-governance"
|
||||
version = "0.3.7"
|
||||
version = "0.3.8"
|
||||
description = "Full-chain and cross-chain governance pallet with early adopter share claims"
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
@ -13,6 +13,7 @@ codec = { workspace = true, features = ["derive"] }
|
||||
scale-info = { workspace = true, features = ["derive"] }
|
||||
serde = { workspace = true }
|
||||
serde_derive = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
rustc-hex = { workspace = true }
|
||||
libsecp256k1 = { workspace = true, default-features = false }
|
||||
|
||||
@ -42,6 +43,7 @@ std = [
|
||||
"serde/std",
|
||||
"codec/std",
|
||||
"scale-info/std",
|
||||
"num-traits/std",
|
||||
"libsecp256k1/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
|
||||
@ -99,7 +99,8 @@ mod benchmarks {
|
||||
let message_string_bytes = Pallet::<T>::ethereum_signable_message(
|
||||
¤t_account,
|
||||
&network_id,
|
||||
&preimage_hash
|
||||
&preimage_hash,
|
||||
0u8,
|
||||
);
|
||||
|
||||
let message_hash = SubstrateKeccakHasher::hash(&message_string_bytes);
|
||||
@ -124,6 +125,7 @@ mod benchmarks {
|
||||
claim_package,
|
||||
dummy_evm_address,
|
||||
evm_signature,
|
||||
dummy_shares,
|
||||
);
|
||||
|
||||
assert_eq!(dummy_shares, GlobalShares::<T>::get().claimed_shares);
|
||||
|
||||
@ -9,7 +9,11 @@ use frame_system::pallet_prelude::*;
|
||||
use sp_core::U256;
|
||||
use sp_std::vec::Vec;
|
||||
use sp_io::crypto::secp256k1_ecdsa_recover;
|
||||
use sp_runtime::traits::{AtLeast32BitUnsigned, CheckedAdd, UniqueSaturatedInto};
|
||||
use sp_runtime::traits::{
|
||||
AtLeast32BitUnsigned, CheckedAdd, Saturating, UniqueSaturatedInto,
|
||||
};
|
||||
|
||||
use num_traits::PrimInt;
|
||||
|
||||
use ghost_helpers::{
|
||||
SubstrateKeccakHasher, merkle_tree::verify_tree_proof,
|
||||
@ -32,9 +36,10 @@ mod benchmarking;
|
||||
mod mock;
|
||||
mod tests;
|
||||
|
||||
const MAX_POSSIBLE_PROOF_DEPTH: u32 = 256;
|
||||
const MAX_POSSIBLE_PROOF_DEPTH: u32 = 18;
|
||||
|
||||
type TokenId = u128;
|
||||
type ClaimNonce = u8;
|
||||
type EvmHash = sp_core::H256;
|
||||
type EvmAddress = sp_core::H160;
|
||||
type EvmSignature = [u8; 65];
|
||||
@ -134,7 +139,8 @@ where
|
||||
}
|
||||
|
||||
pub fn lock_balance(&mut self, extra_balance: Balance) {
|
||||
self.locked_balance.saturating_add(extra_balance);
|
||||
self.locked_balance = self.locked_balance
|
||||
.saturating_add(extra_balance);
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,6 +220,9 @@ pub mod pallet {
|
||||
#[pallet::constant]
|
||||
type MaxProofDepth: Get<u32>;
|
||||
|
||||
#[pallet::constant]
|
||||
type MaxPartialClaims: Get<ClaimNonce>;
|
||||
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
@ -229,9 +238,10 @@ pub mod pallet {
|
||||
|
||||
#[pallet::error]
|
||||
pub enum Error<T> {
|
||||
PreimageAlreadyClaimed,
|
||||
PartialClaimsExhausted,
|
||||
BoundedToOtherNetwork,
|
||||
AuthorityNotGovernor,
|
||||
ExceedsAllowedShares,
|
||||
NetworkHasNoGenesis,
|
||||
InvalidMerkleProof,
|
||||
SharesOverflowed,
|
||||
@ -269,7 +279,16 @@ pub mod pallet {
|
||||
pub type ClaimedHashes<T: Config> = StorageMap<
|
||||
_,
|
||||
Blake2_256, EvmHash,
|
||||
bool,
|
||||
ClaimNonce,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pallet::getter(fn claimed_shares)]
|
||||
pub type ClaimedShares<T: Config> = StorageMap<
|
||||
_,
|
||||
Twox64Concat, EvmHash,
|
||||
BalanceOf<T>,
|
||||
ValueQuery,
|
||||
>;
|
||||
|
||||
@ -317,6 +336,7 @@ pub mod pallet {
|
||||
claim_package: ClaimPackage<BalanceOf<T>>,
|
||||
evm_address: EvmAddress,
|
||||
evm_signature: EvmSignature,
|
||||
requested_shares: BalanceOf<T>,
|
||||
) -> DispatchResult {
|
||||
let who = ensure_signed(origin)?;
|
||||
|
||||
@ -338,12 +358,21 @@ pub mod pallet {
|
||||
let preimage = claim_package.get_preimage(&evm_address, network_id);
|
||||
let preimage_hash = SubstrateKeccakHasher::hash(&preimage);
|
||||
|
||||
ensure!(
|
||||
!ClaimedHashes::<T>::contains_key(&preimage_hash),
|
||||
Error::<T>::PreimageAlreadyClaimed
|
||||
);
|
||||
let max_claim_nonces = T::MaxPartialClaims::get();
|
||||
let current_nonce = ClaimedHashes::<T>::get(&preimage_hash);
|
||||
|
||||
Self::verify_signature(&who, &network_id, &preimage_hash, &evm_address, &evm_signature)?;
|
||||
ensure!(current_nonce < max_claim_nonces, Error::<T>::PartialClaimsExhausted);
|
||||
|
||||
let already_claimed = ClaimedShares::<T>::get(&preimage_hash);
|
||||
let claimed_shares = if current_nonce == max_claim_nonces.saturating_sub(1) {
|
||||
claim_package.shares.saturating_sub(already_claimed)
|
||||
} else {
|
||||
let cumulative_shares = already_claimed.saturating_add(requested_shares);
|
||||
ensure!(cumulative_shares <= claim_package.shares, Error::<T>::ExceedsAllowedShares);
|
||||
requested_shares
|
||||
};
|
||||
|
||||
Self::verify_signature(&who, &network_id, &preimage_hash, &evm_address, &evm_signature, current_nonce)?;
|
||||
Self::verify_merkle_proof(&network_id, &preimage, &claim_package)?;
|
||||
|
||||
NetworkShares::<T>::try_mutate(&network_id, |state| -> DispatchResult {
|
||||
@ -351,25 +380,29 @@ pub mod pallet {
|
||||
let proof_size_match = package_proof_size == state.proofs_size;
|
||||
ensure!(proof_size_match, Error::<T>::SharesOverflowed);
|
||||
|
||||
let increased = state.try_increase_claimed(claim_package.shares);
|
||||
let increased = state.try_increase_claimed(claimed_shares);
|
||||
ensure!(increased.is_some(), Error::<T>::SharesOverflowed);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
GlobalShares::<T>::try_mutate(|state| -> DispatchResult {
|
||||
let increased = state.try_increase_claimed(claim_package.shares);
|
||||
let increased = state.try_increase_claimed(claimed_shares);
|
||||
ensure!(increased.is_some(), Error::<T>::SharesOverflowed);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
member_share.increase_activated_shares(claim_package.shares);
|
||||
member_share.increase_activated_shares(claimed_shares);
|
||||
member_share.initiate_on_network(network_id);
|
||||
|
||||
MemberShares::<T>::insert(&who, member_share);
|
||||
ClaimedHashes::<T>::insert(&preimage_hash, true);
|
||||
ClaimedHashes::<T>::insert(&preimage_hash, current_nonce.saturating_add(1));
|
||||
ClaimedShares::<T>::insert(
|
||||
&preimage_hash,
|
||||
already_claimed.saturating_add(claimed_shares),
|
||||
);
|
||||
|
||||
Self::deposit_event(Event::<T>::SharesClaimed {
|
||||
shares: claim_package.shares,
|
||||
shares: claimed_shares,
|
||||
network_id,
|
||||
who,
|
||||
});
|
||||
@ -390,45 +423,73 @@ impl<T: Config> Pallet<T> {
|
||||
r
|
||||
}
|
||||
|
||||
fn to_ascii_base10<N: PrimInt + UniqueSaturatedInto<u128>>(num: N) -> Vec<u8> {
|
||||
let zero = N::zero();
|
||||
if num == zero { return vec![b'0']; }
|
||||
|
||||
let ten = N::from(10).unwrap_or_else(|| N::zero());
|
||||
let num_u128 = num.unique_saturated_into();
|
||||
let capacity = (num_u128.ilog10() + 1) as usize;
|
||||
|
||||
let mut result = Vec::with_capacity(capacity);
|
||||
let mut n = num;
|
||||
|
||||
while n > zero {
|
||||
result.push(b'0' + (n % ten).to_u8().unwrap_or(0));
|
||||
n = n / ten;
|
||||
}
|
||||
result.reverse();
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn ethereum_signable_message(
|
||||
receiver: &T::AccountId,
|
||||
network_id: &NetworkIdOf<T>,
|
||||
preimage_hash: &EvmHash,
|
||||
nonce: ClaimNonce,
|
||||
) -> Vec<u8> {
|
||||
let prefix = b"GMV Claim:";
|
||||
let network_id_u64: u64 = (*network_id).unique_saturated_into();
|
||||
|
||||
let receiver_ascii_hex = Self::to_ascii_hex(&receiver.encode());
|
||||
let preimage_ascii_hex = Self::to_ascii_hex(preimage_hash.as_ref());
|
||||
let network_ascii_hex = Self::to_ascii_hex(&network_id_u64.to_be_bytes());
|
||||
let network_ascii = Self::to_ascii_base10(network_id_u64);
|
||||
let nonce_ascii = Self::to_ascii_base10(nonce);
|
||||
|
||||
let what_length = receiver_ascii_hex.len()
|
||||
.saturating_add(preimage_ascii_hex.len())
|
||||
.saturating_add(network_ascii_hex.len())
|
||||
.saturating_add(10 + 11 + 12 + 11); // all 4 prefixes
|
||||
let account_label = b"\naccount:0x";
|
||||
let preimage_label = b"\npreimage:0x";
|
||||
let network_label = b"\nnetwork:";
|
||||
let nonce_label = b"\nnonce:";
|
||||
|
||||
let what_length = prefix.len()
|
||||
.saturating_add(account_label.len()).saturating_add(receiver_ascii_hex.len())
|
||||
.saturating_add(preimage_label.len()).saturating_add(preimage_ascii_hex.len())
|
||||
.saturating_add(network_label.len()).saturating_add(network_ascii.len())
|
||||
.saturating_add(nonce_label.len()).saturating_add(nonce_ascii.len());
|
||||
|
||||
let mut what = Vec::with_capacity(what_length);
|
||||
what.extend_from_slice(prefix);
|
||||
|
||||
what.extend_from_slice(b"\naccount:0x");
|
||||
what.extend_from_slice(account_label);
|
||||
what.extend_from_slice(&receiver_ascii_hex);
|
||||
|
||||
what.extend_from_slice(b"\npreimage:0x");
|
||||
what.extend_from_slice(preimage_label);
|
||||
what.extend_from_slice(&preimage_ascii_hex);
|
||||
|
||||
what.extend_from_slice(b"\nnetwork:0x");
|
||||
what.extend_from_slice(&network_ascii_hex);
|
||||
what.extend_from_slice(network_label);
|
||||
what.extend_from_slice(&network_ascii);
|
||||
|
||||
let mut l = what.len();
|
||||
let mut rev = Vec::new();
|
||||
while l > 0 {
|
||||
rev.push(b'0' + (l % 10) as u8);
|
||||
l /= 10;
|
||||
}
|
||||
what.extend_from_slice(nonce_label);
|
||||
what.extend_from_slice(&nonce_ascii);
|
||||
|
||||
let mut v = Vec::with_capacity(26 + rev.len() + what.len());
|
||||
v.extend_from_slice(b"\x19Ethereum Signed Message:\n");
|
||||
v.extend(rev.into_iter().rev());
|
||||
let length_ascii = Self::to_ascii_base10(what.len());
|
||||
let message_prefix = b"\x19Ethereum Signed Message:\n";
|
||||
|
||||
let message_capacity = message_prefix.len() + length_ascii.len() + what.len();
|
||||
let mut v = Vec::with_capacity(message_capacity);
|
||||
v.extend_from_slice(message_prefix);
|
||||
v.extend_from_slice(&length_ascii);
|
||||
v.extend(what);
|
||||
|
||||
v
|
||||
@ -440,8 +501,9 @@ impl<T: Config> Pallet<T> {
|
||||
preimage_hash: &EvmHash,
|
||||
evm_address: &EvmAddress,
|
||||
evm_signature: &EvmSignature,
|
||||
nonce: ClaimNonce,
|
||||
) -> DispatchResult {
|
||||
let message = Self::ethereum_signable_message(who, network_id, preimage_hash);
|
||||
let message = Self::ethereum_signable_message(who, network_id, preimage_hash, nonce);
|
||||
let message_bytes = SubstrateKeccakHasher::hash(&message).to_fixed_bytes();
|
||||
|
||||
let recovered_pubkey = secp256k1_ecdsa_recover(evm_signature, &message_bytes)
|
||||
|
||||
@ -5,7 +5,7 @@ use super::*;
|
||||
pub use crate as ghost_governance;
|
||||
use frame_support::{
|
||||
derive_impl, parameter_types,
|
||||
traits::{ConstU32, ConstU128},
|
||||
traits::{ConstU8, ConstU32, ConstU128},
|
||||
};
|
||||
use frame_system::EnsureRoot;
|
||||
use sp_runtime::BuildStorage;
|
||||
@ -53,6 +53,7 @@ impl Config for Test {
|
||||
|
||||
type MinimumDonation = ConstU128<69>;
|
||||
type MaxProofDepth = ConstU32<5>;
|
||||
type MaxPartialClaims = ConstU8<3>;
|
||||
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ use hex_literal::hex;
|
||||
|
||||
use sp_runtime::AccountId32;
|
||||
use frame_support::traits::Get;
|
||||
use frame_support::assert_ok;
|
||||
use frame_support::{assert_ok, assert_err};
|
||||
use libsecp256k1::{Message, SecretKey, PublicKey};
|
||||
|
||||
use ghost_helpers::merkle_tree::{generate_tree, generate_proof};
|
||||
@ -131,7 +131,8 @@ fn claim_happy_path() {
|
||||
let message_string_bytes = Governance::ethereum_signable_message(
|
||||
¤t_user.substrate_account,
|
||||
&network_id,
|
||||
&preimage_hash
|
||||
&preimage_hash,
|
||||
0u8,
|
||||
);
|
||||
|
||||
let message_hash = SubstrateKeccakHasher::hash(&message_string_bytes);
|
||||
@ -154,7 +155,8 @@ fn claim_happy_path() {
|
||||
network_id,
|
||||
claim_package,
|
||||
current_user.evm_address.clone(),
|
||||
evm_signature
|
||||
evm_signature,
|
||||
current_user.allowed_shares,
|
||||
));
|
||||
|
||||
let updated_share = MemberShares::<Test>::get(¤t_user.substrate_account);
|
||||
@ -172,6 +174,201 @@ fn claim_happy_path() {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn partial_claims_happy_path() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let network_id = 69u64;
|
||||
|
||||
let minimum_donation_u128 = <<Test as crate::Config>::MinimumDonation as Get<u128>>::get();
|
||||
let minimum_donation: BalanceOf<Test> = minimum_donation_u128.unique_saturated_into();
|
||||
|
||||
let secret_key = SecretKey::parse(&[7u8; 32]).unwrap();
|
||||
let public_key = PublicKey::from_secret_key(&secret_key);
|
||||
let pubkey_raw = &public_key.serialize()[1..65];
|
||||
let pubkey_hash = SubstrateKeccakHasher::hash(pubkey_raw);
|
||||
|
||||
let mut evm_addr_bytes = [0u8; 20];
|
||||
evm_addr_bytes.copy_from_slice(&pubkey_hash.as_ref()[12..32]);
|
||||
|
||||
let substrate_account_a = AccountId32::new([11u8; 32]);
|
||||
let substrate_account_b = AccountId32::new([22u8; 32]);
|
||||
let substrate_account_c = AccountId32::new([33u8; 32]);
|
||||
|
||||
let current_user = NewTestUser {
|
||||
substrate_account: substrate_account_a.clone(),
|
||||
evm_secret: secret_key,
|
||||
evm_address: EvmAddress::from(evm_addr_bytes),
|
||||
allowed_shares: 1000u128,
|
||||
token_id: 7,
|
||||
};
|
||||
|
||||
let max_index = 0u8;
|
||||
let raw_values_complex = vec![(0u8, ¤t_user)];
|
||||
|
||||
let merkle_tree = generate_tree::<SubstrateKeccakHasher, u8, _, _, _>(
|
||||
max_index,
|
||||
raw_values_complex,
|
||||
|
||||
|item: (u8, &NewTestUser)| -> Result<(usize, Vec<u8>), ()> {
|
||||
let (index, u) = item;
|
||||
let tmp_package = ClaimPackage {
|
||||
shares: u.allowed_shares,
|
||||
merkle_proof: Default::default(),
|
||||
token_id: u.token_id,
|
||||
index: index as u32
|
||||
};
|
||||
Ok((index as usize, tmp_package.get_preimage(&u.evm_address, network_id).to_vec()))
|
||||
}
|
||||
).unwrap();
|
||||
|
||||
let total_shares = 1_000_000;
|
||||
let merkle_root = *merkle_tree.last().unwrap();
|
||||
let network_state = NetworkShare::new(total_shares, merkle_root, 0);
|
||||
let global_state = ShareState::new(total_shares);
|
||||
|
||||
NetworkShares::<Test>::insert(&network_id, network_state);
|
||||
GlobalShares::<Test>::put(global_state);
|
||||
|
||||
let setup_governor = |account: &<Test as frame_system::Config>::AccountId| {
|
||||
MemberShares::<Test>::insert(account, MemberShare {
|
||||
locked_balance: minimum_donation,
|
||||
initiated_network: None,
|
||||
activated_shares: 0,
|
||||
});
|
||||
};
|
||||
setup_governor(&substrate_account_a);
|
||||
setup_governor(&substrate_account_b);
|
||||
setup_governor(&substrate_account_c);
|
||||
|
||||
let proof = generate_proof::<SubstrateKeccakHasher, u8>(&merkle_tree, max_index, 0u8);
|
||||
let claim_package = ClaimPackage {
|
||||
shares: current_user.allowed_shares,
|
||||
merkle_proof: BoundedVec::try_from(proof).unwrap(),
|
||||
token_id: current_user.token_id,
|
||||
index: 0,
|
||||
};
|
||||
|
||||
let preimage = claim_package.get_preimage(¤t_user.evm_address, network_id);
|
||||
let preimage_hash = SubstrateKeccakHasher::hash(&preimage);
|
||||
|
||||
let generate_test_signature = |target_account: &<Test as frame_system::Config>::AccountId| -> EvmSignature {
|
||||
let active_nonce = ClaimedHashes::<Test>::get(&preimage_hash);
|
||||
let message_string_bytes = Governance::ethereum_signable_message(
|
||||
&target_account,
|
||||
&network_id,
|
||||
&preimage_hash,
|
||||
active_nonce,
|
||||
);
|
||||
|
||||
let message_hash = SubstrateKeccakHasher::hash(&message_string_bytes);
|
||||
let mut message_bytes = [0u8; 32];
|
||||
message_bytes.copy_from_slice(message_hash.as_ref());
|
||||
|
||||
let msg_to_sign = Message::parse(&message_bytes);
|
||||
let (sig, recovery_id) = libsecp256k1::sign(&msg_to_sign, ¤t_user.evm_secret);
|
||||
|
||||
let mut signature_raw = [0u8; 65];
|
||||
signature_raw[0..32].copy_from_slice(&sig.r.b32());
|
||||
signature_raw[32..64].copy_from_slice(&sig.s.b32());
|
||||
signature_raw[64] = recovery_id.serialize();
|
||||
|
||||
EvmSignature::from(signature_raw)
|
||||
};
|
||||
|
||||
let sig_0 = generate_test_signature(&substrate_account_a);
|
||||
assert_ok!(Governance::claim(
|
||||
RuntimeOrigin::signed(substrate_account_a.clone()),
|
||||
network_id,
|
||||
claim_package.clone(),
|
||||
current_user.evm_address.clone(),
|
||||
sig_0,
|
||||
400,
|
||||
));
|
||||
|
||||
let global_share = GlobalShares::<Test>::get();
|
||||
assert_eq!(global_share.claimed_shares, 400);
|
||||
assert_eq!(global_share.total_shares, total_shares);
|
||||
|
||||
let network_share = NetworkShares::<Test>::get(&network_id);
|
||||
assert_eq!(network_share.claimed_shares(), 400);
|
||||
assert_eq!(network_share.total_shares(), total_shares);
|
||||
|
||||
assert_eq!(MemberShares::<Test>::get(&substrate_account_a).activated_shares, 400);
|
||||
assert_eq!(ClaimedHashes::<Test>::get(&preimage_hash), 1);
|
||||
assert_eq!(ClaimedShares::<Test>::get(&preimage_hash), 400);
|
||||
|
||||
let sig_1_fail = generate_test_signature(&substrate_account_b);
|
||||
assert_err!(
|
||||
Governance::claim(
|
||||
RuntimeOrigin::signed(substrate_account_b.clone()),
|
||||
network_id,
|
||||
claim_package.clone(),
|
||||
current_user.evm_address.clone(),
|
||||
sig_1_fail,
|
||||
700,
|
||||
),
|
||||
Error::<Test>::ExceedsAllowedShares
|
||||
);
|
||||
|
||||
let sig_1_success = generate_test_signature(&substrate_account_b);
|
||||
assert_ok!(Governance::claim(
|
||||
RuntimeOrigin::signed(substrate_account_b.clone()),
|
||||
network_id,
|
||||
claim_package.clone(),
|
||||
current_user.evm_address.clone(),
|
||||
sig_1_success,
|
||||
100,
|
||||
));
|
||||
|
||||
let global_share = GlobalShares::<Test>::get();
|
||||
assert_eq!(global_share.claimed_shares, 500);
|
||||
assert_eq!(global_share.total_shares, total_shares);
|
||||
|
||||
let network_share = NetworkShares::<Test>::get(&network_id);
|
||||
assert_eq!(network_share.claimed_shares(), 500);
|
||||
assert_eq!(network_share.total_shares(), total_shares);
|
||||
|
||||
assert_eq!(MemberShares::<Test>::get(&substrate_account_b).activated_shares, 100);
|
||||
assert_eq!(ClaimedHashes::<Test>::get(&preimage_hash), 2);
|
||||
assert_eq!(ClaimedShares::<Test>::get(&preimage_hash), 500);
|
||||
|
||||
let sig_2_final = generate_test_signature(&substrate_account_c);
|
||||
assert_ok!(Governance::claim(
|
||||
RuntimeOrigin::signed(substrate_account_c.clone()),
|
||||
network_id,
|
||||
claim_package.clone(),
|
||||
current_user.evm_address.clone(),
|
||||
sig_2_final,
|
||||
300,
|
||||
));
|
||||
|
||||
let global_share = GlobalShares::<Test>::get();
|
||||
assert_eq!(global_share.claimed_shares, 1_000);
|
||||
assert_eq!(global_share.total_shares, total_shares);
|
||||
|
||||
let network_share = NetworkShares::<Test>::get(&network_id);
|
||||
assert_eq!(network_share.claimed_shares(), 1_000);
|
||||
assert_eq!(network_share.total_shares(), total_shares);
|
||||
|
||||
assert_eq!(MemberShares::<Test>::get(&substrate_account_c).activated_shares, 500);
|
||||
assert_eq!(ClaimedHashes::<Test>::get(&preimage_hash), 3);
|
||||
assert_eq!(ClaimedShares::<Test>::get(&preimage_hash), 1_000);
|
||||
|
||||
let sig_3_exhausted = generate_test_signature(&substrate_account_a);
|
||||
assert_err!(
|
||||
Governance::claim(
|
||||
RuntimeOrigin::signed(substrate_account_a),
|
||||
network_id,
|
||||
claim_package,
|
||||
current_user.evm_address.clone(),
|
||||
sig_3_exhausted,
|
||||
100,
|
||||
),
|
||||
Error::<Test>::PartialClaimsExhausted
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_proof_from_python_preclaims_for_sepolia() {
|
||||
new_test_ext().execute_with(|| {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user