Skip to content

Commit 18210ef

Browse files
committed
update to seperate initialize from constructor
1 parent bd9b483 commit 18210ef

4 files changed

Lines changed: 89 additions & 47 deletions

File tree

base/script/Deploy.s.sol

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,23 @@ contract DeployScript is Script {
7373
remoteBridge: cfg.remoteBridge,
7474
trustedRelayer: cfg.trustedRelayer,
7575
twinBeacon: twinBeacon,
76-
crossChainErc20Factory: crossChainErc20Factory,
77-
validators: cfg.initialValidators,
78-
threshold: cfg.initialThreshold,
79-
ismOwner: cfg.initialOwner
76+
crossChainErc20Factory: crossChainErc20Factory
8077
});
8178

82-
return ERC1967Factory(cfg.erc1967Factory).deployDeterministic({
79+
address proxy = ERC1967Factory(cfg.erc1967Factory).deployDeterministic({
8380
implementation: address(bridgeImpl),
8481
admin: cfg.initialOwner,
8582
salt: _salt("bridge15")
8683
});
84+
85+
// Initialize the Bridge with ISM parameters
86+
Bridge(proxy).initialize({
87+
validators: cfg.initialValidators,
88+
threshold: cfg.initialThreshold,
89+
ismOwner: cfg.initialOwner
90+
});
91+
92+
return proxy;
8793
}
8894

8995
function _deployFactory(HelperConfig.NetworkConfig memory cfg, address precomputedBridgeAddress)

base/src/Bridge.sol

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pragma solidity 0.8.28;
44
import {LibClone} from "solady/utils/LibClone.sol";
55
import {ReentrancyGuardTransient} from "solady/utils/ReentrancyGuardTransient.sol";
66
import {UpgradeableBeacon} from "solady/utils/UpgradeableBeacon.sol";
7+
import {Initializable} from "solady/utils/Initializable.sol";
78

89
import {Call} from "./libraries/CallLib.sol";
910
import {IncomingMessage, MessageType} from "./libraries/MessageLib.sol";
@@ -20,7 +21,7 @@ import {Twin} from "./Twin.sol";
2021
/// @notice The Bridge enables sending calls from Solana to Base.
2122
///
2223
/// @dev Calls sent from Solana to Base are relayed via a Twin contract that is specific per Solana sender pubkey.
23-
contract Bridge is ReentrancyGuardTransient {
24+
contract Bridge is ReentrancyGuardTransient, Initializable {
2425
//////////////////////////////////////////////////////////////
2526
/// Constants ///
2627
//////////////////////////////////////////////////////////////
@@ -56,33 +57,37 @@ contract Bridge is ReentrancyGuardTransient {
5657
///
5758
uint256 private constant _EXECUTION_PROLOGUE_GAS_BUFFER = 35_000;
5859

59-
/// @notice Gas required to run the execution section of `__validateAndRelay`.
60+
/// @notice Gas required to run the execution epilogue section of `__validateAndRelay`.
6061
///
61-
/// @dev Simulated via a forge test performing a single call to `__validateAndRelay` where:
62-
/// - The execution epilogue section was commented out to isolate the execution section.
62+
/// @dev Simulated via a forge test performing a call to `relayMessages` with a single message where:
63+
/// - The execution prologue and the execution sections were commented out to isolate the execution epilogue
64+
/// section.
65+
/// - `isTrustedRelayer` was true to estimate the worst case scenario of doing an additional SSTORE.
6366
/// - The `message.data` field was 4KB large which is sufficient given that the message has to be built from a
6467
/// single Solana transaction (which currently is 1232 bytes).
65-
/// - The metered gas (including the execution prologue section) was 32,858 gas thus the isolated
66-
/// execution section was 32,858 - 30,252 = 2,606 gas.
67-
/// - No buffer is strictly needed as the `_EXECUTION_PROLOGUE_GAS_BUFFER` is already rounded up and above
68-
/// that.
69-
uint256 private constant _EXECUTION_GAS_BUFFER = 3_000;
68+
/// - The metered gas was 6,458 gas.
69+
///
70+
uint256 private constant _EXECUTION_EPILOGUE_GAS_BUFFER = 10_000;
7071

71-
/// @notice Gas required to run the execution epilogue section of `__validateAndRelay`.
72+
/// @notice Gas buffer required to execute the try-catch in `__validateAndRelay` and run the catch block.
7273
///
73-
/// @dev Simulated via a forge test performing a single call to `__validateAndRelay` where:
74-
/// - The `message.data` field was 4KB large which is sufficient given that the message has to be built from a
75-
/// single Solana transaction (which currently is 1232 bytes).
76-
/// - The metered gas (including the execution prologue and execution sections) was 54,481 gas thus the
77-
/// isolated execution epilogue section was 54,481 - 32,858 = 21,623 gas.
78-
uint256 private constant _EXECUTION_EPILOGUE_GAS_BUFFER = 25_000;
74+
/// @dev Computed based on the following formula:
75+
/// `_EXECUTION_GAS_BUFFER = _EXECUTION_PROLOGUE_GAS_BUFFER + _EXECUTION_EPILOGUE_GAS_BUFFER + catch_block_gas`
76+
/// Where the `catch_block_gas` is roughly 5,000 gas.
77+
///
78+
uint256 private constant _EXECUTION_GAS_BUFFER = 50_000;
7979

8080
//////////////////////////////////////////////////////////////
8181
/// Storage ///
8282
//////////////////////////////////////////////////////////////
8383

84-
/// @notice Mapping of message hashes to boolean values indicating successful execution. A message will only be
85-
/// present in this mapping if it has successfully been executed, and therefore cannot be executed again.
84+
/// @notice The nonce of the last MMR root for a given block number. This provides efficient access to the
85+
/// currently active roots for fast-lane optimization without double-inclusion proofs.
86+
mapping(uint256 blockNumber => uint256 nonce) public latestRootNonces;
87+
88+
/// @notice Mapping of message hashes to boolean values indicating successful execution. A message hash will be
89+
/// present in this mapping if and only if it has been successfully executed (including during failed
90+
/// transactions that were later manually retried by users).
8691
mapping(bytes32 messageHash => bool success) public successes;
8792

8893
/// @notice Mapping of message hashes to boolean values indicating failed execution attempts. A message will be
@@ -153,23 +158,31 @@ contract Bridge is ReentrancyGuardTransient {
153158
/// @param trustedRelayer The address of the trusted relayer.
154159
/// @param twinBeacon The address of the Twin beacon.
155160
/// @param crossChainErc20Factory The address of the CrossChainERC20Factory.
156-
/// @param validators Array of validator addresses for ISM verification.
157-
/// @param threshold The ISM verification threshold.
158-
/// @param ismOwner The owner of the ISM verification system.
159161
constructor(
160162
Pubkey remoteBridge,
161163
address trustedRelayer,
162164
address twinBeacon,
163-
address crossChainErc20Factory,
164-
address[] memory validators,
165-
uint128 threshold,
166-
address ismOwner
165+
address crossChainErc20Factory
167166
) {
168167
REMOTE_BRIDGE = remoteBridge;
169168
TRUSTED_RELAYER = trustedRelayer;
170169
TWIN_BEACON = twinBeacon;
171170
CROSS_CHAIN_ERC20_FACTORY = crossChainErc20Factory;
172-
171+
}
172+
173+
/// @notice Initializes the Bridge contract with ISM verification parameters.
174+
///
175+
/// @dev This function should be called immediately after deployment when using with a proxy.
176+
/// Can only be called once due to the initializer modifier.
177+
///
178+
/// @param validators Array of validator addresses for ISM verification.
179+
/// @param threshold The ISM verification threshold.
180+
/// @param ismOwner The owner of the ISM verification system.
181+
function initialize(
182+
address[] memory validators,
183+
uint128 threshold,
184+
address ismOwner
185+
) external initializer {
173186
// Initialize ISM verification library
174187
ISMVerificationLib.initialize(validators, threshold, ismOwner);
175188
}

base/test/Bridge.t.sol

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ contract BridgeTest is Test {
8888
remoteBridge: TEST_SENDER,
8989
trustedRelayer: trustedRelayer,
9090
twinBeacon: address(twinBeacon),
91-
crossChainErc20Factory: address(factory),
91+
crossChainErc20Factory: address(factory)
92+
});
93+
94+
// Initialize the Bridge with ISM parameters
95+
testBridge.initialize({
9296
validators: validators,
9397
threshold: 2,
9498
ismOwner: initialOwner
@@ -881,8 +885,11 @@ contract BridgeTest is Test {
881885
})
882886
);
883887

888+
// Regenerate ISM data for the modified message
889+
bytes memory ismData2 = _generateValidISMData(messages);
890+
884891
vm.prank(trustedRelayer);
885-
bridge.relayMessages(messages, ismData);
892+
bridge.relayMessages(messages, ismData2);
886893

887894
address secondTwin = bridge.twins(TEST_SENDER);
888895
assertEq(firstTwin, secondTwin);

base/test/ISMVerification.t.sol

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,16 @@ contract ISMVerificationTest is Test {
6464
address erc20Beacon = address(new UpgradeableBeacon(owner, erc20Impl));
6565
CrossChainERC20Factory factory = new CrossChainERC20Factory(erc20Beacon);
6666

67-
// Deploy Bridge with ISM configuration
67+
// Deploy Bridge
6868
bridge = new Bridge({
6969
remoteBridge: remoteBridge,
7070
trustedRelayer: trustedRelayer,
7171
twinBeacon: twinBeacon,
72-
crossChainErc20Factory: address(factory),
72+
crossChainErc20Factory: address(factory)
73+
});
74+
75+
// Initialize Bridge with ISM configuration
76+
bridge.initialize({
7377
validators: validators,
7478
threshold: 2,
7579
ismOwner: owner
@@ -136,24 +140,30 @@ contract ISMVerificationTest is Test {
136140
CrossChainERC20Factory factory = new CrossChainERC20Factory(erc20Beacon);
137141

138142
// Test threshold = 0
139-
vm.expectRevert(); // Library will revert with InvalidThreshold
140-
new Bridge({
143+
Bridge testBridge1 = new Bridge({
141144
remoteBridge: remoteBridge,
142145
trustedRelayer: trustedRelayer,
143146
twinBeacon: twinBeacon,
144-
crossChainErc20Factory: address(factory),
147+
crossChainErc20Factory: address(factory)
148+
});
149+
150+
vm.expectRevert(); // Library will revert with InvalidThreshold
151+
testBridge1.initialize({
145152
validators: validators,
146153
threshold: 0,
147154
ismOwner: owner
148155
});
149156

150157
// Test threshold > validator count
151-
vm.expectRevert(); // Library will revert with InvalidThreshold
152-
new Bridge({
158+
Bridge testBridge2 = new Bridge({
153159
remoteBridge: remoteBridge,
154160
trustedRelayer: trustedRelayer,
155161
twinBeacon: twinBeacon,
156-
crossChainErc20Factory: address(factory),
162+
crossChainErc20Factory: address(factory)
163+
});
164+
165+
vm.expectRevert(); // Library will revert with InvalidThreshold
166+
testBridge2.initialize({
157167
validators: validators,
158168
threshold: 3,
159169
ismOwner: owner
@@ -171,12 +181,15 @@ contract ISMVerificationTest is Test {
171181
address erc20Beacon = address(new UpgradeableBeacon(owner, erc20Impl));
172182
CrossChainERC20Factory factory = new CrossChainERC20Factory(erc20Beacon);
173183

174-
vm.expectRevert(); // Library will revert with InvalidThreshold
175-
new Bridge({
184+
Bridge testBridge3 = new Bridge({
176185
remoteBridge: remoteBridge,
177186
trustedRelayer: trustedRelayer,
178187
twinBeacon: twinBeacon,
179-
crossChainErc20Factory: address(factory),
188+
crossChainErc20Factory: address(factory)
189+
});
190+
191+
vm.expectRevert(); // Library will revert with InvalidThreshold
192+
testBridge3.initialize({
180193
validators: validators,
181194
threshold: 1,
182195
ismOwner: owner
@@ -195,12 +208,15 @@ contract ISMVerificationTest is Test {
195208
CrossChainERC20Factory factory = new CrossChainERC20Factory(erc20Beacon);
196209

197210
// This should actually fail based on the current validation logic
198-
vm.expectRevert(); // Library will revert with InvalidThreshold
199-
new Bridge({
211+
Bridge testBridge4 = new Bridge({
200212
remoteBridge: remoteBridge,
201213
trustedRelayer: trustedRelayer,
202214
twinBeacon: twinBeacon,
203-
crossChainErc20Factory: address(factory),
215+
crossChainErc20Factory: address(factory)
216+
});
217+
218+
vm.expectRevert(); // Library will revert with InvalidThreshold
219+
testBridge4.initialize({
204220
validators: validators,
205221
threshold: 0,
206222
ismOwner: owner

0 commit comments

Comments
 (0)