Liquidator can take all collateral and underlying tokens for a fraction of the correct price
When performing liquidation calculations, we use the proportion of the individual token's debt they pay off to calculate the proportion of the liquidated user's collateral and underlying tokens to send to them. In the event that the user has multiple types of debt, the liquidator will be dramatically overpaid.\\nWhen a position's risk rating falls below the underlying token's liquidation threshold, the position becomes liquidatable. At this point, anyone can call `liquidate()` and pay back a share of their debt, and receive a propotionate share of their underlying assets.\\nThis is calculated as follows:\\n```\\nuint256 oldShare = pos.debtShareOf[debtToken];\\n(uint256 amountPaid, uint256 share) = repayInternal(\\n    positionId,\\n    debtToken,\\n    amountCall\\n);\\n\\nuint256 liqSize = (pos.collateralSize * share) / oldShare;\\nuint256 uTokenSize = (pos.underlyingAmount * share) / oldShare;\\nuint256 uVaultShare = (pos.underlyingVaultShare * share) / oldShare;\\n\\npos.collateralSize -= liqSize;\\npos.underlyingAmount -= uTokenSize;\\npos.underlyingVaultShare -= uVaultShare;\\n\\n// // rest of codetransfer liqSize wrapped LP Tokens and uVaultShare underlying vault shares to the liquidator\\n}\\n```\\n\\nTo summarize:\\nThe liquidator inputs a debtToken to pay off and an amount to pay\\nWe check the amount of debt shares the position has on that debtToken\\nWe call `repayInternal()`, which pays off the position and returns the amount paid and number of shares paid off\\nWe then calculate the proportion of collateral and underlying tokens to give the liquidator\\nWe adjust the liquidated position's balances, and send the funds to the liquidator\\nThe problem comes in the calculations. The amount paid to the liquidator is calculated as:\\n```\\nuint256 liqSize = (pos.collateralSize * share) / oldShare\\nuint256 uTokenSize = (pos.underlyingAmount * share) / oldShare;\\nuint256 uVaultShare = (pos.underlyingVaultShare * share) / oldShare;\\n```\\n\\nThese calculations are taking the total size of the collateral or underlying token. They are then multiplying it by `share / oldShare`. But `share / oldShare` is just the proportion of that one type of debt that was paid off, not of the user's entire debt pool.\\nLet's walk through a specific scenario of how this might be exploited:\\nUser deposits 1mm DAI (underlying) and uses it to borrow $950k of ETH and $50k worth of ICHI (11.8k ICHI)\\nBoth assets are deposited into the ETH-ICHI pool, yielding the same collateral token\\nBoth prices crash down by 25% so the position is now liquidatable (worth $750k)\\nA liquidator pays back the full ICHI position, and the calculations above yield `pos.collateralSize * 11.8k / 11.8k` (same calculation for the other two formulas)\\nThe result is that for 11.8k ICHI (worth $37.5k after the price crash), the liquidator got all the DAI (value $1mm) and LP tokens (value $750k)
Issue Liquidator can take all collateral and underlying tokens for a fraction of the correct price\\nAdjust these calculations to use `amountPaid / getDebtValue(positionId)`, which is accurately calculate the proportion of the total debt paid off.
If a position with multiple borrows goes into liquidation, the liquidator can pay off the smallest token (guaranteed to be less than half the total value) to take the full position, stealing funds from innocent users.
```\\nuint256 oldShare = pos.debtShareOf[debtToken];\\n(uint256 amountPaid, uint256 share) = repayInternal(\\n    positionId,\\n    debtToken,\\n    amountCall\\n);\\n\\nuint256 liqSize = (pos.collateralSize * share) / oldShare;\\nuint256 uTokenSize = (pos.underlyingAmount * share) / oldShare;\\nuint256 uVaultShare = (pos.underlyingVaultShare * share) / oldShare;\\n\\npos.collateralSize -= liqSize;\\npos.underlyingAmount -= uTokenSize;\\npos.underlyingVaultShare -= uVaultShare;\\n\\n// // rest of codetransfer liqSize wrapped LP Tokens and uVaultShare underlying vault shares to the liquidator\\n}\\n```\\n