Polynomial Protocol contest - csanuragjain's results

The DeFi Derivatives Powerhouse.

General Information

Platform: Code4rena

Start Date: 13/03/2023

Pot Size: $72,500 USDC

Total HM: 33

Participants: 35

Period: 7 days

Judge: Dravee

Total Solo HM: 16

Id: 222

League: ETH

Polynomial Protocol

Findings Distribution

Researcher Performance

Rank: 22/35

Findings: 2

Award: $241.84

🌟 Selected for report: 1

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: MiloTruck

Also found by: adriro, bin2chen, chaduke, csanuragjain

Labels

bug
2 (Med Risk)
satisfactory
duplicate-236

Awards

105.1468 USDC - $105.15

External Links

Lines of code

https://github.com/code-423n4/2023-03-polynomial/blob/main/src/Exchange.sol#L340

Vulnerability details

Impact

If a user debt is higher than his overall collateral balance then user will never be liquidated as liquidator would be at loss (liquidatee does not have required balanace to pay liquidator)

Proof of Concept

  1. Assume User A safetyRatio has fallen below WIPEOUT_CUTOFF. This means the position can be liquidated by any other user

  2. User B sees the opportunity and liquidate User A

  3. This calls below liquidate function

function liquidate(uint256 positionId, uint256 debt, address user)
        external
        override
        onlyExchange
        nonReentrant
        returns (uint256 totalCollateralReturned)
    {
...
uint256 collateralClaim = debt.mulDivDown(markPrice, collateralPrice);
        uint256 liqBonus = collateralClaim.mulWadDown(coll.liqBonus);
        totalCollateralReturned = liqBonus + collateralClaim;
        if (totalCollateralReturned > userCollateral.amount) totalCollateralReturned = userCollateral.amount;
        userCollateral.amount -= totalCollateralReturned;

        ERC20(userCollateral.collateral).safeTransfer(user, totalCollateralReturned);
...
}
  1. Let's say for debt X, the collateralClaim came out to be Y. If coll.liqBonus was Z then overall collateral required would be YZ for X debt

  2. Now if userCollateral.amount is YZ-10 then overall collateral required would be reduced from YZ to YZ-10

if (totalCollateralReturned > userCollateral.amount) totalCollateralReturned = userCollateral.amount;
        userCollateral.amount -= totalCollateralReturned;
  1. This means liquidator will be paid off YZ-10 when he was expecting YZ, bringing him to an overall loss of 10
ERC20(userCollateral.collateral).safeTransfer(user, totalCollateralReturned);
  1. If Liquidator was cautious enough to not liquidate such positions then User A will not be liquidated by anyone and debt will not be cleared up

Ensure that liquidator is always in benefit on liquidation event.

#0 - c4-judge

2023-03-24T11:37:01Z

JustDravee marked the issue as duplicate of #236

#1 - c4-judge

2023-05-03T00:01:18Z

JustDravee marked the issue as satisfactory

Findings Information

🌟 Selected for report: csanuragjain

Also found by: DadeKuma, KIntern_NA, bytes032, rbserver

Labels

bug
2 (Med Risk)
primary issue
satisfactory
selected for report
sponsor confirmed
M-19

Awards

136.6909 USDC - $136.69

External Links

Lines of code

https://github.com/code-423n4/2023-03-polynomial/blob/main/src/ShortCollateral.sol#L262

Vulnerability details

Impact

If an approved collateral has later started say taking fees on transfer then protocol has no way to remove such collateral. The current deposit logic cannot handle fee on transfer token and would give more funds to user then actually obtained by contract

Proof of Concept

  1. Assume protocol was supporting collateral X (say USDT which has fee currently set as 0)
  2. After some time collateral introduces fee on transfer
  3. Protocol does not have a way to remove a whitelisted collateral
  4. Problem begins once user starts depositing such collateral
function _addCollateral(uint256 positionId, uint256 amount) internal { ... ERC20(shortPosition.collateral).safeTransferFrom(msg.sender, address(this), amount); ERC20(shortPosition.collateral).safeApprove(address(shortCollateral), amount); shortToken.adjustPosition( positionId, msg.sender, shortPosition.collateral, shortPosition.shortAmount, shortPosition.collateralAmount + amount ); shortCollateral.collectCollateral(shortPosition.collateral, positionId, amount); ... }
  1. In this case amount is transferred from user to contract but contract will only receive amount-fees. But contract will still adjust position with full amount instead of amount-fees which is incorrect

Add a way to disapprove collateral so that if in future some policy changes for a particular collateral, protocol can stop supporting it. This will it would only have to deal with existing collateral which can be wiped out slowly using public announcement

#0 - JustDravee

2023-03-22T06:33:28Z

Not a dup of https://github.com/code-423n4/2023-03-polynomial-findings/issues/178 as Fee-on-transfer tokens are only mentioned as a scenario that may make the protocol want to disapprove a collateral.

Due to a real lack of way to disapprove a collateral, I believe this finding is valid

#1 - c4-judge

2023-03-22T06:33:35Z

JustDravee marked the issue as satisfactory

#2 - c4-judge

2023-03-22T07:25:47Z

JustDravee marked the issue as primary issue

#3 - c4-sponsor

2023-04-05T07:44:43Z

mubaris marked the issue as sponsor confirmed

#4 - c4-judge

2023-05-03T02:00:58Z

JustDravee marked the issue as selected for report

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter