-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
improve: Make changes after running Slither on SpokePool contracts #229
Conversation
This PR makes SpokePools compatible with OpenZeppelin's upgradeable proxy pattern
UUPS proxies allow the implementation contract to define the conditions under which an upgrade can be called, compared to a Transparent proxy in which only the owner of the proxy can upgrade. This allows the SpokePool upgrades to be triggered by the cross domain admin via the HubPool
…use no contracts use delegatecall() anymore
Signed-off-by: nicholaspai <npai.nyc@gmail.com>
Co-authored-by: Paul <108695806+pxrl@users.noreply.github.com>
Signed-off-by: nicholaspai <npai.nyc@gmail.com>
Signed-off-by: nicholaspai <npai.nyc@gmail.com>
Signed-off-by: nicholaspai <npai.nyc@gmail.com>
Signed-off-by: nicholaspai <npai.nyc@gmail.com>
contracts/Ovm_SpokePool.sol
Outdated
@@ -59,6 +59,7 @@ contract Ovm_SpokePool is SpokePool { | |||
l1Gas = 5_000_000; | |||
__SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken, _timerAddress); | |||
messenger = Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER; | |||
require(_l2Eth != address(0), "Invalid L2 ETH address"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Slither recommends we add these zero address checks. It does add a fixed gas cost to construction but adds some safety. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about the value of these checks. 0 is only one possible invalid address, but there are ~infinitely many other invalid addresses as well. The only way we can really be confident that the address is set correctly is via post-deployment verification.
I'm not firmly against it or anything, it just seems a bit redundant and might give a false sense of security.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think I agree with your comment and will remove these zero address checks
contracts/PolygonTokenBridger.sol
Outdated
@@ -38,7 +38,7 @@ interface MaticToken { | |||
* This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the | |||
* sender. | |||
*/ | |||
contract PolygonTokenBridger is Lockable { | |||
contract PolygonTokenBridger is ReentrancyGuard { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slither had some complaints about Lockable but i figured this was a good time to use OZ's ReentrancyGuard instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this contract will be in scope for the audit. Are we okay making this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point, removed
@@ -290,6 +290,11 @@ abstract contract SpokePool is | |||
* to ensure that a small input range doesn't limit which indices this method is able to reach. | |||
*/ | |||
function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant { | |||
// Deleting a struct containing a mapping does not delete the mapping in Solidity, therefore the bitmap's |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This warning was the most interesting in this PR IMO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree - interesting find. It seems OK to suppress the warning:
- In the event that a bad bundle makes it to the SpokePool and is subsequently deleted, rootBundle.relayerRefundRoot and rootBundle.slowRelayRoot will be zeroed.
- Proof verification is one of the first things to occur in _executeRelayerRefundLeaf() and _executeSlowRelayLeaf().
- Any immediate attempt to execute its leaves via executeRelayerRefundRoot() or executeSlowRelayLeaf() should revert on failed proof verification.
This array entry will, at some later time, be overwritten with different data, but the bitmap will indefinitely record that the old deleted leaves remain unclaimed. Any attempt to execute those would rely on collisions and should therefore still fail on proof verification.Wrong & irrelevant, as identified by Matt.
Additionally:
- emergencyDeleteRootBundle() is an admin function, so this can't be initiated by any arbitrary caller. To end up here, a specific sequence of unlikely of events needs to occur. It seems highly improbable that a malicious third party could orchestrate that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @pxrl. Just to add one point: we will never reuse this array slot (because deleting an element of an array does not actually reduce the array.length I believe, meaning the slot is still reserved), so the mapping will never be read or written to again, by definition, no? So we shouldn't need to worry about this at all right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to add one point: we will never reuse this array slot (because deleting an element of an array does not actually reduce the array.length I believe, meaning the slot is still reserved), so the mapping will never be read or written to again, by definition, no? So we shouldn't need to worry about this at all right?
You're right - I'd understood that the array element was actually removed, but I can see that it's only zeroed. So my 4th point was garbage!
require( | ||
getCurrentTime() >= quoteTimestamp - depositQuoteTimeBuffer && | ||
getCurrentTime() <= quoteTimestamp + depositQuoteTimeBuffer, | ||
"invalid quote time" | ||
); | ||
|
||
// Increment count of deposits so that deposit ID for this spoke pool is unique. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move the storage variable modification to numberOfDeposits
above the external call safeTransferFrom
to align with CEI pattern
@@ -8,5 +8,5 @@ interface WETH9Interface { | |||
|
|||
function balanceOf(address guy) external view returns (uint256 wad); | |||
|
|||
function transfer(address guy, uint256 wad) external; | |||
function transfer(address guy, uint256 wad) external returns (bool); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This interface was incorrect and inconsistent with how we implement WETH9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good initiative!
@@ -290,6 +290,11 @@ abstract contract SpokePool is | |||
* to ensure that a small input range doesn't limit which indices this method is able to reach. | |||
*/ | |||
function emergencyDeleteRootBundle(uint256 rootBundleId) public override onlyAdmin nonReentrant { | |||
// Deleting a struct containing a mapping does not delete the mapping in Solidity, therefore the bitmap's |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree - interesting find. It seems OK to suppress the warning:
- In the event that a bad bundle makes it to the SpokePool and is subsequently deleted, rootBundle.relayerRefundRoot and rootBundle.slowRelayRoot will be zeroed.
- Proof verification is one of the first things to occur in _executeRelayerRefundLeaf() and _executeSlowRelayLeaf().
- Any immediate attempt to execute its leaves via executeRelayerRefundRoot() or executeSlowRelayLeaf() should revert on failed proof verification.
This array entry will, at some later time, be overwritten with different data, but the bitmap will indefinitely record that the old deleted leaves remain unclaimed. Any attempt to execute those would rely on collisions and should therefore still fail on proof verification.Wrong & irrelevant, as identified by Matt.
Additionally:
- emergencyDeleteRootBundle() is an admin function, so this can't be initiated by any arbitrary caller. To end up here, a specific sequence of unlikely of events needs to occur. It seems highly improbable that a malicious third party could orchestrate that.
contracts/Ovm_SpokePool.sol
Outdated
@@ -59,6 +59,7 @@ contract Ovm_SpokePool is SpokePool { | |||
l1Gas = 5_000_000; | |||
__SpokePool_init(_initialDepositId, _crossDomainAdmin, _hubPool, _wrappedNativeToken, _timerAddress); | |||
messenger = Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER; | |||
require(_l2Eth != address(0), "Invalid L2 ETH address"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about the value of these checks. 0 is only one possible invalid address, but there are ~infinitely many other invalid addresses as well. The only way we can really be confident that the address is set correctly is via post-deployment verification.
I'm not firmly against it or anything, it just seems a bit redundant and might give a false sense of security.
slither contracts/SpokePool.sol | ||
\ --solc-remaps @=node_modules/@ | ||
\ --solc-args "--optimize --optimize-runs 1000000" | ||
\ --filter-paths "node_modules" | ||
\ --exclude naming-convention |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we make a shortcut for this via package.json?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm i'm having trouble getting this to work from an npm run will look into it further
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
contracts/PolygonTokenBridger.sol
Outdated
@@ -38,7 +38,7 @@ interface MaticToken { | |||
* This ultimately allows create2 to generate deterministic addresses that don't depend on the transaction count of the | |||
* sender. | |||
*/ | |||
contract PolygonTokenBridger is Lockable { | |||
contract PolygonTokenBridger is ReentrancyGuard { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this contract will be in scope for the audit. Are we okay making this change?
Slither is a Solidity static analysis framework written in Python 3. It runs a
suite of vulnerability detectors, prints visual information about contract details, and provides an API to easily write
custom analyses. Slither enables developers to find vulnerabilities, enhance their code comprehension, and quickly
prototype custom analyses.
Spire-Contracts has been analyzed using
Slither@0.9.2
and no major bugs was found. To rerun the analytics, run:You can replace
SpokePool.sol
with the specific contract you want to analyze. For this PR I ran this on the following contracts:This covered any contracts imported by those contracts. Notably I did not make any changes recommended to HubPool.sol, even though there were some, because we don't have plans to redeploy that soon.
Signed-off-by: nicholaspai npai.nyc@gmail.com