resupply-lending
This skill should be used when the user asks about "ResupplyPair", "lending pair", "borrow reUSD", "add collateral", "remove collateral", "repay debt", "interest rates", "leveraged positions", or needs to understand Resupply's core lending mechanics.
SKILL.md
| Name | resupply-lending |
| Description | This skill should be used when the user asks about "ResupplyPair", "lending pair", "borrow reUSD", "add collateral", "remove collateral", "repay debt", "interest rates", "leveraged positions", or needs to understand Resupply's core lending mechanics. |
name: resupply-lending description: This skill should be used when the user asks about "ResupplyPair", "lending pair", "borrow reUSD", "add collateral", "remove collateral", "repay debt", "interest rates", "leveraged positions", or needs to understand Resupply's core lending mechanics.
Resupply Lending System
The lending system is built around ResupplyPair contracts that enable users to deposit ERC4626 vault tokens as collateral and borrow reUSD stablecoins.
ResupplyPair Contract
Located at /src/protocol/ResupplyPair.sol with core logic in /src/protocol/pair/ResupplyPairCore.sol.
State Structure
// Collateral tracking
mapping(address => uint256) public userCollateralBalance; // User → collateral amount
uint256 public totalCollateral;
// Borrow tracking (share-based for interest accrual)
mapping(address => uint256) public userBorrowShares; // User → borrow shares
uint256 public totalBorrowShares;
uint256 public totalBorrowAmount; // Actual debt amount
// Configuration
address public collateralContract; // ERC4626 vault token
address public asset; // reUSD stablecoin
uint256 public maxLTV; // e.g., 95_000 (95% with LTV_PRECISION)
uint256 public liquidationFee; // e.g., 5_000 (5%)
uint256 public borrowLimit; // Maximum borrowable amount
Core Operations
Adding Collateral
Deposit ERC4626 vault tokens as collateral:
function addCollateralVault(uint256 _collateralAmount, address _borrower) external {
// Transfer vault tokens from caller
IERC20(collateralContract).safeTransferFrom(msg.sender, address(this), _collateralAmount);
// Update balances
userCollateralBalance[_borrower] += _collateralAmount;
totalCollateral += _collateralAmount;
}
Removing Collateral
Withdraw collateral (must maintain health factor):
function removeCollateralVault(uint256 _collateralAmount, address _receiver) external {
// Update balances
userCollateralBalance[msg.sender] -= _collateralAmount;
totalCollateral -= _collateralAmount;
// Verify position remains healthy
require(_isSolvent(msg.sender), "Position unhealthy");
// Transfer vault tokens
IERC20(collateralContract).safeTransfer(_receiver, _collateralAmount);
}
Borrowing
Mint reUSD against deposited collateral:
function borrow(
uint256 _borrowAmount,
uint256 _underlyingAmount, // For minting to underlying protocols
address _receiver
) external returns (uint256 shares) {
// Accrue interest first
_accrue();
// Calculate borrow shares
shares = totalBorrowShares == 0
? _borrowAmount
: (_borrowAmount * totalBorrowShares) / totalBorrowAmount;
// Update state
userBorrowShares[msg.sender] += shares;
totalBorrowShares += shares;
totalBorrowAmount += _borrowAmount;
// Verify solvency
require(_isSolvent(msg.sender), "Position unhealthy");
// Mint reUSD
IStablecoin(asset).mint(_receiver, _borrowAmount);
}
Repaying
Burn reUSD to reduce debt:
function repay(uint256 _shares, address _borrower) external returns (uint256 amountRepaid) {
_accrue();
// Calculate amount from shares
amountRepaid = (_shares * totalBorrowAmount) / totalBorrowShares;
// Update state
userBorrowShares[_borrower] -= _shares;
totalBorrowShares -= _shares;
totalBorrowAmount -= amountRepaid;
// Burn reUSD from caller
IStablecoin(asset).burn(msg.sender, amountRepaid);
}
Interest Rate Model
Interest accrues per-second based on utilization:
// InterestRateCalculator interface
function getNewRate(
uint256 _currentRate,
uint256 _utilization, // totalBorrow / borrowLimit
uint256 _deltaTime
) external view returns (uint256 newRate);
Utilization calculation:
uint256 utilization = (totalBorrowAmount * 1e18) / borrowLimit;
Interest accrual:
function _accrue() internal {
uint256 deltaTime = block.timestamp - lastAccrueTime;
uint256 interestEarned = (totalBorrowAmount * currentRate * deltaTime) / RATE_PRECISION;
totalBorrowAmount += interestEarned;
lastAccrueTime = block.timestamp;
}
Collateral Valuation
The oracle converts vault tokens to asset value:
// BasicVaultOracle
function getPrice(address collateral) external view returns (uint256) {
// Get ERC4626 exchange rate
uint256 assetsPerShare = IERC4626(collateral).convertToAssets(1e18);
return assetsPerShare;
}
Solvency check:
function _isSolvent(address _borrower) internal view returns (bool) {
uint256 collateralValue = (userCollateralBalance[_borrower] * oracle.getPrice(collateralContract)) / EXCHANGE_PRECISION;
uint256 borrowValue = (userBorrowShares[_borrower] * totalBorrowAmount) / totalBorrowShares;
// LTV check: borrowValue <= collateralValue * maxLTV / LTV_PRECISION
return borrowValue * LTV_PRECISION <= collateralValue * maxLTV;
}
Advanced Operations
Leveraged Positions
Increase exposure in a single transaction:
function leveragedPosition(
address _swapperAddress,
uint256 _borrowAmount,
uint256 _minCollateralReceived,
bytes calldata _swapData
) external returns (uint256 collateralReceived);
Flow:
- Borrow reUSD
- Swap reUSD → collateral via swapper
- Add swapped collateral to position
Repay with Collateral
Reduce debt using collateral:
function repayWithCollateral(
address _swapperAddress,
uint256 _collateralToSwap,
uint256 _minAssetReceived,
bytes calldata _swapData
) external returns (uint256 assetReceived);
Flow:
- Remove collateral
- Swap collateral → reUSD via swapper
- Repay debt with swapped reUSD
Pair Configuration
Pairs are deployed with specific parameters:
struct ConfigData {
address oracle; // Price oracle
address rateCalculator; // Interest rate model
uint256 maxLTV; // e.g., 95_000 (95%)
uint256 initialBorrowLimit; // e.g., 1_000_000e18
uint256 liquidationFee; // e.g., 5_000 (5%)
uint256 mintFee; // Borrow fee
uint256 protocolRedemptionFee;
}
Reward Distribution
Pairs distribute multiple reward tokens to borrowers:
// Claim rewards
function getReward(address _account, address _forwardTo) external;
// Reward tokens can include: RSUP, CRV, CVX
Additional Resources
For the complete IResupplyPair interface with all functions and events, see references/pair-interface.md.