We're excited to share the results of mev-commit's recent comprehensive security review - a critical milestone in our journey to provide industry-leading credible commitment infrastructure. Through collaboration with top security researchers via Cantina's competition, we've strengthened mev-commit’s foundations in several key areas, most significantly to ensure bidding and slashing accuracy and overall fund security. In the spirit of transparency, and as an opportunity to unpack some facets to mev-commit’s novel infrastructure, we’d like to detail some highlights from these findings.
The review helped strengthen mev-commit's core preconfirmation components where providers commit to including specific transactions in blocks. A key improvement focused on the bid decay mechanism that incentivizes timely provider commitments. We identified and patched a vulnerability where providers could manipulate commitment timestamps to avoid penalties by adding cryptographic guarantees to enforce honest behavior.
The Gateway contract serves as the bridge between L1 and the mev-commit chain, handling all cross-chain value transfers and settlement logic. In this contract, we fixed an important issue around failed transfers that could have led to locked funds:
function finalizeTransfer(/*params*/) {
// If this transfer fails, transferFinalizedIdx isn't incremented
(bool success, ) = payable(_recipient).call{value: amount}("");
require(success, "Transfer failed");
transferFinalizedIdx++;
}
A malicious user could exploit such code by intentionally submitting a failed transfer, such as by adding a revert()
to the destination contract address. This failure would prevent transferFinalizedIdx
from incrementing while transferInitiatedIdx
continued to increase, creating an index mismatch that could freeze the contract. We've implemented proper error handling and atomic operations to ensure that even in edge cases – like when a recipient contract unexpectedly reverts – the system maintains consistent state and protects user funds:
function _fund(uint256 _amount, address _toFund) internal override {
require(address(this).balance >= _amount, InsufficientContractBalance(address(this).balance, _amount));
// Try standard transfer first
if (!payable(_toFund).send(_amount)) {
// If transfer fails, track for manual withdrawal
transferredFundsNeedingWithdrawal[_toFund] += _amount;
emit TransferNeedsWithdrawal(_toFund, _amount);
return;
}
emit TransferSuccess(_toFund, _amount);
}
// Allow manual withdrawal for failed transfers
function withdraw(address _recipient) external whenNotPaused nonReentrant {
uint256 amount = transferredFundsNeedingWithdrawal[_recipient];
require(amount > 0, NoFundsNeedingWithdrawal(_recipient));
transferredFundsNeedingWithdrawal[_recipient] = 0;
(bool success, ) = _recipient.call{value: amount}("");
require(success, TransferFailed(_recipient));
emit TransferSuccess(_recipient, amount);
}
This solution implements a "pull" pattern for failed transfers rather than repeatedly trying to push funds to potentially malicious recipients. If a transfer fails, the funds are tracked for manual withdrawal later, preventing both permanent locks and index mismatches. This pattern makes the system more robust against both accidental failures and intentional DoS attempts.
Some of the most significant improvements came from rethinking how providers interact with the protocol's commitment system. For instance, we enhanced how we track provider stakes against their commitments. Previously, when providers stored unopened commitments, there wasn't a mechanism to ensure their total potential slashing liability stayed within their staked amount. A provider could store multiple unopened commitments that, if opened and slashed, would exceed their stake - leaving some bidders unable to receive their full slashing compensation. We've now implemented enhanced tracking that properly accounts for a provider's total commitment liability to ensure they maintain adequate stake to cover all potential slashing scenarios - a crucial protection for both bidders and the system's economic security.
The review also helped us optimize our transaction processing systems for real-world conditions. Consider the case of high-activity periods where many bids are being processed simultaneously. We've improved gas efficiency and added protection against potential denial-of-service vectors by implementing gas limits on external calls and moving from push to pull payment patterns. Consider this vulnerable pattern:
function retrieveFunds(/*params*/) {
// No gas limit specified for external call
(bool success, ) = payable(bidder).call{value: fundsToReturn}("");
require(success, TransferToBidderFailed(bidder, fundsToReturn));
}
Previously, a malicious bidder could force the oracle to consume excessive gas during bid processing or block bid processing entirely. By refactoring how payments are handled and adding proper bounds checking, we've ensured the protocol can process bids efficiently and reliably even under peak load or adversarial conditions.
Validators play a crucial role in our system, and the audit helped clarify responsibilities around validator management and stake coverage. We've established clearer expectations that operators are responsible for monitoring their vault collateral and ensuring registered validators remain slashable (and therefore opted-in). When vault collateral decreases to a level that doesn't cover all validators, operators must either deregister validators of their choice or accept that some validators will no longer be opted-in.
We’re enforcing these principles through tracking of validator status and stake levels. Rather than introducing complex reordering mechanisms, we've clarified that operators should manage their validator sets directly through registration and deregistration based on their stake levels. This approach maintains stronger slashing guarantees and simplifies our operational model.
While successfully completing this review marks an important milestone, we view security as an ongoing commitment. Each improvement we've made serves as a foundation for future enhancements. For instance, our revised commitment verification system which now verifies both commitment signatures and timestamps atomically not only fixes current vulnerabilities but also provides a more flexible framework for adding future security features: Instead of relying solely on signature verification, the system now combines commitment parameters and timing guarantees into a single verifiable structure. This enables easier integration of additional security checks in the future while maintaining backward compatibility.
The review process has also helped us evolve our development practices. We've identified key areas where additional automated testing is needed, particularly around edge cases in bid processing and commitment handling.
These improvements provide a strong foundation for mev-commit's role for multiple parties in the mev ecosystem. The successful review and subsequent enhancements demonstrate our commitment to building infrastructure that users and developers can trust. But more importantly, they establish a framework for ongoing improvements.