Skip to content

Commit ce79cf6

Browse files
committed
Harden constructor
1 parent a9d7c3e commit ce79cf6

File tree

2 files changed

+33
-0
lines changed

2 files changed

+33
-0
lines changed

contracts/ZkSync_SpokePool.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ contract ZkSync_SpokePool is SpokePool, CircleCCTPAdapter {
3939

4040
event SetZkBridge(address indexed erc20Bridge, address indexed oldErc20Bridge);
4141

42+
error InvalidBridgeConfig();
43+
4244
/**
4345
* @notice Constructor.
4446
* @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set.
@@ -62,6 +64,13 @@ contract ZkSync_SpokePool is SpokePool, CircleCCTPAdapter {
6264
SpokePool(_wrappedNativeTokenAddress, _depositQuoteTimeBuffer, _fillDeadlineBuffer)
6365
CircleCCTPAdapter(_l2Usdc, _cctpTokenMessenger, CircleDomainIds.Ethereum)
6466
{
67+
address zero = address(0);
68+
if (address(_l2Usdc) != zero) {
69+
if (address(_zkUSDCBridge) == zero && address(_cctpTokenMessenger) == zero) {
70+
revert InvalidBridgeConfig();
71+
}
72+
}
73+
6574
zkUSDCBridge = _zkUSDCBridge;
6675
}
6776

test/evm/hardhat/chain-specific-spokepools/ZkSync_SpokePool.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,30 @@ describe("ZkSync Spoke Pool", function () {
109109
await zkSyncSpokePool.connect(crossDomainAlias).setZkBridge(rando.address);
110110
expect(await zkSyncSpokePool.zkErc20Bridge()).to.equal(rando.address);
111111
});
112+
it("Invalid USDC bridge configuration is rejected", async function () {
113+
let _constructorArgs = [...constructorArgs];
114+
expect(_constructorArgs[1]).to.equal(usdc.address);
115+
expect(_constructorArgs[2]).to.equal(zkUSDCBridge.address);
116+
expect(_constructorArgs[3]).to.equal(cctpTokenMessenger);
117+
118+
// Verify successful deployment.
119+
let implementation = hre.upgrades.deployImplementation(await getContractFactory("ZkSync_SpokePool", owner), {
120+
kind: "uups",
121+
unsafeAllow: ["delegatecall"],
122+
constructorArgs: _constructorArgs,
123+
});
124+
await expect(implementation).to.not.be.reverted;
125+
126+
_constructorArgs[2] = ZERO_ADDRESS;
127+
_constructorArgs[3] = ZERO_ADDRESS;
128+
129+
implementation = hre.upgrades.deployImplementation(await getContractFactory("ZkSync_SpokePool", owner), {
130+
kind: "uups",
131+
unsafeAllow: ["delegatecall"],
132+
constructorArgs: _constructorArgs,
133+
});
134+
await expect(implementation).to.be.reverted;
135+
});
112136
it("Only cross domain owner can relay admin root bundles", async function () {
113137
const { tree } = await constructSingleRelayerRefundTree(l2Dai, await zkSyncSpokePool.callStatic.chainId());
114138
await expect(zkSyncSpokePool.relayRootBundle(tree.getHexRoot(), mockTreeRoot)).to.be.revertedWith(

0 commit comments

Comments
 (0)