Skip to content

Commit bcd775a

Browse files
committed
feat: add factory for aggregation[messageId,merkleRoot]
1 parent 78b24f2 commit bcd775a

2 files changed

Lines changed: 135 additions & 53 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
pragma solidity >=0.8.0;
3+
4+
// ============ Internal Imports ============
5+
import {StaticAggregationIsmFactory} from "./StaticAggregationIsmFactory.sol";
6+
import {StaticMessageIdMultisigIsmFactory} from "../multisig/StaticMultisigIsm.sol";
7+
import {StaticMerkleRootMultisigIsmFactory} from "../multisig/StaticMultisigIsm.sol";
8+
import {PackageVersioned} from "../../PackageVersioned.sol";
9+
10+
/**
11+
* @title StaticMultisigAggregationIsmFactory
12+
* @notice Factory that deploys an AggregationIsm containing both MessageIdMultisigIsm
13+
* and MerkleRootMultisigIsm with a threshold of 1 (either signature type accepted).
14+
*
15+
* This is the standard multisig ISM pattern used in Hyperlane core deployments,
16+
* packaged as a single factory call for convenience.
17+
*
18+
* @dev All deployed contracts use CREATE2 for deterministic addresses. Calling deploy()
19+
* with the same validators/threshold will return the existing contract addresses.
20+
*
21+
* @dev IMPORTANT: Validator addresses MUST be sorted in ascending order.
22+
* The underlying multisig ISM factories use CREATE2 with validators as part of the salt,
23+
* so different orderings produce different contract addresses.
24+
*/
25+
contract StaticMultisigAggregationIsmFactory is PackageVersioned {
26+
// ============ Immutables ============
27+
StaticAggregationIsmFactory public immutable aggregationIsmFactory;
28+
StaticMessageIdMultisigIsmFactory
29+
public immutable messageIdMultisigIsmFactory;
30+
StaticMerkleRootMultisigIsmFactory
31+
public immutable merkleRootMultisigIsmFactory;
32+
33+
// ============ Events ============
34+
event MultisigAggregationIsmDeployed(
35+
address indexed aggregationIsm,
36+
address messageIdMultisigIsm,
37+
address merkleRootMultisigIsm,
38+
address[] validators,
39+
uint8 threshold
40+
);
41+
42+
// ============ Constructor ============
43+
constructor(
44+
StaticAggregationIsmFactory _aggregationIsmFactory,
45+
StaticMessageIdMultisigIsmFactory _messageIdMultisigIsmFactory,
46+
StaticMerkleRootMultisigIsmFactory _merkleRootMultisigIsmFactory
47+
) {
48+
aggregationIsmFactory = _aggregationIsmFactory;
49+
messageIdMultisigIsmFactory = _messageIdMultisigIsmFactory;
50+
merkleRootMultisigIsmFactory = _merkleRootMultisigIsmFactory;
51+
}
52+
53+
// ============ External Functions ============
54+
55+
/**
56+
* @notice Deploys an AggregationIsm containing MessageIdMultisigIsm and MerkleRootMultisigIsm
57+
* @dev Validators MUST be sorted in ascending order for deterministic addresses.
58+
* @param _validators Array of validator addresses (MUST be sorted ascending)
59+
* @param _threshold Number of validator signatures required
60+
* @return aggregationIsm The deployed AggregationIsm address
61+
*/
62+
function deploy(
63+
address[] calldata _validators,
64+
uint8 _threshold
65+
) external returns (address aggregationIsm) {
66+
// Deploy MessageIdMultisigIsm (reuses existing if same validators/threshold)
67+
address _messageIdIsm = messageIdMultisigIsmFactory.deploy(
68+
_validators,
69+
_threshold
70+
);
71+
72+
// Deploy MerkleRootMultisigIsm (reuses existing if same validators/threshold)
73+
address _merkleRootIsm = merkleRootMultisigIsmFactory.deploy(
74+
_validators,
75+
_threshold
76+
);
77+
78+
// Deploy AggregationIsm with threshold 1 (either MessageId OR MerkleRoot)
79+
address[] memory _modules = new address[](2);
80+
_modules[0] = _messageIdIsm;
81+
_modules[1] = _merkleRootIsm;
82+
aggregationIsm = aggregationIsmFactory.deploy(_modules, 1);
83+
84+
emit MultisigAggregationIsmDeployed(
85+
aggregationIsm,
86+
_messageIdIsm,
87+
_merkleRootIsm,
88+
_validators,
89+
_threshold
90+
);
91+
}
92+
93+
/**
94+
* @notice Computes the AggregationIsm address that would be deployed for given parameters
95+
* @dev Useful for predicting addresses before deployment or checking if already deployed.
96+
* @param _validators Array of validator addresses (MUST be sorted ascending)
97+
* @param _threshold Number of validator signatures required
98+
* @return aggregationIsm The AggregationIsm address
99+
*/
100+
function getAddress(
101+
address[] calldata _validators,
102+
uint8 _threshold
103+
) external view returns (address aggregationIsm) {
104+
// Compute MessageIdMultisigIsm address
105+
address _messageIdIsm = messageIdMultisigIsmFactory.getAddress(
106+
_validators,
107+
_threshold
108+
);
109+
110+
// Compute MerkleRootMultisigIsm address
111+
address _merkleRootIsm = merkleRootMultisigIsmFactory.getAddress(
112+
_validators,
113+
_threshold
114+
);
115+
116+
// Compute AggregationIsm address
117+
address[] memory _modules = new address[](2);
118+
_modules[0] = _messageIdIsm;
119+
_modules[1] = _merkleRootIsm;
120+
aggregationIsm = aggregationIsmFactory.getAddress(_modules, 1);
121+
}
122+
}

