HACK ANALYSIS 5 min read

ResupplyFi Hack Analysis


ResupplyFi Hack Analysis

Overview:

On June 26, 2025, ResupplyFi (@ResupplyFi) — a decentralized lending protocol — was exploited for approximately $9.56 million. The attacker targeted the ResupplyPair contract which uses the manipulated rate, just hours after its deployment. The root cause was an exchange rate manipulation bug triggered via a classic ERC4626 “first donation” vault attack, resulting in a division-by-large-value scenario that collapsed the exchangeRate to zero.

This manipulated rate was used to compute the borrower’s Loan-to-Value (LTV) in the _isSolvent() check. Since ltv = 0 when exchangeRate = 0, the attacker bypassed the solvency check and borrowed $10 million reUSD using just 1 wei of collateral. This vulnerability falls under OWASP SC03: Logic Errors.

Smart Contract Hack Overview:

Fig: Attack Transaction

Decoding the Smart Contract Vulnerability:

  • The root cause of the vulnerability that enabled the ResupplyFi exploit stemmed from a flawed implementation of the _updateExchangeRate() and _isSolvent() functions within the ResupplyPairCore.sol contract. Specifically, the contract relied on an inverse exchange rate calculation using a price oracle tied to an ERC4626 vault (cvcrvUSD), whose share price (pricePerShare) was used directly to derive the value of collateral.
Fig: Vulnerable _updateExchangeRate() Function
  • In _updateExchangeRate(), the contract retrieves the price using an oracle call to getPrices(address(collateral)), which returns the pricePerShare of the underlying ERC4626 vault. It then inverts this price using 1e36 / price, because debt is denominated in units of collateral.
price = IOracle(_exchangeRateInfo.oracle).getPrices(address(collateral));

_exchangeRate = 1e36 / IOracle(_exchangeRateInfo.oracle).getPrices(address(collateral));
  • Because the vault was nearly empty, the attacker exploited the ERC4626 donation logic — they made a small deposit and a large donation to the vault, drastically inflating pricePerShare. As a result, the oracle returned an extremely high price.
  • This led to 1e36 / price being evaluated to 0 due to Solidity’s integer division flooring behavior. Critically, the implementation did not include any validation like require(_exchangeRate > 0), so this invalid value was saved to storage as the current exchange rate.
Fig: Vulnerable _isSolvent() Function
  • This incorrect _exchangeRate = 0 value then flowed into the _isSolvent() function, which uses the exchange rate to calculate a borrower’s Loan-to-Value (LTV) ratio.
  • The _isSolvent() function is responsible for ensuring that users cannot borrow more than they are allowed to, based on the current value of their collateral. It blindly uses the stored _exchangeRate to compute the user’s effective LTV ratio. However, if _exchangeRate is zero (as manipulated by the attacker), then the entire numerator of the LTV formula collapses to zero, and _ltv = 0.
_ltv = ((_borrowAmount * _exchangeRate * LTV_PRECISION) / EXCHANGE_PRECISION) / _collateralAmount;
  • This causes the function to always return true, regardless of how much the user is attempting to borrow, as long as they have a non-zero amount of collateral (even 1 wei). This behavior completely bypasses the core economic invariant that the borrowed amount must be backed by sufficient collateral.
  • As a result, the attacker was able to borrow $10 million worth of reUSD using just 1 wei of collateral. After swapping and redistributing the stolen funds, they successfully escaped with an estimated profit of $9.56 million, split across 2 addresses.

Attack Sequence:

Attacker deposited 1 wei into an empty cvcrvUSD ERC4626 vault, then made a large donation to artificially inflate pricePerShare.

Called borrow() on the newly deployed ResupplyPair, triggering an oracle price fetch and exchangeRate = 1e36 / price.

Due to the inflated price, exchangeRate computed to zero via Solidity floor division.

The _isSolvent() check returned true, since LTV became zero, bypassing collateral validation.

Attacker borrowed 10 million reUSD using just 1 wei of collateral, and walked away with ~$9.56 million split across multiple wallets.

Fig: Attack Sequence simplified
  • Within few hours of the exploit, ResupplyFi governance executed a series of emergency transactions (e.g., execTransaction) to zero out borrow limits and reset interest rates, as seen in UpdateRate and SetBorrowLimit events.
Fig: Mitigation events
Fig: ResupplyFi Team’s acknowledgment of the attack.

Mitigation and Best Practices:

  • Always add sanity checks like require(_exchangeRate > 0) and upper/lower bounds to prevent zero or extreme values from being written to storage due to manipulated oracle inputs or division errors.
  • Also, avoid using uninitialized or low-liquidity ERC4626 vaults as collateral or oracles. Consider enforcing a minimum liquidity threshold before a vault can be used for borrowing or price calculations.
  • Ensure a minimum borrow threshold relative to the value of collateral. And temporarily cap borrowing limits on newly deployed pairs until they are battle-tested.
  • To prevent such vulnerabilities, the best Smart Contract auditors must examine the Smart Contracts for logical issues. We at CredShields provide smart contract security and end-to-end security of web applications and externally exposed networks. Our public audit reports can be found on https://github.com/Credshields/audit-reports. Schedule a call at https://credshields.com/
  • Scan your Solidity contracts against the latest common security vulnerabilities with 494+ detections at SolidityScan.
Fig: SolidityScan — Smart Contract Vulnerability Scanner

Conclusion:

SolidityScan is an advanced smart contract scanning tool that discovers vulnerabilities and reduces risks in code. Request a security audit with us, and we will help you secure your smart contracts. Signup for a free trial at https://solidityscan.com/signup

Follow us on our Social Media for Web3 security-related updates.

SolidityScan — LinkedIn | Twitter | Telegram | Discord