Badger eBTC Audit + Certora Formal Verification Competition - SpicyMeatball's results

Use stETH to borrow Bitcoin with 0% fees | The only smart contract based #BTC.

General Information

Platform: Code4rena

Start Date: 24/10/2023

Pot Size: $149,725 USDC

Total HM: 7

Participants: 52

Period: 21 days

Judge: ronnyx2017

Total Solo HM: 2

Id: 300

League: ETH

eBTC Protocol

Findings Distribution

Researcher Performance

Rank: 7/52

Findings: 2

Award: $4,658.25

QA:
grade-a

๐ŸŒŸ Selected for report: 1

๐Ÿš€ Solo Findings: 0

Findings Information

๐ŸŒŸ Selected for report: Stormy

Also found by: SpicyMeatball

Labels

bug
3 (High Risk)
partial-25
sufficient quality report
upgraded by judge
duplicate-323

Awards

4505.4922 USDC - $4,505.49

External Links

Lines of code

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L599-L602

Vulnerability details

Impact

Users can use LeverageMacro contracts to aggregate and execute multiple operations like taking a flashloan, swapping tokens and opening a CDP in one transaction. There are currently two types of macros:

  • LeverageMacroDelegateTarget - called with delegateCall from a user's smart wallet
  • LeverageMacroReference - a standalone contract that users interact with directly In the case of LeverageMacroReference when the user opens a CDP the borrower will be a msg.sender i.e. LeverageMacro
function _openCdpCallback(bytes memory data) internal { OpenCdpOperation memory flData = abi.decode(data, (OpenCdpOperation)); /** * Open CDP and Emit event */ bytes32 _cdpId = borrowerOperations.openCdp( flData.eBTCToMint, flData._upperHint, flData._lowerHint, flData.stETHToDeposit ); }

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L174

If this CDP is later liquidated or redeemed, the surplus will only be available to the borrower

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/CdpManager.sol#L257 https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/LiquidationLibrary.sol#L337

Unfortunately it is pretty much impossible to call claimSurplusCollShares from the LeverageMacroReference

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L599-L602

users can try to encode the call in one of the SwapOperations to execute it with excessivelySafeCall, but first they need to use one of the required operations, which is not very practical

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/LeverageMacroBase.sol#L298-L304

As a result the surplus received from redeeming/liquidating will be unavailable to the user.

Proof of Concept

See above

Tools Used

Manual review

Include address borrower into OpenCdpOperation struct https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/LeverageMacroBase.sol#L313 thus user can specify his address as a borrower and make LeverageMacroReference his approved position manager. Later he will be able to claim surplus using his EOA wallet. Also it will be a good idea to allow approved position managers to claim surplus on borrowers behalf.

Assessed type

Context

#0 - c4-pre-sort

2023-11-17T07:28:35Z

bytes032 marked the issue as sufficient quality report

#1 - c4-pre-sort

2023-11-17T07:28:44Z

bytes032 marked the issue as duplicate of #323

#2 - c4-judge

2023-11-27T09:06:41Z

jhsagd76 changed the severity to 3 (High Risk)

#3 - c4-judge

2023-11-27T09:06:56Z

jhsagd76 marked the issue as satisfactory

#4 - CodingNameKiki

2023-12-05T21:57:19Z

Hey @jhsagd76 , l was going over the selected reports and their duplicates for a final look and l came across this report, l am not very up to date with the latest c4 rules around issues so l wanted to mention it to you.

Basically as stated in the selected report our issue arrives from the fact that LeverageMacro canโ€™t make a call to borrower operations in order for the LeverageMacro to claim the surplus coll. This is a fact as in the function excessivelySafeCall the LeverageMacro specifically performs couple of checks to ensure that any calls made to the ebtc contracts are reverted.

users can try to encode the call in one of the SwapOperations to execute it with excessivelySafeCall, but first they need to use one of the required operations, which is not very practical

However if we look at the statement above in this report, we can see that the warden didnโ€™t find the core issue that the LeverageMacro canโ€™t make a call to the ebtc contracts to claim the surplus but rather reported it as there is no functionality for that and which is why l think this issue was originally reported as a medium.

#5 - jhsagd76

2023-12-06T01:37:55Z

Nice catch! This report missed the most important check in the _ensureNotSystem function https://github.com/code-423n4/2023-10-badger/blob/2bacb215bf3257320e4f6dd7dcb039f1f06f3214/packages/contracts/contracts/LeverageMacroBase.sol#L401-L415 , change to 25% rewards. Because it pointed out a part of the issue.

#6 - c4-judge

2023-12-06T01:38:38Z

