@@ -7,10 +7,11 @@ import {
77import { IAccessControl } from "openzeppelin-contracts/contracts/access/IAccessControl.sol " ;
88import { TimelockController } from "openzeppelin-contracts/contracts/governance/TimelockController.sol " ;
99
10+ import { DefaultHook } from "@hyperlane-xyz/core/contracts/hooks/DefaultHook.sol " ;
1011import { PausableHook } from "@hyperlane-xyz/core/contracts/hooks/PausableHook.sol " ;
1112import { StaticAggregationHook } from "@hyperlane-xyz/core/contracts/hooks/aggregation/StaticAggregationHook.sol " ;
12- import { IMailbox } from "@hyperlane-xyz/core/contracts/interfaces/IMailbox.sol " ;
1313import { PausableIsm } from "@hyperlane-xyz/core/contracts/isms/PausableIsm.sol " ;
14+ import { DefaultFallbackRoutingIsm } from "@hyperlane-xyz/core/contracts/isms/routing/DefaultFallbackRoutingIsm.sol " ;
1415import { HypERC20Collateral } from "@hyperlane-xyz/core/contracts/token/HypERC20Collateral.sol " ;
1516import { HypXERC20 } from "@hyperlane-xyz/core/contracts/token/extensions/HypXERC20.sol " ;
1617
@@ -19,55 +20,70 @@ import { BaseScript } from "./Base.s.sol";
1920/// @title HypEXA
2021/// @notice Deploys and maintains the Hyperlane HypXERC20 router for EXA.
2122contract HypEXA is BaseScript {
22- function deployRouter (address token , uint32 [] calldata remoteDomains ) external returns (HypXERC20 router ) {
23+ function deployRouter (uint32 [] calldata remoteDomains ) external returns (HypXERC20 router ) {
2324 address admin = acct ("admin " );
25+ address exa = protocol ("EXA " , true , getChain ("optimism " ).chainId);
2426 router = HypXERC20 (CREATE3_FACTORY.getDeployed (admin, keccak256 (abi.encode ("HypEXA " ))));
2527 if (address (router).code.length != 0 ) return router;
28+
29+ uint32 [] memory domains = remoteDomains;
30+ if (domains.length == 0 ) {
31+ domains = new uint32 [](1 );
32+ if (block .chainid == getChain ("optimism " ).chainId) domains[0 ] = uint32 (getChain ("base " ).chainId);
33+ else if (block .chainid == getChain ("base " ).chainId) domains[0 ] = uint32 (getChain ("optimism " ).chainId);
34+ else revert UnsupportedChain (block .chainid );
35+ }
36+
2637 vm.startBroadcast (admin);
2738
2839 (address hook , address ism ) = _deployAggregations (
2940 _deployPausableHook (acct ("exactly " )),
3041 _deployPausableHook (acct ("pauser " )),
42+ _deployDefaultHook (),
3143 _deployPausableIsm (acct ("exactly " )),
32- _deployPausableIsm (acct ("pauser " ))
44+ _deployPausableIsm (acct ("pauser " )),
45+ _deployDefaultIsm ()
3346 );
3447
48+ address impl = CREATE3_FACTORY.getDeployed (admin, keccak256 (abi.encode ("HypEXAImpl " )));
49+ if (impl.code.length == 0 ) {
50+ impl = CREATE3_FACTORY.deploy (
51+ keccak256 (abi.encode ("HypEXAImpl " )),
52+ abi.encodePacked (type (HypXERC20).creationCode, abi.encode (exa, 1 , 1 , acct ("hyperlaneMailbox " )))
53+ );
54+ }
55+
3556 router = HypXERC20 (
3657 CREATE3_FACTORY.deploy (
3758 keccak256 (abi.encode ("HypEXA " )),
3859 abi.encodePacked (
3960 type (TransparentUpgradeableProxy).creationCode,
40- abi.encode (
41- address (new HypXERC20 (token, 1 , 1 , acct ("hyperlaneMailbox " ))),
42- protocol ("ProxyAdmin " ),
43- abi.encodeCall (HypERC20Collateral.initialize, (hook, ism, admin))
44- )
61+ abi.encode (impl, protocol ("ProxyAdmin " ), abi.encodeCall (HypERC20Collateral.initialize, (hook, ism, admin)))
4562 )
4663 )
4764 );
4865
49- if (remoteDomains.length > 0 ) {
50- bytes32 [] memory addresses = new bytes32 [](remoteDomains.length );
51- bytes32 remote = bytes32 (uint256 (uint160 (address (router))));
52- for (uint256 i = 0 ; i < remoteDomains.length ; ++ i) {
53- addresses[i] = remote;
54- }
55- router.enrollRemoteRouters (remoteDomains, addresses);
66+ bytes32 [] memory addresses = new bytes32 [](domains.length );
67+ bytes32 remote = bytes32 (uint256 (uint160 (address (router))));
68+ for (uint256 i = 0 ; i < domains.length ; ++ i) {
69+ addresses[i] = remote;
5670 }
71+ router.enrollRemoteRouters (domains, addresses);
5772
5873 router.transferOwnership (acct ("exactly " ));
5974 vm.stopBroadcast ();
6075 }
6176
62- function proposeBridgeRole (address token , bytes32 salt ) external {
77+ function proposeBridgeRole (bytes32 salt ) external {
6378 address router = CREATE3_FACTORY.getDeployed (acct ("admin " ), keccak256 (abi.encode ("HypEXA " )));
6479 if (router.code.length == 0 ) revert RouterNotDeployed ();
65- if (IAccessControl (token).hasRole (keccak256 ("BRIDGE_ROLE " ), router)) revert AlreadyGranted ();
80+ address exa = protocol ("EXA " , true , getChain ("optimism " ).chainId);
81+ if (IAccessControl (exa).hasRole (keccak256 ("BRIDGE_ROLE " ), router)) revert AlreadyGranted ();
6682 TimelockController timelock = TimelockController (payable (protocol ("TimelockController " )));
6783 uint256 delay = timelock.getMinDelay ();
6884 vm.broadcast (acct ("deployer " ));
6985 timelock.schedule (
70- token , 0 , abi.encodeCall (IAccessControl.grantRole, (keccak256 ("BRIDGE_ROLE " ), router)), bytes32 (0 ), salt, delay
86+ exa , 0 , abi.encodeCall (IAccessControl.grantRole, (keccak256 ("BRIDGE_ROLE " ), router)), bytes32 (0 ), salt, delay
7187 );
7288 }
7389
@@ -83,59 +99,88 @@ contract HypEXA is BaseScript {
8399 _expectOwner (hooks[0 ], acct ("exactly " ));
84100 _expectOwner (modules[0 ], acct ("exactly " ));
85101 (hook, ism) = _deployAggregations (
86- hooks[0 ], _deployPausableHook (acct ("pauser " )), modules[0 ], _deployPausableIsm (acct ("pauser " ))
102+ hooks[0 ],
103+ _deployPausableHook (acct ("pauser " )),
104+ hooks[2 ],
105+ modules[0 ],
106+ _deployPausableIsm (acct ("pauser " )),
107+ modules[2 ]
87108 );
88109 HypXERC20 (router).setHook (hook);
89110 HypXERC20 (router).setInterchainSecurityModule (ism);
90111
91112 vm.stopBroadcast ();
92113 }
93114
94- /// @notice Refreshes router hook and ism with new defaults from the Mailbox.
95- function refreshDefaults () external returns (address hook , address ism ) {
96- address router = CREATE3_FACTORY.getDeployed (acct ("admin " ), keccak256 (abi.encode ("HypEXA " )));
97- if (router.code.length == 0 ) revert RouterNotDeployed ();
98- vm.startBroadcast (acct ("exactly " ));
99-
100- address [] memory hooks = StaticAggregationHook (address (HypXERC20 (router).hook ())).hooks ("" );
101- (address [] memory modules ,) =
102- IStaticAggregationIsm (address (HypXERC20 (router).interchainSecurityModule ())).modulesAndThreshold ("" );
103- _expectOwner (hooks[0 ], acct ("exactly " ));
104- _expectOwner (hooks[1 ], acct ("pauser " ));
105- _expectOwner (modules[0 ], acct ("exactly " ));
106- _expectOwner (modules[1 ], acct ("pauser " ));
107- (hook, ism) = _deployAggregations (hooks[0 ], hooks[1 ], modules[0 ], modules[1 ]);
108- HypXERC20 (router).setHook (hook);
109- HypXERC20 (router).setInterchainSecurityModule (ism);
110-
111- vm.stopBroadcast ();
112- }
113-
114- function _deployAggregations (address exactlyHook , address pauserHook , address exactlyIsm , address pauserIsm )
115- internal
116- returns (address aggregationHook , address aggregationIsm )
117- {
118- address mailbox = acct ("hyperlaneMailbox " );
115+ function _deployAggregations (
116+ address exactlyHook ,
117+ address pauserHook ,
118+ address defaultHook ,
119+ address exactlyIsm ,
120+ address pauserIsm ,
121+ address defaultIsm
122+ ) internal returns (address aggregationHook , address aggregationIsm ) {
119123 address [] memory hooks = new address [](3 );
120124 hooks[0 ] = exactlyHook;
121125 hooks[1 ] = pauserHook;
122- hooks[2 ] = address ( IMailbox (mailbox). defaultHook ()) ;
126+ hooks[2 ] = defaultHook;
123127 aggregationHook = IStaticAggregationHookFactory (acct ("hyperlaneAggregationHookFactory " )).deploy (hooks);
124128
125129 address [] memory isms = new address [](3 );
126130 isms[0 ] = exactlyIsm;
127131 isms[1 ] = pauserIsm;
128- isms[2 ] = address ( IMailbox (mailbox). defaultIsm ()) ;
132+ isms[2 ] = defaultIsm;
129133 aggregationIsm = IStaticAggregationIsmFactory (acct ("hyperlaneAggregationIsmFactory " )).deploy (isms, 3 );
130134 }
131135
136+ function _deployDefaultHook () internal returns (address hook ) {
137+ address admin = acct ("admin " );
138+ hook = CREATE3_FACTORY.getDeployed (admin, keccak256 (abi.encode ("HypEXADefaultHook " )));
139+ if (hook.code.length == 0 ) {
140+ hook = CREATE3_FACTORY.deploy (
141+ keccak256 (abi.encode ("HypEXADefaultHook " )),
142+ abi.encodePacked (type (DefaultHook).creationCode, abi.encode (acct ("hyperlaneMailbox " )))
143+ );
144+ }
145+ }
146+
147+ function _deployDefaultIsm () internal returns (address ism ) {
148+ address admin = acct ("admin " );
149+ address impl = CREATE3_FACTORY.getDeployed (admin, keccak256 (abi.encode ("HypEXADefaultIsmImpl " )));
150+ if (impl.code.length == 0 ) {
151+ impl = CREATE3_FACTORY.deploy (
152+ keccak256 (abi.encode ("HypEXADefaultIsmImpl " )),
153+ abi.encodePacked (type (DefaultFallbackRoutingIsm).creationCode, abi.encode (acct ("hyperlaneMailbox " )))
154+ );
155+ }
156+ ism = CREATE3_FACTORY.getDeployed (admin, keccak256 (abi.encode ("HypEXADefaultIsm " )));
157+ if (ism.code.length == 0 ) {
158+ ism = CREATE3_FACTORY.deploy (
159+ keccak256 (abi.encode ("HypEXADefaultIsm " )),
160+ abi.encodePacked (
161+ type (TransparentUpgradeableProxy).creationCode,
162+ abi.encode (impl, protocol ("ProxyAdmin " ), abi.encodeCall (IRoutingIsmInitializer.initialize, (acct ("exactly " ))))
163+ )
164+ );
165+ }
166+ }
167+
132168 function _deployPausableHook (address owner ) internal returns (address hook ) {
133- hook = address (new PausableHook ());
134- PausableHook (hook).transferOwnership (owner);
169+ address factory = CREATE3_FACTORY.getDeployed (acct ("admin " ), keccak256 (abi.encode ("PausableHookFactory " )));
170+ if (factory.code.length == 0 ) {
171+ factory =
172+ CREATE3_FACTORY.deploy (keccak256 (abi.encode ("PausableHookFactory " )), type (PausableHookFactory).creationCode);
173+ }
174+ hook = address (PausableHookFactory (factory).deploy (owner));
135175 }
136176
137177 function _deployPausableIsm (address owner ) internal returns (address ism ) {
138- ism = address (new PausableIsm (owner));
178+ address factory = CREATE3_FACTORY.getDeployed (acct ("admin " ), keccak256 (abi.encode ("PausableIsmFactory " )));
179+ if (factory.code.length == 0 ) {
180+ factory =
181+ CREATE3_FACTORY.deploy (keccak256 (abi.encode ("PausableIsmFactory " )), type (PausableIsmFactory).creationCode);
182+ }
183+ ism = address (PausableIsmFactory (factory).deploy (owner));
139184 }
140185
141186 function _expectOwner (address target , address owner ) internal view {
@@ -146,12 +191,30 @@ contract HypEXA is BaseScript {
146191error AlreadyGranted ();
147192error RouterNotDeployed ();
148193error UnexpectedOwner (address target , address owner );
194+ error UnsupportedChain (uint256 chainid );
195+
196+ contract PausableHookFactory {
197+ function deploy (address owner ) external returns (PausableHook hook ) {
198+ hook = new PausableHook ();
199+ hook.transferOwnership (owner);
200+ }
201+ }
202+
203+ contract PausableIsmFactory {
204+ function deploy (address owner ) external returns (PausableIsm ism ) {
205+ ism = new PausableIsm (owner);
206+ }
207+ }
149208
150209interface IStaticAggregationHookFactory {
151210 function deploy (address [] calldata values ) external returns (address );
152211 function getAddress (address [] calldata values ) external view returns (address );
153212}
154213
214+ interface IRoutingIsmInitializer {
215+ function initialize (address owner ) external ;
216+ }
217+
155218interface IStaticAggregationIsm {
156219 function modulesAndThreshold (bytes calldata ) external view returns (address [] memory , uint8 );
157220}
0 commit comments