feat: support `IWeightedMultisigIsm` in relayer (#4360)
### Description <!-- What's included in this PR? --> ### Drive-by changes <!-- Are there any minor or drive-by changes also included? --> ### Related issues - fixes https://github.com/hyperlane-xyz/issues/issues/1345 ### Backward compatibility <!-- Are these changes backward compatible? Are there any infrastructure implications, e.g. changes that would prohibit deploying older commits using this infra tooling? Yes/No --> ### Testing <!-- What kind of testing have these changes undergone? None/Manual/Unit Tests -->pull/4399/head
parent
707db4a279
commit
24c8188e55
@ -1,8 +1,13 @@ |
||||
mod base; |
||||
mod merkle_root_multisig; |
||||
mod message_id_multisig; |
||||
mod weighted; |
||||
|
||||
pub use base::{MetadataToken, MultisigIsmMetadataBuilder, MultisigMetadata}; |
||||
|
||||
pub use merkle_root_multisig::MerkleRootMultisigMetadataBuilder; |
||||
pub use message_id_multisig::MessageIdMultisigMetadataBuilder; |
||||
|
||||
pub use weighted::{ |
||||
WeightedMerkleRootMultisigMetadataBuilder, WeightedMessageIdMultisigMetadataBuilder, |
||||
}; |
||||
|
@ -0,0 +1,108 @@ |
||||
use super::base::MultisigIsmMetadataBuilder; |
||||
|
||||
use crate::msg::metadata::{ |
||||
multisig::{ |
||||
MerkleRootMultisigMetadataBuilder, MessageIdMultisigMetadataBuilder, MetadataToken, |
||||
MultisigMetadata, |
||||
}, |
||||
MessageMetadataBuilder, |
||||
}; |
||||
use async_trait::async_trait; |
||||
use derive_more::{AsRef, Deref}; |
||||
use derive_new::new; |
||||
use eyre::{Context, Result}; |
||||
use hyperlane_base::{MultisigCheckpointSyncer, ValidatorWithWeight, Weight}; |
||||
use hyperlane_core::{HyperlaneMessage, H256}; |
||||
|
||||
#[derive(Debug, Clone, Deref, new, AsRef)] |
||||
pub struct WeightedMerkleRootMultisigMetadataBuilder(MessageMetadataBuilder); |
||||
|
||||
#[async_trait] |
||||
impl MultisigIsmMetadataBuilder for WeightedMerkleRootMultisigMetadataBuilder { |
||||
async fn ism_validator_requirements( |
||||
&self, |
||||
ism_address: H256, |
||||
message: &HyperlaneMessage, |
||||
) -> Result<(Vec<ValidatorWithWeight>, Weight)> { |
||||
const CTX: &str = "When fetching WeightedMultisigIsm metadata"; |
||||
let weighted_multisig_ism = self |
||||
.as_ref() |
||||
.build_weighted_multisig_ism(ism_address) |
||||
.await |
||||
.context(CTX)?; |
||||
|
||||
let (validators, threshold) = weighted_multisig_ism |
||||
.validators_and_threshold_weight(message) |
||||
.await |
||||
.context(CTX)?; |
||||
|
||||
let validators: Vec<ValidatorWithWeight> = validators |
||||
.into_iter() |
||||
.map(|(validator, weight)| ValidatorWithWeight::new(validator, weight)) |
||||
.collect(); |
||||
|
||||
Ok((validators, threshold)) |
||||
} |
||||
|
||||
fn token_layout(&self) -> Vec<MetadataToken> { |
||||
MerkleRootMultisigMetadataBuilder::new(self.0.clone()).token_layout() |
||||
} |
||||
|
||||
async fn fetch_metadata( |
||||
&self, |
||||
validators: &[ValidatorWithWeight], |
||||
threshold_weight: Weight, |
||||
message: &HyperlaneMessage, |
||||
checkpoint_syncer: &MultisigCheckpointSyncer, |
||||
) -> Result<Option<MultisigMetadata>> { |
||||
MerkleRootMultisigMetadataBuilder::new(self.0.clone()) |
||||
.fetch_metadata(validators, threshold_weight, message, checkpoint_syncer) |
||||
.await |
||||
} |
||||
} |
||||
|
||||
#[derive(Debug, Clone, Deref, new, AsRef)] |
||||
pub struct WeightedMessageIdMultisigMetadataBuilder(MessageMetadataBuilder); |
||||
|
||||
#[async_trait] |
||||
impl MultisigIsmMetadataBuilder for WeightedMessageIdMultisigMetadataBuilder { |
||||
async fn ism_validator_requirements( |
||||
&self, |
||||
ism_address: H256, |
||||
message: &HyperlaneMessage, |
||||
) -> Result<(Vec<ValidatorWithWeight>, u64)> { |
||||
const CTX: &str = "When fetching WeightedMultisigIsm metadata"; |
||||
let weighted_multisig_ism = self |
||||
.as_ref() |
||||
.build_weighted_multisig_ism(ism_address) |
||||
.await |
||||
.context(CTX)?; |
||||
|
||||
let (validators, threshold) = weighted_multisig_ism |
||||
.validators_and_threshold_weight(message) |
||||
.await |
||||
.context(CTX)?; |
||||
|
||||
let validators: Vec<ValidatorWithWeight> = validators |
||||
.into_iter() |
||||
.map(|(validator, weight)| ValidatorWithWeight::new(validator, weight)) |
||||
.collect(); |
||||
|
||||
Ok((validators, threshold)) |
||||
} |
||||
fn token_layout(&self) -> Vec<MetadataToken> { |
||||
MessageIdMultisigMetadataBuilder::new(self.0.clone()).token_layout() |
||||
} |
||||
|
||||
async fn fetch_metadata( |
||||
&self, |
||||
validators: &[ValidatorWithWeight], |
||||
threshold_weight: Weight, |
||||
message: &HyperlaneMessage, |
||||
checkpoint_syncer: &MultisigCheckpointSyncer, |
||||
) -> Result<Option<MultisigMetadata>> { |
||||
MessageIdMultisigMetadataBuilder::new(self.0.clone()) |
||||
.fetch_metadata(validators, threshold_weight, message, checkpoint_syncer) |
||||
.await |
||||
} |
||||
} |
@ -0,0 +1,75 @@ |
||||
[ |
||||
{ |
||||
"type": "function", |
||||
"name": "moduleType", |
||||
"inputs": [], |
||||
"outputs": [ |
||||
{ |
||||
"name": "", |
||||
"type": "uint8", |
||||
"internalType": "uint8" |
||||
} |
||||
], |
||||
"stateMutability": "view" |
||||
}, |
||||
{ |
||||
"type": "function", |
||||
"name": "validatorsAndThresholdWeight", |
||||
"inputs": [ |
||||
{ |
||||
"name": "_message", |
||||
"type": "bytes", |
||||
"internalType": "bytes" |
||||
} |
||||
], |
||||
"outputs": [ |
||||
{ |
||||
"name": "validators", |
||||
"type": "tuple[]", |
||||
"internalType": "struct IStaticWeightedMultisigIsm.ValidatorInfo[]", |
||||
"components": [ |
||||
{ |
||||
"name": "signingAddress", |
||||
"type": "address", |
||||
"internalType": "address" |
||||
}, |
||||
{ |
||||
"name": "weight", |
||||
"type": "uint96", |
||||
"internalType": "uint96" |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"name": "thresholdWeight", |
||||
"type": "uint96", |
||||
"internalType": "uint96" |
||||
} |
||||
], |
||||
"stateMutability": "view" |
||||
}, |
||||
{ |
||||
"type": "function", |
||||
"name": "verify", |
||||
"inputs": [ |
||||
{ |
||||
"name": "_metadata", |
||||
"type": "bytes", |
||||
"internalType": "bytes" |
||||
}, |
||||
{ |
||||
"name": "_message", |
||||
"type": "bytes", |
||||
"internalType": "bytes" |
||||
} |
||||
], |
||||
"outputs": [ |
||||
{ |
||||
"name": "", |
||||
"type": "bool", |
||||
"internalType": "bool" |
||||
} |
||||
], |
||||
"stateMutability": "nonpayable" |
||||
} |
||||
] |
@ -0,0 +1,123 @@ |
||||
use async_trait::async_trait; |
||||
use ethers::providers::Middleware; |
||||
use hyperlane_core::{ |
||||
ChainResult, ContractLocator, HyperlaneAbi, HyperlaneChain, HyperlaneContract, HyperlaneDomain, |
||||
HyperlaneMessage, HyperlaneProvider, RawHyperlaneMessage, WeightedMultisigIsm, H256, |
||||
}; |
||||
use std::collections::HashMap; |
||||
use std::sync::Arc; |
||||
use tracing::instrument; |
||||
|
||||
use crate::{BuildableWithProvider, ConnectionConf, EthereumProvider}; |
||||
|
||||
use crate::interfaces::i_static_weighted_multisig_ism::{ |
||||
IStaticWeightedMultisigIsm as EthereumWeightedMultisigIsmInternal, |
||||
ISTATICWEIGHTEDMULTISIGISM_ABI, |
||||
}; |
||||
|
||||
/// Builder for WeightedMultisigIsm contracts
|
||||
pub struct WeighedMultisigIsmBuilder {} |
||||
|
||||
#[async_trait] |
||||
impl BuildableWithProvider for WeighedMultisigIsmBuilder { |
||||
type Output = Box<dyn WeightedMultisigIsm>; |
||||
const NEEDS_SIGNER: bool = false; |
||||
|
||||
async fn build_with_provider<M: Middleware + 'static>( |
||||
&self, |
||||
provider: M, |
||||
_conn: &ConnectionConf, |
||||
locator: &ContractLocator, |
||||
) -> Self::Output { |
||||
Box::new(EthereumWeightedMultisigIsm::new( |
||||
Arc::new(provider), |
||||
locator, |
||||
)) |
||||
} |
||||
} |
||||
|
||||
/// A reference to an WeightedMultisigIsm contract on some Ethereum chain
|
||||
#[derive(Debug)] |
||||
pub struct EthereumWeightedMultisigIsm<M> |
||||
where |
||||
M: Middleware, |
||||
{ |
||||
contract: Arc<EthereumWeightedMultisigIsmInternal<M>>, |
||||
domain: HyperlaneDomain, |
||||
} |
||||
|
||||
impl<M> EthereumWeightedMultisigIsm<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
/// Create a reference to a mailbox at a specific Ethereum address on some
|
||||
/// chain
|
||||
pub fn new(provider: Arc<M>, locator: &ContractLocator) -> Self { |
||||
Self { |
||||
contract: Arc::new(EthereumWeightedMultisigIsmInternal::new( |
||||
locator.address, |
||||
provider, |
||||
)), |
||||
domain: locator.domain.clone(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl<M> HyperlaneChain for EthereumWeightedMultisigIsm<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
fn domain(&self) -> &HyperlaneDomain { |
||||
&self.domain |
||||
} |
||||
|
||||
fn provider(&self) -> Box<dyn HyperlaneProvider> { |
||||
Box::new(EthereumProvider::new( |
||||
self.contract.client(), |
||||
self.domain.clone(), |
||||
)) |
||||
} |
||||
} |
||||
|
||||
impl<M> HyperlaneContract for EthereumWeightedMultisigIsm<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
fn address(&self) -> H256 { |
||||
self.contract.address().into() |
||||
} |
||||
} |
||||
|
||||
#[async_trait] |
||||
impl<M> WeightedMultisigIsm for EthereumWeightedMultisigIsm<M> |
||||
where |
||||
M: Middleware + 'static, |
||||
{ |
||||
#[instrument(err)] |
||||
async fn validators_and_threshold_weight( |
||||
&self, |
||||
message: &HyperlaneMessage, |
||||
) -> ChainResult<(Vec<(H256, u64)>, u64)> { |
||||
let (validator_addresses, threshold) = self |
||||
.contract |
||||
.validators_and_threshold_weight(RawHyperlaneMessage::from(message).to_vec().into()) |
||||
.call() |
||||
.await?; |
||||
let validators: Vec<(H256, u64)> = validator_addresses |
||||
.iter() |
||||
.map(|x| (H256::from(x.signing_address), x.weight as u64)) |
||||
.collect(); |
||||
Ok((validators, threshold as u64)) |
||||
} |
||||
} |
||||
|
||||
/// ABI for WeightedMultisigIsm contracts
|
||||
pub struct EthereumWeightedMultisigIsmAbi; |
||||
|
||||
impl HyperlaneAbi for EthereumWeightedMultisigIsmAbi { |
||||
const SELECTOR_SIZE_BYTES: usize = 4; |
||||
|
||||
fn fn_map() -> HashMap<Vec<u8>, &'static str> { |
||||
crate::extract_fn_map(&ISTATICWEIGHTEDMULTISIGISM_ABI) |
||||
} |
||||
} |
Loading…
Reference in new issue