diff --git a/src/contracts/isms/multisig/merkleroot_multisig_ism.cairo b/src/contracts/isms/multisig/merkleroot_multisig_ism.cairo index 2c75912..974c7bc 100644 --- a/src/contracts/isms/multisig/merkleroot_multisig_ism.cairo +++ b/src/contracts/isms/multisig/merkleroot_multisig_ism.cairo @@ -51,13 +51,13 @@ pub mod merkleroot_multisig_ism { } let (signature_r, signature_s) = get_signature_at(_metadata.clone(), i); - // we loop on the validators list public kew in order to find a match + // we loop on the validators list public key in order to find a match let mut cur_idx = 0; let is_signer_in_list = loop { if (cur_idx == validators.len()) { break false; } - let signer = *validators.at(cur_idx).address; + let signer = *validators.at(cur_idx); if check_ecdsa_signature( digest, signer.try_into().unwrap(), signature_r, signature_s ) { diff --git a/src/contracts/isms/multisig/messageid_multisig_ism.cairo b/src/contracts/isms/multisig/messageid_multisig_ism.cairo index 31735c9..4b18cf3 100644 --- a/src/contracts/isms/multisig/messageid_multisig_ism.cairo +++ b/src/contracts/isms/multisig/messageid_multisig_ism.cairo @@ -19,7 +19,7 @@ pub mod messageid_multisig_ism { mod Errors { pub const NO_MULTISIG_THRESHOLD_FOR_MESSAGE: felt252 = 'No MultisigISM treshold present'; - pub const VERIFICATION_FAILED_THRESHOLD_NOT_REACHED: felt252 = 'Verify failed, < threshold'; + pub const NO_MATCH_FOR_SIGNATURE: felt252 = 'No match for given signature'; pub const EMPTY_METADATA: felt252 = 'Empty metadata'; } #[abi(embed_v0)] @@ -42,8 +42,6 @@ pub mod messageid_multisig_ism { let (validators, threshold) = validator_configuration .validators_and_threshold(_message); assert(threshold > 0, Errors::NO_MULTISIG_THRESHOLD_FOR_MESSAGE); - let validator_count = validators.len(); - let mut unmatched_signatures = 0; let mut matched_signatures = 0; let mut i = 0; @@ -53,41 +51,28 @@ pub mod messageid_multisig_ism { break (); } let signature = get_signature_at(_metadata.clone(), i); - - // we loop on the validators list public kew in order to find a match + // we loop on the validators list public key in order to find a match let mut cur_idx = 0; let is_signer_in_list = loop { if (cur_idx == validators.len()) { break false; } - let signer = *validators.at(cur_idx).address; - if bool_is_eth_signature_valid( - digest.into(), signature, signer.try_into().unwrap() - ) { + let signer = *validators.at(cur_idx); + if bool_is_eth_signature_valid(digest, signature, signer) { // we found a match break true; } cur_idx += 1; }; - if (!is_signer_in_list) { - unmatched_signatures += 1; - } else { - matched_signatures += 1; - } - assert( - unmatched_signatures < validator_count - threshold, - Errors::VERIFICATION_FAILED_THRESHOLD_NOT_REACHED - ); + assert(is_signer_in_list, Errors::NO_MATCH_FOR_SIGNATURE); i += 1; }; - assert( - matched_signatures >= threshold, Errors::VERIFICATION_FAILED_THRESHOLD_NOT_REACHED - ); + println!("matched_signatures: {}", matched_signatures); true } } - fn digest(_metadata: Bytes, _message: Message) -> felt252 { + fn digest(_metadata: Bytes, _message: Message) -> u256 { let origin_merkle_tree_hook = MessageIdIsmMetadata::origin_merkle_tree_hook( _metadata.clone() ); @@ -100,8 +85,6 @@ pub mod messageid_multisig_ism { index, MessageTrait::format_message(_message) ) - .try_into() - .unwrap() } fn get_signature_at(_metadata: Bytes, _index: u32) -> Signature { diff --git a/src/contracts/isms/multisig/multisig_ism.cairo b/src/contracts/isms/multisig/multisig_ism.cairo index 6acdc77..cba6460 100644 --- a/src/contracts/isms/multisig/multisig_ism.cairo +++ b/src/contracts/isms/multisig/multisig_ism.cairo @@ -15,15 +15,10 @@ pub mod multisig_ism { impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl; type Index = felt252; - #[derive(Serde, Copy, starknet::Store, Drop, PartialEq)] - pub struct ValidatorInformations { - pub address: EthAddress, - pub public_key: u256 - } #[storage] struct Storage { - validators: LegacyMap, + validators: LegacyMap, threshold: u32, #[substorage(v0)] ownable: OwnableComponent::Storage, @@ -48,12 +43,11 @@ pub mod multisig_ism { mod Errors { pub const VALIDATOR_ADDRESS_CANNOT_BE_NULL: felt252 = 'Validator address cannot be 0'; - pub const VALIDATOR_PUBLIC_KEY_CANNOT_BE_NULL: felt252 = 'Validator pk cannot be 0'; } #[abi(embed_v0)] impl IMultisigIsmImpl of IMultisigIsm { - fn get_validators(self: @ContractState) -> Span { + fn get_validators(self: @ContractState) -> Span { build_validators_span(self) } @@ -61,7 +55,7 @@ pub mod multisig_ism { self.threshold.read() } - fn set_validators(ref self: ContractState, _validators: Span) { + fn set_validators(ref self: ContractState, _validators: Span) { self.ownable.assert_only_owner(); let mut cur_idx = 0; @@ -71,10 +65,8 @@ pub mod multisig_ism { } let validator = *_validators.at(cur_idx); assert( - validator.address != 0.try_into().unwrap(), - Errors::VALIDATOR_ADDRESS_CANNOT_BE_NULL + validator != 0.try_into().unwrap(), Errors::VALIDATOR_ADDRESS_CANNOT_BE_NULL ); - // assert(validator.public_key != 0, Errors::VALIDATOR_PUBLIC_KEY_CANNOT_BE_NULL); self.validators.write(cur_idx.into(), validator); cur_idx += 1; } @@ -87,7 +79,7 @@ pub mod multisig_ism { fn validators_and_threshold( self: @ContractState, _message: Message - ) -> (Span, u32) { + ) -> (Span, u32) { // USER CONTRACT DEFINITION HERE // USER CAN SPECIFY VALIDATORS SELECTION CONDITIONS let threshold = self.threshold.read(); @@ -95,12 +87,12 @@ pub mod multisig_ism { } } - fn build_validators_span(self: @ContractState) -> Span { + fn build_validators_span(self: @ContractState) -> Span { let mut validators = ArrayTrait::new(); let mut cur_idx = 0; loop { let validator = self.validators.read(cur_idx); - if (validator.address == 0.try_into().unwrap()) { + if (validator == 0.try_into().unwrap()) { break (); } validators.append(validator); diff --git a/src/contracts/isms/multisig/validator_announce.cairo b/src/contracts/isms/multisig/validator_announce.cairo index d488571..4d91469 100644 --- a/src/contracts/isms/multisig/validator_announce.cairo +++ b/src/contracts/isms/multisig/validator_announce.cairo @@ -130,10 +130,10 @@ pub mod validator_announce { let mailboxclient = IMailboxClientDispatcher { contract_address: self.mailboxclient.read() }; - let mailboxcient_address: felt252 = self.mailboxclient.read().try_into().unwrap(); + let mailboxclient_address: felt252 = self.mailboxclient.read().try_into().unwrap(); let mut input: Array = array![ mailboxclient.get_local_domain().into(), - mailboxcient_address.try_into().unwrap(), + mailboxclient_address.try_into().unwrap(), HYPERLANE_ANNOUNCEMENT.into() ]; let hash = keccak_u256s_be_inputs(input.span()); diff --git a/src/contracts/libs/multisig/message_id_ism_metadata.cairo b/src/contracts/libs/multisig/message_id_ism_metadata.cairo index 14d7d24..9f93bea 100644 --- a/src/contracts/libs/multisig/message_id_ism_metadata.cairo +++ b/src/contracts/libs/multisig/message_id_ism_metadata.cairo @@ -11,7 +11,7 @@ pub mod message_id_ism_metadata { pub const ORIGIN_MERKLE_TREE_HOOK_OFFSET: u32 = 0; pub const ROOT_OFFSET: u32 = 32; pub const INDEX_OFFSET: u32 = 64; - pub const SIGNATURE_OFFSET: u32 = 96; + pub const SIGNATURE_OFFSET: u32 = 80; impl MessagIdIsmMetadataImpl of MessageIdIsmMetadata { fn origin_merkle_tree_hook(_metadata: Bytes) -> u256 { let (_, felt) = _metadata.read_u256(ORIGIN_MERKLE_TREE_HOOK_OFFSET); @@ -30,9 +30,9 @@ pub mod message_id_ism_metadata { fn signature_at(_metadata: Bytes, _index: u32) -> (u8, u256, u256) { // the first signer index is 0 - let (_, r) = _metadata.read_u256(SIGNATURE_OFFSET + 96 * _index); - let (_, s) = _metadata.read_u256(SIGNATURE_OFFSET + 96 * _index); - let (_, v) = _metadata.read_u8(SIGNATURE_OFFSET + 96 * _index + 32); + let (index_r, r) = _metadata.read_u256(SIGNATURE_OFFSET + 80 * _index); + let (index_s, s) = _metadata.read_u256(index_r); + let (_, v) = _metadata.read_u8(index_s); (v, r, s) } } diff --git a/src/interfaces.cairo b/src/interfaces.cairo index c1298d2..fa00866 100644 --- a/src/interfaces.cairo +++ b/src/interfaces.cairo @@ -1,6 +1,5 @@ use alexandria_bytes::Bytes; use core::array::ArrayTrait; -use hyperlane_starknet::contracts::isms::multisig::multisig_ism::multisig_ism::ValidatorInformations; use hyperlane_starknet::contracts::libs::message::Message; use starknet::ContractAddress; use starknet::EthAddress; @@ -222,13 +221,13 @@ pub trait IRouter { pub trait IMultisigIsm { fn validators_and_threshold( self: @TContractState, _message: Message - ) -> (Span, u32); + ) -> (Span, u32); - fn get_validators(self: @TContractState) -> Span; + fn get_validators(self: @TContractState) -> Span; fn get_threshold(self: @TContractState) -> u32; - fn set_validators(ref self: TContractState, _validators: Span); + fn set_validators(ref self: TContractState, _validators: Span); fn set_threshold(ref self: TContractState, _threshold: u32); } diff --git a/src/lib.cairo b/src/lib.cairo index f3f4486..5f9ac2a 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -37,5 +37,5 @@ mod utils { mod tests { pub mod setup; pub mod test_mailbox; -// pub mod test_multisig; + pub mod test_multisig; } diff --git a/src/tests/setup.cairo b/src/tests/setup.cairo index 0ef29fd..3320f4b 100644 --- a/src/tests/setup.cairo +++ b/src/tests/setup.cairo @@ -2,13 +2,17 @@ use core::result::ResultTrait; use hyperlane_starknet::contracts::mocks::message_recipient::message_recipient; use hyperlane_starknet::interfaces::{ IMailboxDispatcher, IMailboxDispatcherTrait, IMessageRecipientDispatcher, - IMessageRecipientDispatcherTrait + IMessageRecipientDispatcherTrait, IInterchainSecurityModule, + IInterchainSecurityModuleDispatcher, IInterchainSecurityModuleDispatcherTrait, + IMultisigIsmDispatcher, IMultisigIsmDispatcherTrait, IValidatorAnnounceDispatcher, + IValidatorAnnounceDispatcherTrait, IMailboxClientDispatcher, IMailboxClientDispatcherTrait }; use snforge_std::{ declare, ContractClassTrait, CheatTarget, EventSpy, EventAssertions, spy_events, SpyOn }; +use starknet::secp256_trait::Signature; -use starknet::{ContractAddress, contract_address_const}; +use starknet::{ContractAddress, contract_address_const, EthAddress}; pub const LOCAL_DOMAIN: u32 = 534352; pub const DESTINATION_DOMAIN: u32 = 9841001; @@ -49,6 +53,14 @@ pub fn RECIPIENT_ADDRESS() -> ContractAddress { contract_address_const::<'RECIPIENT_ADDRESS'>() } +pub fn VALIDATOR_ADDRESS() -> EthAddress { + 'VALIDATOR_ADDRESS'.try_into().unwrap() +} + +pub fn VALIDATOR_PUBLIC_KEY() -> u256 { + 'VALIDATOR_PUBLIC_KEY' +} + pub fn setup() -> (IMailboxDispatcher, EventSpy) { let mailbox_class = declare("mailbox").unwrap(); let (mailbox_addr, _) = mailbox_class @@ -64,3 +76,77 @@ pub fn mock_setup() -> IMessageRecipientDispatcher { let (message_recipient_addr, _) = message_recipient_class.deploy(@array![]).unwrap(); IMessageRecipientDispatcher { contract_address: message_recipient_addr } } + +pub fn setup_messageid_multisig_ism() -> IInterchainSecurityModuleDispatcher { + let messageid_multisig_class = declare("messageid_multisig_ism").unwrap(); + + let (messageid_multisig_addr, _) = messageid_multisig_class.deploy(@array![]).unwrap(); + IInterchainSecurityModuleDispatcher { contract_address: messageid_multisig_addr } +} + +pub fn setup_multisig_ism() -> IMultisigIsmDispatcher { + let multisig_ism_class = declare("multisig_ism").unwrap(); + let (multisig_ism_addr, _) = multisig_ism_class.deploy(@array![OWNER().into()]).unwrap(); + IMultisigIsmDispatcher { contract_address: multisig_ism_addr } +} + +pub fn setup_mailbox_client() -> IMailboxClientDispatcher { + let (mailbox, _) = setup(); + let mailboxclient_class = declare("mailboxclient").unwrap(); + let (mailboxclient_addr, _) = mailboxclient_class + .deploy(@array![mailbox.contract_address.into(), OWNER().into()]) + .unwrap(); + IMailboxClientDispatcher { contract_address: mailboxclient_addr } +} + + +pub fn setup_validator_announce() -> IValidatorAnnounceDispatcher { + let validator_announce_class = declare("validator_announce").unwrap(); + let mailboxclient = setup_mailbox_client(); + let (validator_announce_addr, _) = validator_announce_class + .deploy(@array![mailboxclient.contract_address.into()]) + .unwrap(); + IValidatorAnnounceDispatcher { contract_address: validator_announce_addr } +} + + +// Configuration from the main cairo repo: https://github.com/starkware-libs/cairo/blob/main/corelib/src/test/secp256k1_test.cairo +pub fn get_message_and_signature(y_parity: bool) -> (u256, Array, Array) { + let msg_hash = 0xfbff8940be2153ce000c0e1933bf32e179c60f53c45f56b4ac84b2e90f1f6214; + let validators_array: Array = array![ + 0x2cb1a91F2F23D6eC7FD22d2f7996f55B71EB32dc.try_into().unwrap(), + 0x0fb1A81BcefDEc06154279219F227938D00B1c12.try_into().unwrap(), + 0xF650b555CFDEfF61d225058e26326266E69660c2.try_into().unwrap(), + 0x03aC66d13dc1B5b10fc363fC32f324ca947CDac1.try_into().unwrap(), + 0x5711B186cdCAFD9E7aa1f78c0A0c30d3C7A2Af77.try_into().unwrap() + ]; + let signatures = array![ + Signature { + r: 0xb994fec0137776002d05dcf847bbba338285f1210c9ca7829109578ac876519f, + s: 0x0a42bb91f22ef042ca82fdcf8c8a5846e0debbce509dc2a0ce28a988dcbe4a16, + y_parity + }, + Signature { + r: 0xf81a5dd3f871ad2d27a3b538e73663d723f8263fb3d289514346d43d000175f5, + s: 0x083df770623e9ae52a7bb154473961e24664bb003bdfdba6100fb5e540875ce1, + y_parity + }, + Signature { + r: 0x76b194f951f94492ca582dab63dc413b9ac1ca9992c22bc2186439e9ab8fdd3c, + s: 0x62a6a6f402edaa53e9bdc715070a61edb0d98d4e14e182f60bdd4ae932b40b29, + y_parity + }, + Signature { + r: 0x35932eefd85897d868aaacd4ba7aee81a2384e42ba062133f6d37fdfebf94ad4, + s: 0x78cce49db96ee27c3f461800388ac95101476605baa64a194b7dd4d56d2d4a4d, + y_parity + }, + Signature { + r: 0x6b38d4353d69396e91c57542254348d16459d448ab887574e9476a6ff76d49a1, + s: 0x3527627295bde423d7d799afef22affac4f00c70a5b651ad14c8879aeb9b6e03, + y_parity + } + ]; + + (msg_hash, validators_array, signatures) +} diff --git a/src/tests/test_multisig.cairo b/src/tests/test_multisig.cairo new file mode 100644 index 0000000..c98937f --- /dev/null +++ b/src/tests/test_multisig.cairo @@ -0,0 +1,217 @@ +use alexandria_bytes::{Bytes, BytesTrait}; +use alexandria_data_structures::array_ext::ArrayTraitExt; +use core::array::ArrayTrait; +use core::array::SpanTrait; +use hyperlane_starknet::contracts::libs::message::{Message, MessageTrait, HYPERLANE_VERSION}; +use hyperlane_starknet::contracts::libs::multisig::message_id_ism_metadata::message_id_ism_metadata::MessageIdIsmMetadata; +use hyperlane_starknet::contracts::mailbox::mailbox; +use hyperlane_starknet::interfaces::IMessageRecipientDispatcherTrait; +use hyperlane_starknet::interfaces::IMultisigIsmDispatcherTrait; +use hyperlane_starknet::interfaces::{ + IMailbox, IMailboxDispatcher, IMailboxDispatcherTrait, ModuleType, + IInterchainSecurityModuleDispatcher, IInterchainSecurityModuleDispatcherTrait +}; +use hyperlane_starknet::tests::setup::{ + setup, mock_setup, setup_messageid_multisig_ism, setup_multisig_ism, OWNER, NEW_OWNER, + VALIDATOR_ADDRESS, VALIDATOR_PUBLIC_KEY, setup_validator_announce, get_message_and_signature, + LOCAL_DOMAIN, DESTINATION_DOMAIN, RECIPIENT_ADDRESS +}; +use openzeppelin::access::ownable::OwnableComponent; +use openzeppelin::access::ownable::interface::{IOwnableDispatcher, IOwnableDispatcherTrait}; +use snforge_std::cheatcodes::events::EventAssertions; +use snforge_std::{start_prank, CheatTarget, stop_prank}; +use starknet::eth_address::EthAddress; +use starknet::secp256_trait::Signature; +#[test] +fn test_set_validators() { + let new_validators = array![VALIDATOR_ADDRESS()].span(); + let validators = setup_multisig_ism(); + let ownable = IOwnableDispatcher { contract_address: validators.contract_address }; + start_prank(CheatTarget::One(ownable.contract_address), OWNER()); + validators.set_validators(new_validators); + let validators_span = validators.get_validators(); + assert(validators_span == new_validators, 'wrong validator address def'); +} + + +#[test] +fn test_set_threshold() { + let new_threshold = 3; + let validators = setup_multisig_ism(); + let ownable = IOwnableDispatcher { contract_address: validators.contract_address }; + start_prank(CheatTarget::One(ownable.contract_address), OWNER()); + validators.set_threshold(new_threshold); + assert(validators.get_threshold() == new_threshold, 'wrong validator threshold'); +} + + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn test_set_validators_fails_if_caller_not_owner() { + let new_validators = array![VALIDATOR_ADDRESS(),].span(); + let validators = setup_multisig_ism(); + let ownable = IOwnableDispatcher { contract_address: validators.contract_address }; + start_prank(CheatTarget::One(ownable.contract_address), NEW_OWNER()); + validators.set_validators(new_validators); +} + +#[test] +#[should_panic(expected: ('Caller is not the owner',))] +fn test_set_threshold_fails_if_caller_not_owner() { + let new_threshold = 3; + let validators = setup_multisig_ism(); + let ownable = IOwnableDispatcher { contract_address: validators.contract_address }; + start_prank(CheatTarget::One(ownable.contract_address), NEW_OWNER()); + validators.set_threshold(new_threshold); +} + + +#[test] +fn test_message_id_ism_metadata() { + let origin_merkle_tree_hook = array![ + // origin_merkle_tree_hook + 0x02030405060708091011121314151623, 0x16151413121110090807060504030201 + ]; + let root = array![0x01000304050607080910111213141516, 0x01020304050607080920111213141516,]; + let index = array![0x00000013000000000000000000000000]; + let index_u32 = 0x13; + let signature_1 = array![ + 0x09020304050607080910111213141516, + 0x01020304050607080920111213141516, + 0x01020304050607080910000000000000, + 0x02010304050607080910111213141516, + 0x03000000000000000000000000000000 + ]; + let signature_2 = array![ + 0x01020304050607080910111213141516, + 0x01020304050607080910111213141516, + 0x01020304050607080910111213141516, + 0x01020304050607080910000000000000, + 0x02000000000000000000000000000000 + ]; + let signature_3 = array![ + 0x01020304050607080910111213141516, + 0x13092450000011115450564500700000, + 0x01020304050607080910000000000000, + 0x01020304050607080910111213141516, + 0x02000000000000000000000000000000 + ]; + let signature_1_v = 0x3; + let signature_2_v = 0x2; + let signature_3_v = 0x2; + let mut metadata = origin_merkle_tree_hook.concat(@root); + metadata = metadata.concat(@index); + metadata = metadata.concat(@signature_1); + metadata = metadata.concat(@signature_2); + metadata = metadata.concat(@signature_3); + let bytes_metadata = BytesTrait::new(496, metadata); + assert( + MessageIdIsmMetadata::origin_merkle_tree_hook( + bytes_metadata.clone() + ) == u256 { low: *origin_merkle_tree_hook.at(1), high: *origin_merkle_tree_hook.at(0) }, + 'wrong merkle tree hook' + ); + assert( + MessageIdIsmMetadata::root( + bytes_metadata.clone() + ) == u256 { low: *root.at(1), high: *root.at(0) }, + 'wrong root' + ); + assert(MessageIdIsmMetadata::index(bytes_metadata.clone()) == index_u32, 'wrong index'); + assert( + MessageIdIsmMetadata::signature_at( + bytes_metadata.clone(), 0 + ) == ( + signature_1_v, + u256 { low: *signature_1.at(1), high: *signature_1.at(0) }, + u256 { low: *signature_1.at(3), high: *signature_1.at(2) } + ), + 'wrong signature 1' + ); + assert( + MessageIdIsmMetadata::signature_at( + bytes_metadata.clone(), 1 + ) == ( + signature_2_v, + u256 { low: *signature_2.at(1), high: *signature_2.at(0) }, + u256 { low: *signature_2.at(3), high: *signature_2.at(2) } + ), + 'wrong signature 2' + ); + assert( + MessageIdIsmMetadata::signature_at( + bytes_metadata.clone(), 2 + ) == ( + signature_3_v, + u256 { low: *signature_3.at(1), high: *signature_3.at(0) }, + u256 { low: *signature_3.at(3), high: *signature_3.at(2) } + ), + 'wrong signature 3' + ); +} + + +#[test] +fn test_message_id_multisig_module_type() { + let messageid = setup_messageid_multisig_ism(); + assert( + messageid.module_type() == ModuleType::MESSAGE_ID_MULTISIG(messageid.contract_address), + 'Wrong module type' + ); +} + + +#[test] +fn test_message_id_multisig_verify() { + let array = array![ + 0x01020304050607080910111213141516, + 0x01020304050607080910111213141516, + 0x01020304050607080910000000000000 + ]; + let message_body = BytesTrait::new(42, array); + let message = Message { + version: HYPERLANE_VERSION, + nonce: 0, + origin: LOCAL_DOMAIN, + sender: OWNER(), + destination: DESTINATION_DOMAIN, + recipient: RECIPIENT_ADDRESS(), + body: message_body.clone() + }; + let messageid = setup_messageid_multisig_ism(); + let (msg_hash, validators_address, signatures) = get_message_and_signature(false); + let validators = setup_multisig_ism(); + let metadata = array![ + 0x01020304050607080910111213141516, + 0x16151413121110090807060504030201, + 0x01020304050607080910111213141516, + 0x01020304050607080920111213141516, + 0x00000010000000000000000000000000, + *signatures.at(0).r.high, + *signatures.at(0).r.low, + *signatures.at(0).s.high, + *signatures.at(0).s.low, + *signatures.at(1).r.high, + *signatures.at(1).r.low, + *signatures.at(1).s.high, + *signatures.at(1).s.low, + *signatures.at(2).r.high, + *signatures.at(2).r.low, + *signatures.at(2).s.high, + *signatures.at(2).s.low, + *signatures.at(3).r.high, + *signatures.at(3).r.low, + *signatures.at(3).s.high, + *signatures.at(3).s.low, + 0x00000010000000000000000000000000 + ]; + let ownable = IOwnableDispatcher { contract_address: validators.contract_address }; + start_prank(CheatTarget::One(ownable.contract_address), OWNER()); + validators.set_validators(validators_address.span()); + validators.set_threshold(3); + let bytes_metadata = BytesTrait::new(496, metadata); + assert( + messageid.verify(bytes_metadata, message, validators.contract_address) == true, + 'verification failed' + ); +}