Summary
In the QuantAMMWeightedPoolFactory contract, there's functions to create and deploy Pools with and without params. Both functions are using a hardcoded value "version" for pool parameter version. This oversight can confuse the devs, auditors (like us), and users and most important it may open a possibility for phishing attacks.
Vulnerability Details
QuantAMMWeightedPoolFactory::createWithoutArgs:
function createWithoutArgs(NewPoolParams memory params) external returns (address pool) {
if (params.roleAccounts.poolCreator != address(0)) {
revert StandardPoolWithCreator();
}
LiquidityManagement memory liquidityManagement = getDefaultLiquidityManagement();
liquidityManagement.enableDonation = params.enableDonation;
liquidityManagement.disableUnbalancedLiquidity = params.disableUnbalancedLiquidity;
pool = _create(
abi.encode(
QuantAMMWeightedPool.NewPoolParams({
name: params.name,
symbol: params.symbol,
numTokens: params.normalizedWeights.length,
@> version: "version",
updateWeightRunner: _updateWeightRunner,
poolRegistry: params.poolRegistry,
poolDetails: params.poolDetails
}),
getVault()
),
params.salt
);
QuantAMMWeightedPool(pool).initialize(
params._initialWeights,
params._poolSettings,
params._initialMovingAverages,
params._initialIntermediateValues,
params._oracleStalenessThreshold
);
_registerPoolWithVault(
pool,
params.tokens,
params.swapFeePercentage,
false,
params.roleAccounts,
params.poolHooksContract,
liquidityManagement
);
}
QuantAMMWeightedPoolFactory::create:
function create(NewPoolParams memory params) external returns (address pool, bytes memory poolArgs) {
if (params.roleAccounts.poolCreator != address(0)) {
revert StandardPoolWithCreator();
}
LiquidityManagement memory liquidityManagement = getDefaultLiquidityManagement();
liquidityManagement.enableDonation = params.enableDonation;
liquidityManagement.disableUnbalancedLiquidity = params.disableUnbalancedLiquidity;
poolArgs = abi.encode(
QuantAMMWeightedPool.NewPoolParams({
name: params.name,
symbol: params.symbol,
numTokens: params.normalizedWeights.length,
@> version: "version",
updateWeightRunner: _updateWeightRunner,
poolRegistry: params.poolRegistry,
poolDetails: params.poolDetails
}),
getVault()
);
pool = _create(poolArgs, params.salt);
QuantAMMWeightedPool(pool).initialize(
params._initialWeights,
params._poolSettings,
params._initialMovingAverages,
params._initialIntermediateValues,
params._oracleStalenessThreshold
);
_registerPoolWithVault(
pool,
params.tokens,
params.swapFeePercentage,
false,
params.roleAccounts,
params.poolHooksContract,
liquidityManagement
);
}
Impact
Tools Used
Manual review
Recommendations
Mitigations
One possible solution:
QuantAMMWeightedPoolFactory::createWithoutArgs:
function createWithoutArgs(NewPoolParams memory params) external returns (address pool) {
.
.
...
// disableUnbalancedLiquidity must be set to true if a hook has the flag enableHookAdjustedAmounts = true.
liquidityManagement.disableUnbalancedLiquidity = params.disableUnbalancedLiquidity;
pool = _create(
abi.encode(
QuantAMMWeightedPool.NewPoolParams({
name: params.name,
symbol: params.symbol,
numTokens: params.normalizedWeights.length,
- version: "version",
+ version: _poolVersion,
updateWeightRunner: _updateWeightRunner,
poolRegistry: params.poolRegistry,
poolDetails: params.poolDetails
}),
getVault()
),
params.salt
);
.
.
...
}
QuantAMMWeightedPoolFactory::create:
function create(NewPoolParams memory params) external returns (address pool, bytes memory poolArgs) {
.
.
...
liquidityManagement.disableUnbalancedLiquidity = params.disableUnbalancedLiquidity;
poolArgs = abi.encode(
QuantAMMWeightedPool.NewPoolParams({
name: params.name,
symbol: params.symbol,
numTokens: params.normalizedWeights.length,
- version: "version",
+ version: _poolVersion,
updateWeightRunner: _updateWeightRunner,
poolRegistry: params.poolRegistry,
poolDetails: params.poolDetails
}),
getVault()
);
pool = _create(poolArgs, params.salt);
.
.
...
}
Another possible solution:
QuantAMMWeightedPoolFactory::createWithoutArgs:
function createWithoutArgs(NewPoolParams memory params) external returns (address pool) {
.
.
...
// disableUnbalancedLiquidity must be set to true if a hook has the flag enableHookAdjustedAmounts = true.
liquidityManagement.disableUnbalancedLiquidity = params.disableUnbalancedLiquidity;
pool = _create(
abi.encode(
QuantAMMWeightedPool.NewPoolParams({
name: params.name,
symbol: params.symbol,
numTokens: params.normalizedWeights.length,
- version: "version",
+ version: params.version,
updateWeightRunner: _updateWeightRunner,
poolRegistry: params.poolRegistry,
poolDetails: params.poolDetails
}),
getVault()
),
params.salt
);
.
.
...
}
QuantAMMWeightedPoolFactory::create:
function create(NewPoolParams memory params) external returns (address pool, bytes memory poolArgs) {
.
.
...
liquidityManagement.disableUnbalancedLiquidity = params.disableUnbalancedLiquidity;
poolArgs = abi.encode(
QuantAMMWeightedPool.NewPoolParams({
name: params.name,
symbol: params.symbol,
numTokens: params.normalizedWeights.length,
- version: "version",
+ version: params.version,
updateWeightRunner: _updateWeightRunner,
poolRegistry: params.poolRegistry,
poolDetails: params.poolDetails
}),
getVault()
);
pool = _create(poolArgs, params.salt);
.
.
...
}