jhsagd76 marked the issue as partial-25

Awards

152.7604 USDC - $152.76

Labels

bug
grade-a
QA (Quality Assurance)
selected for report
sufficient quality report
Q-25

External Links

Redundant check

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/LiquidationLibrary.sol#L863 _redistributeDebt will never be called if debt = 0 https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/LiquidationLibrary.sol#L525-L527

BaseMath is not used

PriceFeed contract inherits from BaseMath but doesn't use it's single constant DECIMAL_PRECISION, so it's possible to remove it.

Unused modifier

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/EBTCToken.sol#L323 this modifier is not used in EBTCTokem.sol

Double checking recipient != address(0)

Before transferring tokens we invoke _requireValidRecipient, where among many checks we check that recipient != address(0), https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/EBTCToken.sol#L297 same check is made inside _transfer function https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/EBTCToken.sol#L248

Enforce beta is not zero

Authorized users can change beta value https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/CdpManager.sol#L830 if it's set to zero. we'll divide by zero here https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/CdpManager.sol#L624

arrayIndex value is not deleted when we remove cpd

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/CdpManagerStorage.sol#L269-L274 https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/CdpManagerStorage.sol#L471 When we remove cpd, we zero all it's values, but arrayIndex remains.

UpdateManager?

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L963 Borrower can approve operations to the PositionManager, UpdateManager is not mentioned anywhere in the contract. _requireBorrowerOrPositionManagerApproval would be more clear.

Hash value names inconsistency

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L33-L35 we use

keccak256( "PermitPositionManagerApproval(address borrower,address positionManager,uint8 status,uint256 nonce,uint256 deadline)" );

but in permitPositionManagerApproval we use approval instead of status
https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L709

Consider using enum values instead of numbers

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L826 https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L831

status == ICdpManagerData.Status.active status == ICdpManagerData.Status.nonExistent

It would be more appropriate to use syncGlobalAccountingAndGracePeriod

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L1146 https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L1157 https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L1168

Here we update global system parameters but we use syncGlobalAccounting which doesn't trigger recovery mode if TCR becomes less than CCR, unlike syncGlobalAccountingAndGracePeriod.

function syncGlobalAccounting() external { _requireCallerIsBorrowerOperations(); _syncGlobalAccounting(); }
function syncGlobalAccountingAndGracePeriod() public { _syncGlobalAccounting(); // Apply // Could trigger RM _syncGracePeriod(); // Synch Grace Period }

Typos, wrong comments and naming

  1. These comments are copy-pasted from Auth.sol, we don't check the owner here

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/Dependencies/AuthNoOwner.sol#L33-L34 https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/Dependencies/AuthNoOwner.sol#L39-L40

  1. Fee floor is actually 0%

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/Dependencies/EbtcBase.sol#L35

  1. Entire system debt

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/Dependencies/EbtcBase.sol#L73

  1. Memorizing typo

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/Dependencies/Auth.sol#L33

  1. sending EBTC directly to a Liquity

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/EBTCToken.sol#L22

  1. _NICR would be more appropriate name

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/HintHelpers.sol#L165

CR is associated with collateral ratio, however in this function we use NICR values to find a hint

  1. Wrong pair names in comments

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/PriceFeed.sol#L784 https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/PriceFeed.sol#L786 should be stETH-ETH feed

  1. ETH-USD comment from Liquity

https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/CdpManager.sol#L594

should be stETH-BTC

#0 - c4-pre-sort

2023-11-17T13:26:32Z

bytes032 marked the issue as sufficient quality report

#1 - c4-judge

2023-11-27T10:26:12Z

jhsagd76 marked the issue as grade-a

#2 - jhsagd76

2023-11-28T10:14:54Z

8L+8N + 2S -6 = 31

25

#3 - c4-judge

2023-11-28T10:15:01Z

jhsagd76 marked the issue as selected for report

#4 - jhsagd76

2023-11-28T10:21:36Z

This one is invalid:

UpdateManager? https://github.com/code-423n4/2023-10-badger/blob/main/packages/contracts/contracts/BorrowerOperations.sol#L963 Borrower can approve operations to the PositionManager, UpdateManager is not mentioned anywhere in the contract. _requireBorrowerOrPositionManagerApproval would be more clear.

This one is for gas op, out of scope

Double checking recipient != address(0)

The 8 issues in the section "Typos, wrong comments and naming" is NC. Other issues are L.

#5 - jhsagd76

2023-11-28T10:26:06Z

There are some other QA issues downgraded from H/M can be also added to the report: #159, #244, #224, #73, #70 , #185, #151, #112, #17 , #261, #150

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