Summary
The GlobalConfigurationBranch::createPerpMarket
function has incomplete input validation for critical components of the params
argument. Specifically, it lacks checks for the keeper
address in SettlementConfiguration.Data
and the makerFee
and takerFee
in OrderFees.Data
. This oversight means
A zero address could be set as the keeper
in the SettlementConfiguration
, potentially breaking keeper-dependent functionalities.
Zero Input values could be passed as takerFee
and makerFee
, risking economic imbalances in the market.
Vulnerability Details
1.) Missing Zero Address Check: The keeper
address in SettlementConfiguration.Data
is not checked for a zero address. This check is absent in GlobalConfigurationBranch::createPerpMarket
function, PerpMarket::create function and the SettlementConfiguration::update
function.
https://github.com/Cyfrin/2024-07-zaros/blob/main/src/perpetuals/branches/GlobalConfigurationBranch.sol#L379-L441
https://github.com/Cyfrin/2024-07-zaros/blob/main/src/perpetuals/leaves/PerpMarket.sol#L395-L429
https://github.com/Cyfrin/2024-07-zaros/blob/main/src/perpetuals/leaves/SettlementConfiguration.sol#L109-L123
function update(
uint128 marketId,
uint128 settlementConfigurationId,
Data memory settlementConfiguration
) internal {
self.keeper = settlementConfiguration.keeper;
}
2.) Incomplete Validation for OrderFees: The orderFees
parameter, which contains makerFee
and takerFee
, is not validated for zero values in the createPerpMarket
function.
function createPerpMarket(CreatePerpMarketParams calldata params) external onlyOwner {
if (params.marketId == 0) {
revert Errors.ZeroInput("marketId");
}
if (abi.encodePacked(params.name).length == 0) {
revert Errors.ZeroInput("name");
}
if (abi.encodePacked(params.symbol).length == 0) {
revert Errors.ZeroInput("symbol");
}
if (params.priceAdapter == address(0)) {
revert Errors.ZeroInput("priceAdapter");
}
if (params.maintenanceMarginRateX18 == 0) {
revert Errors.ZeroInput("maintenanceMarginRateX18");
}
if (params.maxOpenInterest == 0) {
revert Errors.ZeroInput("maxOpenInterest");
}
if (params.maxSkew == 0) {
revert Errors.ZeroInput("maxSkew");
}
if (params.initialMarginRateX18 <= params.maintenanceMarginRateX18) {
revert Errors.InitialMarginRateLessOrEqualThanMaintenanceMarginRate();
}
if (params.skewScale == 0) {
revert Errors.ZeroInput("skewScale");
}
if (params.minTradeSizeX18 == 0) {
revert Errors.ZeroInput("minTradeSizeX18");
}
if (params.maxFundingVelocity == 0) {
revert Errors.ZeroInput("maxFundingVelocity");
}
if (params.priceFeedHeartbeatSeconds == 0) {
revert Errors.ZeroInput("priceFeedHeartbeatSeconds");
}
}
Impact
Tools Used
Manual Review
Recommendations
1). Add Zero Address Check for Keeper: Ensure that the keeper
address in SettlementConfiguration.Data
is checked to confirm it is not a zero address by adding this line of code below:
if (params.marketOrderConfiguration.keeper == address(0)) {
revert Errors.ZeroInput("keeper");
}
if (params.offchainOrdersConfiguration.keeper == address(0)) {
revert Errors.ZeroInput("keeper");
}
2). Validate Order Fees: Include checks to ensure makerFee
and takerFee
are greater than zero by adding this line of code below:
if (params.orderFees.makerFee == 0) {
revert Errors.ZeroInput("makerFee");
}
if (params.orderFees.takerFee == 0) {
revert Errors.ZeroInput("takerFee");
}
the GlobalConfigurationBranch::createPerpMarket could be updated to:
function createPerpMarket(CreatePerpMarketParams calldata params) external onlyOwner {
if (params.marketId == 0) {
revert Errors.ZeroInput("marketId");
}
if (abi.encodePacked(params.name).length == 0) {
revert Errors.ZeroInput("name");
}
if (abi.encodePacked(params.symbol).length == 0) {
revert Errors.ZeroInput("symbol");
}
if (params.priceAdapter == address(0)) {
revert Errors.ZeroInput("priceAdapter");
}
if (params.maintenanceMarginRateX18 == 0) {
revert Errors.ZeroInput("maintenanceMarginRateX18");
}
if (params.maxOpenInterest == 0) {
revert Errors.ZeroInput("maxOpenInterest");
}
if (params.maxSkew == 0) {
revert Errors.ZeroInput("maxSkew");
}
if (params.initialMarginRateX18 <= params.maintenanceMarginRateX18) {
revert Errors.InitialMarginRateLessOrEqualThanMaintenanceMarginRate();
}
if (params.skewScale == 0) {
revert Errors.ZeroInput("skewScale");
}
if (params.minTradeSizeX18 == 0) {
revert Errors.ZeroInput("minTradeSizeX18");
}
if (params.maxFundingVelocity == 0) {
revert Errors.ZeroInput("maxFundingVelocity");
}
if (params.priceFeedHeartbeatSeconds == 0) {
revert Errors.ZeroInput("priceFeedHeartbeatSeconds");
}
if (params.marketOrderConfiguration.keeper == address(0)) {
revert Errors.ZeroInput("keeper");
}
if (params.offchainOrdersConfiguration.keeper == address(0)) {
revert Errors.ZeroInput("keeper");
}
if (params.orderFees.makerFee == 0) {
revert Errors.ZeroInput("makerFee");
}
if (params.orderFees.takerFee == 0) {
revert Errors.ZeroInput("takerFee");
}
}