diff --git a/contracts/multisig-prover/src/contract.rs b/contracts/multisig-prover/src/contract.rs index 31c375c58..3cd6d9b5f 100644 --- a/contracts/multisig-prover/src/contract.rs +++ b/contracts/multisig-prover/src/contract.rs @@ -626,8 +626,6 @@ mod tests { assert!(event.is_some()); } - /// TODO: remove ignore flag - #[ignore = "construct proof is temporarily broken during the multisig prover amplifier gateway migration"] #[test] fn test_query_proof() { let mut deps = setup_test_case(); @@ -641,7 +639,7 @@ mod tests { assert_eq!(res.message_ids.len(), 1); match res.status { ProofStatus::Completed { execute_data } => { - assert_eq!(execute_data, test_data::execute_data()); + assert_eq!(execute_data, test_data::approve_messages_calldata()); } _ => panic!("Expected proof status to be completed"), // multisig mock will always return completed multisig } diff --git a/contracts/multisig-prover/src/encoding/abi2/execute_data.rs b/contracts/multisig-prover/src/encoding/abi2/execute_data.rs index b457ae5e7..2d4bcbf5c 100644 --- a/contracts/multisig-prover/src/encoding/abi2/execute_data.rs +++ b/contracts/multisig-prover/src/encoding/abi2/execute_data.rs @@ -6,7 +6,8 @@ use axelar_wasm_std::hash::Hash; use multisig::{key::Signature, msg::SignerWithSig, worker_set::WorkerSet}; use crate::{ - encoding::abi2::{evm_address, Proof, WeightedSigners}, + encoding::abi2::{evm_address, Message, Proof, WeightedSigners}, + error::ContractError, payload::Payload, }; @@ -41,6 +42,18 @@ impl From for IAxelarAmplifierGateway::Proof { } } +impl From for IAxelarAmplifierGateway::Message { + fn from(message: Message) -> Self { + IAxelarAmplifierGateway::Message { + messageId: message.messageId, + sourceChain: message.sourceChain, + sourceAddress: message.sourceAddress, + contractAddress: message.contractAddress, + payloadHash: message.payloadHash, + } + } +} + impl Proof { /// Proof contains the entire worker set and optimized signatures. Signatures are sorted in ascending order based on the signer's address. pub fn new(worker_set: &WorkerSet, mut signers_with_sigs: Vec) -> Self { @@ -65,20 +78,32 @@ pub fn encode( signers: Vec, payload_digest: &Hash, payload: &Payload, -) -> HexBinary { +) -> Result { let signers = to_recoverable(payload_digest.as_slice(), signers); let proof = Proof::new(worker_set, signers); - match payload { - Payload::Messages(_) => todo!(), + let data = match payload { + Payload::Messages(messages) => { + let messages: Vec<_> = messages + .iter() + .map(|msg| Message::try_from(msg).map(IAxelarAmplifierGateway::Message::from)) + .collect::, _>>()?; + + IAxelarAmplifierGateway::approveMessagesCall::new((messages, proof.into())) + .abi_encode() + .into() + } Payload::WorkerSet(new_worker_set) => { let new_worker_set = WeightedSigners::from(new_worker_set); + IAxelarAmplifierGateway::rotateSignersCall::new((new_worker_set.into(), proof.into())) .abi_encode() .into() } - } + }; + + Ok(data) } // Convert non-recoverable ECDSA signatures to recoverable ones. @@ -120,6 +145,7 @@ mod tests { use axelar_wasm_std::hash::Hash; use multisig::key::{KeyType, KeyTyped, Signature}; + use multisig::msg::{Signer, SignerWithSig}; use crate::{ encoding::abi2::{ @@ -128,7 +154,7 @@ mod tests { payload_hash_to_sign, }, payload::Payload, - test::test_data::{curr_worker_set, worker_set_from_pub_keys}, + test::test_data::{curr_worker_set, domain_separator, messages, worker_set_from_pub_keys}, }; #[test] @@ -138,11 +164,7 @@ mod tests { HexBinary::from_hex("52c65e01d464f6e440ebff7561b09edc1c9ff7754dd8bdaaa0410a952b9824cb") .unwrap(); - let domain_separator: [u8; 32] = - HexBinary::from_hex("3593643a7d7e917a099eef6c52d1420bb4f33eb074b16439556de5984791262b") - .unwrap() - .to_array() - .unwrap(); + let domain_separator = domain_separator(); let new_pub_keys = vec![ "0352a321079b435a4566ac8c92ab18584d8537d563f6c2c0bbbf58246ad047c611", @@ -162,20 +184,7 @@ mod tests { "7c685ecc8a42da4cd9d6de7860b0fddebb4e2e934357500257c1070b1a15be5e27f13b627cf9fa44f59d535af96be0a5ec214d988c48e2b5aaf3ba537d0215bb1b", ].into_iter().map(|sig| HexBinary::from_hex(sig).unwrap()).collect(); - let signers_with_sigs = worker_set - .signers - .values() - .sorted_by(|s1, s2| { - Ord::cmp( - &evm_address(&s1.pub_key).unwrap(), - &evm_address(&s2.pub_key).unwrap(), - ) - }) - .zip(sigs) - .map(|(signer, sig)| { - signer.with_sig(Signature::try_from((signer.pub_key.key_type(), sig)).unwrap()) - }) - .collect(); + let signers_with_sigs = signers_with_sigs(worker_set.signers.values(), sigs); let payload = Payload::WorkerSet(new_worker_set); let payload_hash: Hash = payload_hash_to_sign(&domain_separator, &worker_set, &payload) @@ -184,7 +193,7 @@ mod tests { .try_into() .unwrap(); - let execute_data = encode(&worker_set, signers_with_sigs, &payload_hash, &payload); + let execute_data = encode(&worker_set, signers_with_sigs, &payload_hash, &payload).unwrap(); let data_hash = Keccak256::digest(execute_data.as_slice()); assert_eq!(HexBinary::from(data_hash.as_slice()), expected_data_hash); @@ -226,4 +235,54 @@ mod tests { panic!("Invalid signature type") } } + + #[test] + fn approve_messages_function_data() { + // ApproveMessages function calldata hash generated by axelar-gmp-sdk-solidity unit tests + let expected_data_hash = + HexBinary::from_hex("cf6200f6889b7157af0bfcb2eaaabc03d89b94428dcbe613f5844f4f593c050d") + .unwrap(); + + let domain_separator = domain_separator(); + let worker_set = curr_worker_set(); + + // Generated signatures are already sorted by weight and evm address + let sigs: Vec<_> = vec![ + "6e320a96a33260b488c6c4a2fa007345a4db974bf9d94a9568edf79452ee0e805eedb7c4e67ce16fb5cc0691b04b5caf3b0014e1133d5175a9bc47d917f57e251c", + "fdd7269bbc41946f73ca744a4037fd1e9fcf2d2a93db8cfe2143c2b0ea52bd96300c7f61803cebaff1590bc137ca0503697a502d06a1c4998aaceb77c0a91c6b1c", + "01363790ed71e5070be5d79277350b3300cbba90b1141dbcf49103eaf113178c30947ff9fb293d23860aa33150b883e0852faae0fad1218550a8c730ac9961fc1b", + ].into_iter().map(|sig| HexBinary::from_hex(sig).unwrap()).collect(); + + let signers_with_sigs = signers_with_sigs(worker_set.signers.values(), sigs); + + let payload = Payload::Messages(messages()); + let payload_hash: Hash = payload_hash_to_sign(&domain_separator, &worker_set, &payload) + .unwrap() + .as_slice() + .try_into() + .unwrap(); + + let execute_data = encode(&worker_set, signers_with_sigs, &payload_hash, &payload).unwrap(); + let data_hash = Keccak256::digest(execute_data.as_slice()); + + assert_eq!(HexBinary::from(data_hash.as_slice()), expected_data_hash); + } + + fn signers_with_sigs<'a>( + signers: impl Iterator, + sigs: Vec, + ) -> Vec { + signers + .sorted_by(|s1, s2| { + Ord::cmp( + &evm_address(&s1.pub_key).unwrap(), + &evm_address(&s2.pub_key).unwrap(), + ) + }) + .zip(sigs) + .map(|(signer, sig)| { + signer.with_sig(Signature::try_from((signer.pub_key.key_type(), sig)).unwrap()) + }) + .collect() + } } diff --git a/contracts/multisig-prover/src/encoding/abi2/mod.rs b/contracts/multisig-prover/src/encoding/abi2/mod.rs index f16fecb96..4aa7dec3e 100644 --- a/contracts/multisig-prover/src/encoding/abi2/mod.rs +++ b/contracts/multisig-prover/src/encoding/abi2/mod.rs @@ -152,7 +152,9 @@ mod tests { use crate::{ encoding::abi2::{payload_hash_to_sign, CommandType, Message, WeightedSigners}, payload::Payload, - test::test_data::{curr_worker_set, messages, new_worker_set, worker_set_from_pub_keys}, + test::test_data::{ + curr_worker_set, domain_separator, messages, new_worker_set, worker_set_from_pub_keys, + }, }; #[test] @@ -186,11 +188,7 @@ mod tests { HexBinary::from_hex("fbb9a154bbafd0be9469d7c83bfe5807d916ec7430f5232f29b967240880f327") .unwrap(); - let domain_separator: [u8; 32] = - HexBinary::from_hex("3593643a7d7e917a099eef6c52d1420bb4f33eb074b16439556de5984791262b") - .unwrap() - .to_array() - .unwrap(); + let domain_separator = domain_separator(); let new_pub_keys = vec![ "02de8b0cc10de1becab121cb1254a7b4075866b6e040d5a4cdd38c7ea6c68c7d0a", @@ -254,11 +252,7 @@ mod tests { HexBinary::from_hex("2ab230ae08c9fc5e9110c08061a9dffe928a1093133a6f157316fb9c90bf825c") .unwrap(); - let domain_separator: [u8; 32] = - HexBinary::from_hex("3593643a7d7e917a099eef6c52d1420bb4f33eb074b16439556de5984791262b") - .unwrap() - .to_array() - .unwrap(); + let domain_separator = domain_separator(); let digest = payload_hash_to_sign( &domain_separator, diff --git a/contracts/multisig-prover/src/payload.rs b/contracts/multisig-prover/src/payload.rs index dd39d7f3a..71ab5312d 100644 --- a/contracts/multisig-prover/src/payload.rs +++ b/contracts/multisig-prover/src/payload.rs @@ -67,12 +67,9 @@ impl Payload { let payload_hash = payload.digest(encoder, domain_separator, worker_set)?; match encoder { - Encoder::Abi => Ok(abi2::execute_data::encode( - worker_set, - signers_with_sigs, - &payload_hash, - payload, - )), + Encoder::Abi => { + abi2::execute_data::encode(worker_set, signers_with_sigs, &payload_hash, payload) + } Encoder::Bcs => todo!(), } } diff --git a/contracts/multisig-prover/src/test/test_data.rs b/contracts/multisig-prover/src/test/test_data.rs index d156b3f50..7c745e8d4 100644 --- a/contracts/multisig-prover/src/test/test_data.rs +++ b/contracts/multisig-prover/src/test/test_data.rs @@ -129,6 +129,10 @@ pub fn execute_data() -> HexBinary { HexBinary::from_hex("09c5eabe000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000007600000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000000539000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000101d9a96970a852fe24dad94e05c4c8c5eab33d027cb7d381c2745c390d75e998000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000013617070726f7665436f6e747261637443616c6c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000a4f10f76b86e01b98daf66a3d02a65e14adb07678c3685dc41c2eca11426f8035742fb97ea9f14931152670a5703f18fe8b392f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000967616e616368652d310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307835323434346631383335416463303230383663333743623232363536313630356532453136393962000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000050000000000000000000000004ef5c8d81b6417fa80c320b5fc1d3900506dff540000000000000000000000006c51eec96bf0a8ec799cdd0bbcb4512f8334afe80000000000000000000000007aeb4eebf1e8dcde3016d4e1dca52b4538cf7aaf000000000000000000000000c5b95c99d883c3204cfc2e73669ce3aa7437f4a6000000000000000000000000ffffde829096dfe8b833997e939865ff57422ea90000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000004172b242d7247fc31d14ce82b32f3ea911808f6f600f362150f9904c974315942927c25f9388cecdbbb0b3723164eea92206775870cd28e1ffd8f1cb9655fb3c4a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004186909155a6ba27f173edf15d283da6a0019fb6afe6b223ca68530464813f468f356e70788faf6d1d9ff7bfcfd9021b560d72408bef4c86c66e3a94b9dee0a34a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419b2d986652fdebe67554f1b33ae6161b205ea84e0dacb07ffde0889791bcab2e5be3b8229eae01f2c22805c87f15cb7f9642e9cba951489edcac5d12ace399391b00000000000000000000000000000000000000000000000000000000000000").unwrap() } +pub fn approve_messages_calldata() -> HexBinary { + HexBinary::from_hex("64f1d85a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000a4f10f76b86e01b98daf66a3d02a65e14adb07678c3685dc41c2eca11426f8035742fb97ea9f14931152670a5703f18fe8b392f000000000000000000000000000000000000000000000000000000000000000443078666638323263383838303738353966663232366235386532346632343937346137306630346239343432353031616533386664363635623363363866333833342d3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000967616e616368652d310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a307835323434346631383335416463303230383663333743623232363536313630356532453136393962000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000003010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000004ef5c8d81b6417fa80c320b5fc1d3900506dff5400000000000000000000000000000000000000000000000000000000000000010000000000000000000000006c51eec96bf0a8ec799cdd0bbcb4512f8334afe800000000000000000000000000000000000000000000000000000000000000010000000000000000000000007aeb4eebf1e8dcde3016d4e1dca52b4538cf7aaf0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c5b95c99d883c3204cfc2e73669ce3aa7437f4a60000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ffffde829096dfe8b833997e939865ff57422ea900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000004172b242d7247fc31d14ce82b32f3ea911808f6f600f362150f9904c974315942927c25f9388cecdbbb0b3723164eea92206775870cd28e1ffd8f1cb9655fb3c4a1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004186909155a6ba27f173edf15d283da6a0019fb6afe6b223ca68530464813f468f356e70788faf6d1d9ff7bfcfd9021b560d72408bef4c86c66e3a94b9dee0a34a1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419b2d986652fdebe67554f1b33ae6161b205ea84e0dacb07ffde0889791bcab2e5be3b8229eae01f2c22805c87f15cb7f9642e9cba951489edcac5d12ace399391b00000000000000000000000000000000000000000000000000000000000000").unwrap() +} + pub fn threshold() -> MajorityThreshold { let numerator: nonempty::Uint64 = Uint64::from(2u8).try_into().unwrap(); let denominator: nonempty::Uint64 = Uint64::from(3u8).try_into().unwrap(); @@ -235,3 +239,11 @@ pub fn worker_set_from_pub_keys(pub_keys: Vec<&str>) -> WorkerSet { .collect(); WorkerSet::new(participants, Uint256::from_u128(3), 0) } + +// Domain separator matches axelar-gmp-sdk-solidity repo test data +pub fn domain_separator() -> [u8; 32] { + HexBinary::from_hex("3593643a7d7e917a099eef6c52d1420bb4f33eb074b16439556de5984791262b") + .unwrap() + .to_array() + .unwrap() +} diff --git a/integration-tests/tests/message_routing.rs b/integration-tests/tests/message_routing.rs index 22bd9e037..712db966f 100644 --- a/integration-tests/tests/message_routing.rs +++ b/integration-tests/tests/message_routing.rs @@ -9,8 +9,6 @@ pub mod test_utils; /// Tests that a single message can be routed fully through the protocol. Submits a message to the /// gateway, votes on the poll, routes the message to the outgoing gateway, triggers signing at the prover /// and signs via multisig. Also tests that rewards are distributed as expected for voting and signing. -/// TODO: remove ignore flag -#[ignore = "verify messages is temporarily broken during the multisig prover amplifier gateway migration"] #[test] fn single_message_can_be_verified_and_routed_and_proven_and_rewards_are_distributed() { let test_utils::TestCase {