Vulnerability Details
In the create function below , it never checks the params.tokens
which is a TokenConfig
struct ever :
https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-quantamm/contracts/QuantAMMWeightedPoolFactory.sol#L85-L125
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
);
}
TokenConfig struct is as :
https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/interfaces/contracts/vault/VaultTypes.sol#L211-L216
struct TokenConfig {
IERC20 token;
TokenType tokenType;
IRateProvider rateProvider;
bool paysYieldFees;
}
Here if the Pool Creator gives tokenType as WITH_RATE
instead of STANDARD
, then many of the important operations of the Pool with the Vault will revert, as the QuantAMMWeightedPool has a revert in getRate
function
https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/pool-quantamm/contracts/QuantAMMWeightedPool.sol#L823-L825
function getRate() public pure override returns (uint256) {
revert WeightedPoolBptRateUnsupported();
}
And this getRate
function is used in getTokenRate
https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/vault/contracts/lib/PoolDataLib.sol#L151-L162
function getTokenRate(TokenInfo memory tokenInfo) internal view returns (uint256 rate) {
TokenType tokenType = tokenInfo.tokenType;
if (tokenType == TokenType.STANDARD) {
rate = FixedPoint.ONE;
} else if (tokenType == TokenType.WITH_RATE) {
rate = tokenInfo.rateProvider.getRate();
} else {
revert IVaultErrors.InvalidTokenConfiguration();
}
}
which is indeed used in load and reload functions of the Vault :
https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/vault/contracts/lib/PoolDataLib.sol#L57-L58
poolData.tokenInfo[i] = tokenInfo;
poolData.tokenRates[i] = getTokenRate(tokenInfo);
https://github.com/Cyfrin/2024-12-quantamm/blob/a775db4273eb36e7b4536c5b60207c9f17541b92/pkg/vault/contracts/lib/PoolDataLib.sol#L141-L145
for (uint256 i = 0; i < numTokens; ++i) {
poolData.tokenRates[i] = getTokenRate(poolData.tokenInfo[i]);
packedBalance = poolTokenBalances[i];
possibly blocking the swapping , adding and remove liquidity functionality to the Vault .
Tools Used
Manual Review
Recommendations
Allow only the STANDARD
type tokens to be created in the QuantAMMWeightedPoolFactory