solidity/contracts/isms/routing/RoutingMultisigIsmFactory.sol

Lines changed: 13 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,29 @@ pragma solidity >=0.8.0;
44
// ============ Internal Imports ============
55
import {DomainRoutingIsm} from "./DomainRoutingIsm.sol";
66
import {DomainRoutingIsmFactory} from "./DomainRoutingIsmFactory.sol";
7-
import {StaticAggregationIsmFactory} from "../aggregation/StaticAggregationIsmFactory.sol";
8-
import {StaticMessageIdMultisigIsmFactory} from "../multisig/StaticMultisigIsm.sol";
9-
import {StaticMerkleRootMultisigIsmFactory} from "../multisig/StaticMultisigIsm.sol";
7+
import {StaticMultisigAggregationIsmFactory} from "../aggregation/StaticMultisigAggregationIsmFactory.sol";
108
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";
119
import {PackageVersioned} from "../../PackageVersioned.sol";
1210

1311
/**
1412
* @title RoutingMultisigIsmFactory
15-
* @notice Factory that deploys the complete routing[agg(messageId, merkleRoot)] ISM structure
16-
* using existing audited ISM contracts. This factory simplifies deployment by:
17-
* 1. Deploying MessageId and MerkleRoot multisig ISMs for each domain
18-
* 2. Deploying an AggregationIsm (threshold 1) for each domain containing both multisig ISMs
19-
* 3. Deploying a DomainRoutingIsm that routes messages to the appropriate AggregationIsm
13+
* @notice Factory that deploys the complete routing[agg(messageId, merkleRoot)] ISM structure.
2014
*
21-
* This creates the same structure as the current core deployments but as a single factory call,
22-
* making ISM reads and updates much simpler (similar to Solana's approach).
15+
* This factory orchestrates:
16+
* 1. Deploying an AggregationIsm (containing MessageId + MerkleRoot multisig ISMs) for each domain
17+
* 2. Deploying a DomainRoutingIsm that routes messages to the appropriate AggregationIsm
2318
*
24-
* @dev This factory creates a fresh ISM tree on each deploy(). To update domains, deploy a new
25-
* routing ISM rather than modifying an existing one. The underlying DomainRoutingIsm supports
26-
* owner-controlled set() for adding domains, but this factory doesn't expose that pattern.
19+
* For incremental domain additions, use StaticMultisigAggregationIsmFactory directly to deploy
20+
* new aggregation ISMs, then call routingIsm.set(domain, newAggIsm) on the existing routing ISM.
2721
*
2822
* @dev Gas considerations: Deploying for many domains in one transaction may hit block gas limits.
2923
* For large deployments (>10 domains), consider batching or deploying in multiple transactions.
3024
*/
3125
contract RoutingMultisigIsmFactory is PackageVersioned {
3226
// ============ Immutables ============
3327
DomainRoutingIsmFactory public immutable routingIsmFactory;
34-
StaticAggregationIsmFactory public immutable aggregationIsmFactory;
35-
StaticMessageIdMultisigIsmFactory
36-
public immutable messageIdMultisigIsmFactory;
37-
StaticMerkleRootMultisigIsmFactory
38-
public immutable merkleRootMultisigIsmFactory;
28+
StaticMultisigAggregationIsmFactory
29+
public immutable multisigAggregationIsmFactory;
3930

4031
// ============ Events ============
4132
event RoutingMultisigIsmDeployed(
@@ -47,14 +38,10 @@ contract RoutingMultisigIsmFactory is PackageVersioned {
4738
// ============ Constructor ============
4839
constructor(
4940
DomainRoutingIsmFactory _routingIsmFactory,
50-
StaticAggregationIsmFactory _aggregationIsmFactory,
51-
StaticMessageIdMultisigIsmFactory _messageIdMultisigIsmFactory,
52-
StaticMerkleRootMultisigIsmFactory _merkleRootMultisigIsmFactory
41+
StaticMultisigAggregationIsmFactory _multisigAggregationIsmFactory
5342
) {
5443
routingIsmFactory = _routingIsmFactory;
55-
aggregationIsmFactory = _aggregationIsmFactory;
56-
messageIdMultisigIsmFactory = _messageIdMultisigIsmFactory;
57-
merkleRootMultisigIsmFactory = _merkleRootMultisigIsmFactory;
44+
multisigAggregationIsmFactory = _multisigAggregationIsmFactory;
5845
}
5946

6047
// ============ External Functions ============
@@ -99,23 +86,10 @@ contract RoutingMultisigIsmFactory is PackageVersioned {
9986

10087
// Deploy AggregationIsm for each domain
10188
for (uint256 i = 0; i < _domainCount; ++i) {
102-
// Deploy MessageIdMultisigIsm for this domain
103-
address _messageIdIsm = messageIdMultisigIsmFactory.deploy(
89+
address _aggregationIsm = multisigAggregationIsmFactory.deploy(
10490
_validators[i],
10591
_thresholds[i]
10692
);
107-
108-
// Deploy MerkleRootMultisigIsm for this domain
109-
address _merkleRootIsm = merkleRootMultisigIsmFactory.deploy(
110-
_validators[i],
111-
_thresholds[i]
112-
);
113-
114-
// Deploy AggregationIsm with threshold 1 (either MessageId OR MerkleRoot)
115-
address[] memory _modules = new address[](2);
116-
_modules[0] = _messageIdIsm;
117-
_modules[1] = _merkleRootIsm;
118-
address _aggregationIsm = aggregationIsmFactory.deploy(_modules, 1);
11993
_aggregationIsms[i] = IInterchainSecurityModule(_aggregationIsm);
12094
aggregationIsmAddresses[i] = _aggregationIsm;
12195
}
@@ -160,25 +134,11 @@ contract RoutingMultisigIsmFactory is PackageVersioned {
160134
uint256 _domainCount = _domains.length;
161135
aggregationIsms = new address[](_domainCount);
162136

163-
// Compute AggregationIsm addresses for each domain
164137
for (uint256 i = 0; i < _domainCount; ++i) {
165-
// Compute MessageIdMultisigIsm address
166-
address _messageIdIsm = messageIdMultisigIsmFactory.getAddress(
138+
aggregationIsms[i] = multisigAggregationIsmFactory.getAddress(
167139
_validators[i],
168140
_thresholds[i]
169141
);
170-
171-
// Compute MerkleRootMultisigIsm address
172-
address _merkleRootIsm = merkleRootMultisigIsmFactory.getAddress(
173-
_validators[i],
174-
_thresholds[i]
175-
);
176-
177-
// Compute AggregationIsm address
178-
address[] memory _modules = new address[](2);
179-
_modules[0] = _messageIdIsm;
180-
_modules[1] = _merkleRootIsm;
181-
aggregationIsms[i] = aggregationIsmFactory.getAddress(_modules, 1);
182142
}
183143
}
184144
}

0 commit comments

Comments
 (0)