diff --git a/contracts/Arbitrum_SpokePool.sol b/contracts/Arbitrum_SpokePool.sol index 64aec54d9..3baa47969 100644 --- a/contracts/Arbitrum_SpokePool.sol +++ b/contracts/Arbitrum_SpokePool.sol @@ -29,6 +29,8 @@ contract Arbitrum_SpokePool is SpokePool { /** * @notice Construct the AVM SpokePool. + * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate + * relay hash collisions. * @param _l2GatewayRouter Address of L2 token gateway. Can be reset by admin. * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin. * @param _hubPool Hub pool address to set. Can be changed by admin. @@ -36,12 +38,13 @@ contract Arbitrum_SpokePool is SpokePool { * @param timerAddress Timer address to set. */ constructor( + uint32 _initialDepositId, address _l2GatewayRouter, address _crossDomainAdmin, address _hubPool, address _wethAddress, address timerAddress - ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) { + ) SpokePool(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress, timerAddress) { _setL2GatewayRouter(_l2GatewayRouter); } diff --git a/contracts/Boba_SpokePool.sol b/contracts/Boba_SpokePool.sol index adc549387..7832759b1 100644 --- a/contracts/Boba_SpokePool.sol +++ b/contracts/Boba_SpokePool.sol @@ -9,16 +9,20 @@ import "./Ovm_SpokePool.sol"; contract Boba_SpokePool is Ovm_SpokePool { /** * @notice Construct the OVM Boba SpokePool. + * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate + * relay hash collisions. * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin. * @param _hubPool Hub pool address to set. Can be changed by admin. * @param timerAddress Timer address to set. */ constructor( + uint32 _initialDepositId, address _crossDomainAdmin, address _hubPool, address timerAddress ) Ovm_SpokePool( + _initialDepositId, _crossDomainAdmin, _hubPool, 0x4200000000000000000000000000000000000006, diff --git a/contracts/Ethereum_SpokePool.sol b/contracts/Ethereum_SpokePool.sol index 0d949cf5c..fd44f67a1 100644 --- a/contracts/Ethereum_SpokePool.sol +++ b/contracts/Ethereum_SpokePool.sol @@ -15,15 +15,18 @@ contract Ethereum_SpokePool is SpokePool, Ownable { /** * @notice Construct the Ethereum SpokePool. * @dev crossDomainAdmin is unused on this contract. + * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate + * relay hash collisions. * @param _hubPool Hub pool address to set. Can be changed by admin. * @param _wethAddress Weth address for this network to set. * @param timerAddress Timer address to set. */ constructor( + uint32 _initialDepositId, address _hubPool, address _wethAddress, address timerAddress - ) SpokePool(_hubPool, _hubPool, _wethAddress, timerAddress) {} + ) SpokePool(_initialDepositId, _hubPool, _hubPool, _wethAddress, timerAddress) {} /************************************** * INTERNAL FUNCTIONS * diff --git a/contracts/Optimism_SpokePool.sol b/contracts/Optimism_SpokePool.sol index f877bdb04..cd6d26369 100644 --- a/contracts/Optimism_SpokePool.sol +++ b/contracts/Optimism_SpokePool.sol @@ -10,16 +10,20 @@ import "./Ovm_SpokePool.sol"; contract Optimism_SpokePool is Ovm_SpokePool { /** * @notice Construct the OVM Optimism SpokePool. + * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate + * relay hash collisions. * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin. * @param _hubPool Hub pool address to set. Can be changed by admin. * @param timerAddress Timer address to set. */ constructor( + uint32 _initialDepositId, address _crossDomainAdmin, address _hubPool, address timerAddress ) Ovm_SpokePool( + _initialDepositId, _crossDomainAdmin, _hubPool, Lib_PredeployAddresses.OVM_ETH, diff --git a/contracts/Ovm_SpokePool.sol b/contracts/Ovm_SpokePool.sol index c54c47c61..bd16f235b 100644 --- a/contracts/Ovm_SpokePool.sol +++ b/contracts/Ovm_SpokePool.sol @@ -34,11 +34,14 @@ contract Ovm_SpokePool is CrossDomainEnabled, SpokePool { /** * @notice Construct the OVM SpokePool. + * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate + * relay hash collisions. * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin. * @param _hubPool Hub pool address to set. Can be changed by admin. * @param timerAddress Timer address to set. */ constructor( + uint32 _initialDepositId, address _crossDomainAdmin, address _hubPool, address _l2Eth, @@ -46,7 +49,7 @@ contract Ovm_SpokePool is CrossDomainEnabled, SpokePool { address timerAddress ) CrossDomainEnabled(Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER) - SpokePool(_crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress) + SpokePool(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken, timerAddress) { l2Eth = _l2Eth; } diff --git a/contracts/Polygon_SpokePool.sol b/contracts/Polygon_SpokePool.sol index 9a17950fc..8675bf96d 100644 --- a/contracts/Polygon_SpokePool.sol +++ b/contracts/Polygon_SpokePool.sol @@ -62,6 +62,8 @@ contract Polygon_SpokePool is IFxMessageProcessor, SpokePool { /** * @notice Construct the Polygon SpokePool. + * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate + * relay hash collisions. * @param _polygonTokenBridger Token routing contract that sends tokens from here to HubPool. Changeable by Admin. * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin. * @param _hubPool Hub pool address to set. Can be changed by admin. @@ -70,13 +72,14 @@ contract Polygon_SpokePool is IFxMessageProcessor, SpokePool { * @param timerAddress Timer address to set. */ constructor( + uint32 _initialDepositId, PolygonTokenBridger _polygonTokenBridger, address _crossDomainAdmin, address _hubPool, address _wmaticAddress, // Note: wmatic is used here since it is the token sent via msg.value on polygon. address _fxChild, address timerAddress - ) SpokePool(_crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) { + ) SpokePool(_initialDepositId, _crossDomainAdmin, _hubPool, _wmaticAddress, timerAddress) { polygonTokenBridger = _polygonTokenBridger; fxChild = _fxChild; } diff --git a/contracts/SpokePool.sol b/contracts/SpokePool.sol index 988e7b713..3cf7b9ef2 100644 --- a/contracts/SpokePool.sol +++ b/contracts/SpokePool.sol @@ -130,17 +130,21 @@ abstract contract SpokePool is SpokePoolInterface, Testable, Lockable, MultiCall /** * @notice Construct the base SpokePool. + * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate + * relay hash collisions. * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin. * @param _hubPool Hub pool address to set. Can be changed by admin. * @param _wrappedNativeTokenAddress wrappedNativeToken address for this network to set. * @param timerAddress Timer address to set. */ constructor( + uint32 _initialDepositId, address _crossDomainAdmin, address _hubPool, address _wrappedNativeTokenAddress, address timerAddress ) Testable(timerAddress) { + numberOfDeposits = _initialDepositId; _setCrossDomainAdmin(_crossDomainAdmin); _setHubPool(_hubPool); wrappedNativeToken = WETH9(_wrappedNativeTokenAddress); diff --git a/contracts/ZkSync_SpokePool.sol b/contracts/ZkSync_SpokePool.sol index 368933409..41bcb7b24 100644 --- a/contracts/ZkSync_SpokePool.sol +++ b/contracts/ZkSync_SpokePool.sol @@ -35,6 +35,8 @@ contract ZkSync_SpokePool is SpokePool { /** * @notice Construct the ZkSync SpokePool. + * @param _initialDepositId Starting deposit ID. Set to 0 unless this is a re-deployment in order to mitigate + * relay hash collisions. * @param _zkErc20Bridge Address of L2 ERC20 gateway. Can be reset by admin. * @param _zkEthBridge Address of L2 ETH gateway. Can be reset by admin. * @param _crossDomainAdmin Cross domain admin to set. Can be changed by admin. @@ -43,13 +45,14 @@ contract ZkSync_SpokePool is SpokePool { * @param timerAddress Timer address to set. */ constructor( + uint32 _initialDepositId, ZkBridgeLike _zkErc20Bridge, ZkBridgeLike _zkEthBridge, address _crossDomainAdmin, address _hubPool, address _wethAddress, address timerAddress - ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) { + ) SpokePool(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress, timerAddress) { _setZkBridges(_zkErc20Bridge, _zkEthBridge); } diff --git a/contracts/test/MockSpokePool.sol b/contracts/test/MockSpokePool.sol index 3fe65ffc2..bc62b6501 100644 --- a/contracts/test/MockSpokePool.sol +++ b/contracts/test/MockSpokePool.sol @@ -13,11 +13,12 @@ contract MockSpokePool is SpokePool { // solhint-disable-next-line no-empty-blocks constructor( + uint32 _initialDepositId, address _crossDomainAdmin, address _hubPool, address _wethAddress, address timerAddress - ) SpokePool(_crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks + ) SpokePool(_initialDepositId, _crossDomainAdmin, _hubPool, _wethAddress, timerAddress) {} // solhint-disable-line no-empty-blocks // solhint-disable-next-line no-empty-blocks function _bridgeTokensToHubPool(RelayerRefundLeaf memory relayerRefundLeaf) internal override {} diff --git a/test/SpokePool.Admin.ts b/test/SpokePool.Admin.ts index c67f95b5b..69f543021 100644 --- a/test/SpokePool.Admin.ts +++ b/test/SpokePool.Admin.ts @@ -1,4 +1,4 @@ -import { expect, ethers, Contract, SignerWithAddress } from "./utils"; +import { expect, ethers, Contract, SignerWithAddress, getContractFactory } from "./utils"; import { spokePoolFixture } from "./fixtures/SpokePool.Fixture"; import { destinationChainId, mockRelayerRefundRoot, mockSlowRelayRoot } from "./constants"; @@ -10,6 +10,12 @@ describe("SpokePool Admin Functions", async function () { [owner] = await ethers.getSigners(); ({ spokePool, erc20 } = await spokePoolFixture()); }); + it("Can set initial deposit ID", async function () { + const spokePool = await ( + await getContractFactory("MockSpokePool", owner) + ).deploy(1, owner.address, owner.address, owner.address, owner.address); + expect(await spokePool.numberOfDeposits()).to.equal(1); + }); it("Enable token path", async function () { await expect(spokePool.connect(owner).setEnableRoute(erc20.address, destinationChainId, true)) .to.emit(spokePool, "EnabledDepositRoute") diff --git a/test/chain-specific-spokepools/Arbitrum_SpokePool.ts b/test/chain-specific-spokepools/Arbitrum_SpokePool.ts index e07747d1d..222c9ccb0 100644 --- a/test/chain-specific-spokepools/Arbitrum_SpokePool.ts +++ b/test/chain-specific-spokepools/Arbitrum_SpokePool.ts @@ -25,7 +25,7 @@ describe("Arbitrum Spoke Pool", function () { arbitrumSpokePool = await ( await getContractFactory("Arbitrum_SpokePool", owner) - ).deploy(l2GatewayRouter.address, owner.address, hubPool.address, l2Weth, timer.address); + ).deploy(0, l2GatewayRouter.address, owner.address, hubPool.address, l2Weth, timer.address); await seedContract(arbitrumSpokePool, relayer, [dai], weth, amountHeldByPool); await arbitrumSpokePool.connect(crossDomainAlias).whitelistToken(l2Dai, dai.address); diff --git a/test/chain-specific-spokepools/Ethereum_SpokePool.ts b/test/chain-specific-spokepools/Ethereum_SpokePool.ts index cd194b0e4..cae90bdc4 100644 --- a/test/chain-specific-spokepools/Ethereum_SpokePool.ts +++ b/test/chain-specific-spokepools/Ethereum_SpokePool.ts @@ -15,7 +15,7 @@ describe("Ethereum Spoke Pool", function () { spokePool = await ( await getContractFactory("Ethereum_SpokePool", owner) - ).deploy(hubPool.address, weth.address, timer.address); + ).deploy(0, hubPool.address, weth.address, timer.address); // Seed spoke pool with tokens that it should transfer to the hub pool // via the _bridgeTokensToHubPool() internal call. diff --git a/test/chain-specific-spokepools/Optimism_SpokePool.ts b/test/chain-specific-spokepools/Optimism_SpokePool.ts index abd4eac2e..eafd78ec1 100644 --- a/test/chain-specific-spokepools/Optimism_SpokePool.ts +++ b/test/chain-specific-spokepools/Optimism_SpokePool.ts @@ -29,7 +29,7 @@ describe("Optimism Spoke Pool", function () { optimismSpokePool = await ( await getContractFactory("Optimism_SpokePool", owner) - ).deploy(owner.address, hubPool.address, timer.address); + ).deploy(0, owner.address, hubPool.address, timer.address); await seedContract(optimismSpokePool, relayer, [dai], weth, amountHeldByPool); }); diff --git a/test/chain-specific-spokepools/Polygon_SpokePool.ts b/test/chain-specific-spokepools/Polygon_SpokePool.ts index c19d8f0ce..a97c123d9 100644 --- a/test/chain-specific-spokepools/Polygon_SpokePool.ts +++ b/test/chain-specific-spokepools/Polygon_SpokePool.ts @@ -33,7 +33,15 @@ describe("Polygon Spoke Pool", function () { polygonSpokePool = await ( await getContractFactory("Polygon_SpokePool", owner) - ).deploy(polygonTokenBridger.address, owner.address, hubPool.address, weth.address, fxChild.address, timer.address); + ).deploy( + 0, + polygonTokenBridger.address, + owner.address, + hubPool.address, + weth.address, + fxChild.address, + timer.address + ); await seedContract(polygonSpokePool, relayer, [dai], weth, amountHeldByPool); await seedWallet(owner, [], weth, toWei("1")); diff --git a/test/fixtures/HubPool.Fixture.ts b/test/fixtures/HubPool.Fixture.ts index 3a073b91e..e2aa657eb 100644 --- a/test/fixtures/HubPool.Fixture.ts +++ b/test/fixtures/HubPool.Fixture.ts @@ -44,7 +44,7 @@ export async function deployHubPool(ethers: any) { const mockAdapter = await (await getContractFactory("Mock_Adapter", signer)).deploy(); const mockSpoke = await ( await getContractFactory("MockSpokePool", signer) - ).deploy(crossChainAdmin.address, hubPool.address, weth.address, parentFixture.timer.address); + ).deploy(0, crossChainAdmin.address, hubPool.address, weth.address, parentFixture.timer.address); await hubPool.setCrossChainContracts(repaymentChainId, mockAdapter.address, mockSpoke.address); await hubPool.setCrossChainContracts(originChainId, mockAdapter.address, mockSpoke.address); @@ -53,7 +53,7 @@ export async function deployHubPool(ethers: any) { const mockAdapterMainnet = await (await getContractFactory("Mock_Adapter", signer)).deploy(); const mockSpokeMainnet = await ( await getContractFactory("MockSpokePool", signer) - ).deploy(crossChainAdmin.address, hubPool.address, weth.address, parentFixture.timer.address); + ).deploy(0, crossChainAdmin.address, hubPool.address, weth.address, parentFixture.timer.address); await hubPool.setCrossChainContracts(mainnetChainId, mockAdapterMainnet.address, mockSpokeMainnet.address); // Deploy mock l2 tokens for each token created before and whitelist the routes. diff --git a/test/fixtures/SpokePool.Fixture.ts b/test/fixtures/SpokePool.Fixture.ts index a14862652..dc6494cee 100644 --- a/test/fixtures/SpokePool.Fixture.ts +++ b/test/fixtures/SpokePool.Fixture.ts @@ -35,7 +35,7 @@ export async function deploySpokePool(ethers: any): Promise<{ // Deploy the pool const spokePool = await ( await getContractFactory("MockSpokePool", deployerWallet) - ).deploy(crossChainAdmin.address, hubPool.address, weth.address, timer.address); + ).deploy(0, crossChainAdmin.address, hubPool.address, weth.address, timer.address); await spokePool.setChainId(consts.destinationChainId); return { timer, weth, erc20, spokePool, unwhitelistedErc20, destErc20 }; diff --git a/test/gas-analytics/HubPool.RootExecution.ts b/test/gas-analytics/HubPool.RootExecution.ts index b44f157a0..d6a4d3ceb 100644 --- a/test/gas-analytics/HubPool.RootExecution.ts +++ b/test/gas-analytics/HubPool.RootExecution.ts @@ -95,14 +95,14 @@ describe("Gas Analytics: HubPool Root Bundle Execution", function () { const adapter = await (await getContractFactory("Mock_Adapter", owner)).deploy(); const spoke = await ( await getContractFactory("MockSpokePool", owner) - ).deploy(randomAddress(), hubPool.address, randomAddress(), consts.zeroAddress); + ).deploy(0, randomAddress(), hubPool.address, randomAddress(), consts.zeroAddress); await hubPool.setCrossChainContracts(hubPoolChainId, adapter.address, spoke.address); for (let i = 0; i < REFUND_CHAIN_COUNT; i++) { const adapter = await (await getContractFactory("Mock_Adapter", owner)).deploy(); const spoke = await ( await getContractFactory("MockSpokePool", owner) - ).deploy(randomAddress(), hubPool.address, randomAddress(), consts.zeroAddress); + ).deploy(0, randomAddress(), hubPool.address, randomAddress(), consts.zeroAddress); await hubPool.setCrossChainContracts(i, adapter.address, spoke.address); await Promise.all( l1Tokens.map(async (token) => {