Reports

Smart Contract Security Assessment

Resupply Update Report

Resupply Finance is a CDP-based lending protocol that allows simple, low-risk, leveraged yield farming while encouraging the use of value-added ecosystem protocols' underlying stables like Curve's crvUSD and Frax's FRAX.

4
Issues
0
C/H/M
Period
Jul 14, 2025 - Jul 15, 2025
Auditors
Adriro, HHK

Review Summary

Protocol Overview

Resupply Finance is a CDP-based lending protocol that allows simple, low-risk, leveraged yield farming while encouraging the use of value-added ecosystem protocols' underlying stables like Curve's crvUSD and Frax's FRAX.

Protocol
Resupply
Timeline
Jul 14, 2025 - Jul 15, 2025
Audit Team
Adriro, HHK

Audit Overview

Scope and Resources

Scope

This audit covers the changes made to the ResupplyPairCore and ResupplyPairDeployer contracts, along with the new BorrowLimitController.

Overall Assessment

This update includes post-exchange rate issue fixes, an updated deployer, and a new contract called BorrowLimitController used to slowly increase pairs' borrowing caps over time.

Evaluation Matrix

access control

mathematics

complexity

libraries

decentralization

code stability

documentation

monitoring

testing

Key Findings

Findings Summary

0
Critical
0
High
0
Medium
0
Low
4
Informational
0
Gas
I-1 Finding

I-1: Missing burn amount checks in `updateSupportedProtocol()`

Informational

Description:

The sanity checks over amountToBurn and minShareBurnAmount applied in addSupportedProtocol() are missing while config is updated in updateSupportedProtocol().

Impact:

Informational.

Recommendation:

Add the sanity checks to updateSupportedProtocol().

Developer Response:

Fixed in f6da20f.

I-2 Finding

I-2: Current deployer is not registered in ResupplyRegistry

Informational

Summary:

The current deployer contract isn't registered in the main registry, skipping the migration logic in the new deployer.

Description:

The new ResupplyPairDeployer contract performs a state migration from the previous deployer during construction.

139:         address _previousPairDeployer = IResupplyRegistry(registry).getAddress("DEPLOYER");
140:         if(_previousPairDeployer != address(0)) {
141:             _migrateState(_previousPairDeployer);
142:         }

Currently, the registry (0x10101010E0C3171D894B71B3400668aF311e7D94) doesn't contain the "DEPLOYER" key, causing the migration logic to be skipped.

Impact:

Informational.

Recommendation:

Ensure the current deployer contract is registered to enable the migration mechanism when the new deployer contract is created.

Developer Response:

Pair deployer registry check updated to look for PAIR_DEPLOYER key: 7445002.

PAIR_DEPLOYER key set on registry via this transaction: 0xe644dc0e44ec6d4f51ccf9d8966d63f0bcc3edfe26ab93e499d87169d63331f7.

I-3 Finding

I-3: `_migrateState()` could assign the wrong protocol id

Informational

Description:

Inside _migrateState() the function loops through supportedProtocols and run getBorrowAndCollateralTokens() to find which protocol id was used for that pair, then it sets the storage mapping to _deployer.collateralId().

However if two supportedProtocols have the same methods to query the _borrowToken and _collateralToken then the loop will exit early and use the first matching protocol's id to get _deployer.collateralId() and store it.

Currently only Frax and Curve are being used and their methods are different so this will happen only if new protocols are supported in the future.

Impact:

Informational. If the deployer is migrated again with new supported protocols then the mapping may be incorrectly migrated.

Recommendation:

Check that _deployer.collateralId() > 0 inside the if(_borrowToken != address(0) && _collateralToken != address(0)) condition.

Developer Response:

Agree, this could be an issue if a future supported protocol was added with conflicting selectors. That will not happen before we upgrade the deployer, but nonetheless have re-worked the _migrateState() flow a bit: 7445002.

I-4 Finding

I-4: Delegate exchange rate threshold to the Oracle implementation

Informational

Summary:

Instead of hardcoding an arbitrary limit in the pair implementation, it could be more flexible to delegate this logic to the Oracle implementation.

Description:

The updated implementation of _updateExchangeRate() implements a hardcoded limit to detect Oracle manipulation attempts.

571:         // Get the latest exchange rate from the oracle
572:         uint256 priceFromOracle = IOracle(_exchangeRateInfo.oracle).getPrices(address(collateral));
573:         //all prices should *normally* be within the 1e18 (or 1e15 for curvelend) range
574:         //reject any prices that are well beyond that
575:         if(priceFromOracle > 1e22){
576:             revert InvalidOraclePrice();
577:         }

While this threshold has been acknowledged by the team as a reasonable limit for the share price, moving this check to the Oracle would improve flexibility as this implementation can be eventually updated in the pair.

Note that this check is not present in other occurrences in the codebase where getPrices() is used, such as previewRedeem() in RedemptionHandler or isSolvent() in the Utilities contract.

Impact:

Informational.

Recommendation:

Delegating this logic to the Oracle would allow different strategies, for example:

  • Create an Oracle with a configurable limit.
  • Define an Oracle for each protocol to adapt to potential pricing particularities (e.g. account for the 1e15 / 1e18 difference in Curve and Frax).
  • Implement more advance strategies such a time-weighted Oracle or a dual Oracle.

Developer Response:

Updated Core and Basic Vault Oracle here: c6a80f0.

Final Remarks

Overall, the protocol demonstrates good security practices and code quality. The team has been responsive to feedback and has implemented most recommendations. We recommend addressing the identified issues before mainnet deployment.

Methodology

Severity Classification

Critical

Immediate threat to user funds or protocol integrity

Direct loss of funds, protocol compromise

High

Significant security risk requiring urgent attention

Potential fund loss, major functionality disruption

Medium

Important issue that should be addressed

Limited fund risk, functionality concerns

Low

Minor issue with minimal impact

Best practice violations, minor inefficiencies

Gas

Findings that improve gas efficiency

Increased transaction costs

Informational

Code quality and best practice recommendations

Reduced maintainability and readability