Incorrect decimalOffset causes the share-per-asset ratio to be 1 instead of 10^offset.
The vault's decimals function returns 18, while in reality has same decimals as the underlying asset.
When a ZlpVault is initialized, it sets decimalOffset. Since the SYSTEM_DECIMALS is 18, it's safe to assume decimalOffset will be set to 18 - underlying token decimals.
ZlpVault overrides _decimalsOffset(), which is used by the OpenZeppelin (OZ) implementation to calculate the vault's decimals, resulting in 18.
The ERC-4626 OZ implementation uses decimalOffset to protect against so-called "inflation attacks."
The protocol overrides _convertToAssets and _convertToShares to implement custom logic.
These functions call getIndexTokenSwapRate and getVaultAssetSwapRate, respectively(1, 2). However, the problem is that these functions use a different value for decimalOffset.
The newly calculated decimalOffset is 0, meaning the share-per-asset ratio becomes 1 instead of 10^offset.
While this still offers protection against inflation attacks (if the offset is 0, the attacker's loss is at least equal to the users', as noted here), the vault's decimals function returns 18, whereas in reality, it matches the underlying asset's decimals.
Smaller protection against inflation attack for vaults with assets with less than 18 decimals;
Vault decimals misrepresentation. It could represent an external risk in case of vault's integration with other protocols.
Ensure consistency in how decimalOffset is used acros functions.
Modify getIndexTokenSwapRate and getVaultAssetSwapRate to correctly derive decimalOffset from the underlying token, or better, read it directly from zlpVault.
Consider setting zlpVaultStorage.decimalsOffset to SYSTEM_DECIMALS - underlyingAssetDecimals.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.