编译器
0.8.28+commit.7893614a
文件 1 的 31:Address.sol
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
library Address {
error AddressEmptyCode(address target);
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert Errors.FailedCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}
文件 2 的 31:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
文件 3 的 31:CoreOwnable.sol
pragma solidity 0.8.28;
import {ICore} from "../interfaces/ICore.sol";
contract CoreOwnable {
ICore public immutable core;
constructor(address _core) {
core = ICore(_core);
}
modifier onlyOwner() {
require(msg.sender == address(core), "!core");
_;
}
function owner() public view returns (address) {
return address(core);
}
}
文件 4 的 31:ERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual returns (string memory) {
return _name;
}
function symbol() public view virtual returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return 18;
}
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
_totalSupply -= value;
}
} else {
unchecked {
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
文件 5 的 31:EpochTracker.sol
pragma solidity 0.8.28;
import "../interfaces/ICore.sol";
contract EpochTracker {
uint256 public immutable startTime;
uint256 public immutable epochLength;
constructor(address _core) {
startTime = ICore(_core).startTime();
epochLength = ICore(_core).epochLength();
}
function getEpoch() public view returns (uint256 epoch) {
return (block.timestamp - startTime) / epochLength;
}
}
文件 6 的 31:Errors.sol
pragma solidity ^0.8.20;
library Errors {
error InsufficientBalance(uint256 balance, uint256 needed);
error FailedCall();
error FailedDeployment();
error MissingPrecompile(address);
}
文件 7 的 31:IAuthHook.sol
pragma solidity 0.8.28;
interface IAuthHook {
function preHook(address operator, address target, bytes calldata data) external returns (bool);
function postHook(bytes memory result, address operator, address target, bytes calldata data) external returns (bool);
}
文件 8 的 31:IConvexStaking.sol
pragma solidity 0.8.28;
interface IConvexStaking {
function poolInfo(uint256 _pid) external view returns(
address lptoken,
address token,
address gauge,
address crvRewards,
address stash,
bool shutdown
);
function deposit(uint256 _pid, uint256 _amount, bool _stake) external returns(bool);
function depositAll(uint256 _pid, bool _stake) external returns(bool);
function withdrawAndUnwrap(uint256 amount, bool claim) external returns(bool);
function withdrawAllAndUnwrap(bool claim) external;
function getReward() external returns(bool);
function getReward(address _account, bool _claimExtras) external returns(bool);
function totalSupply() external view returns (uint256);
function extraRewardsLength() external view returns (uint256);
function extraRewards(uint256 _rid) external view returns (address _rewardContract);
function rewardToken() external view returns (address _rewardToken);
function token() external view returns (address _token);
function balanceOf(address account) external view returns (uint256);
}
文件 9 的 31:ICore.sol
pragma solidity 0.8.28;
import { IAuthHook } from './IAuthHook.sol';
interface ICore {
struct OperatorAuth {
bool authorized;
IAuthHook hook;
}
event VoterSet(address indexed newVoter);
event OperatorExecuted(address indexed caller, address indexed target, bytes data);
event OperatorSet(address indexed caller, address indexed target, bool authorized, bytes4 selector, IAuthHook authHook);
function execute(address target, bytes calldata data) external returns (bytes memory);
function epochLength() external view returns (uint256);
function startTime() external view returns (uint256);
function voter() external view returns (address);
function ownershipTransferDeadline() external view returns (uint256);
function pendingOwner() external view returns (address);
function setOperatorPermissions(
address caller,
address target,
bytes4 selector,
bool authorized,
IAuthHook authHook
) external;
function setVoter(address newVoter) external;
function operatorPermissions(address caller, address target, bytes4 selector) external view returns (bool authorized, IAuthHook hook);
}
文件 10 的 31:IERC1363.sol
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
interface IERC1363 is IERC20, IERC165 {
function transferAndCall(address to, uint256 value) external returns (bool);
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
function approveAndCall(address spender, uint256 value) external returns (bool);
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}
文件 11 的 31:IERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
文件 12 的 31:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 13 的 31:IERC20Metadata.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 14 的 31:IERC4626.sol
pragma solidity 0.8.28;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed caller,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
function asset() external view returns (address);
function convertToAssets(uint256 shares) external view returns (uint256);
function convertToShares(uint256 assets) external view returns (uint256);
function maxDeposit(address) external view returns (uint256);
function maxMint(address) external view returns (uint256);
function maxRedeem(address owner) external view returns (uint256);
function maxWithdraw(address owner) external view returns (uint256);
function previewDeposit(uint256 assets) external view returns (uint256);
function previewMint(uint256 shares) external view returns (uint256);
function previewRedeem(uint256 shares) external view returns (uint256);
function previewWithdraw(uint256 assets) external view returns (uint256);
function totalAssets() external view returns (uint256);
function mint(uint256 shares, address receiver) external returns (uint256 assets);
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
}
文件 15 的 31:IFeeDeposit.sol
pragma solidity 0.8.28;
interface IFeeDeposit {
function operator() external view returns(address);
function lastDistributedEpoch() external view returns(uint256);
function setOperator(address _newAddress) external;
function distributeFees() external;
function incrementPairRevenue(uint256 _fees, uint256 _otherFees) external;
}
文件 16 的 31:ILiquidationHandler.sol
pragma solidity 0.8.28;
interface ILiquidationHandler {
function operator() external view returns(address);
function setOperator(address _newAddress) external;
function processLiquidationDebt(address _collateral, uint256 _collateralAmount, uint256 _debtAmount) external;
function processCollateral(address _collateral) external;
function liquidate(
address _pair,
address _borrower
) external returns (uint256 _collateralForLiquidator);
}
文件 17 的 31:IMintable.sol
pragma solidity 0.8.28;
interface IMintable{
function mint(address _to, uint256 _amount) external;
function burn(address _from, uint256 _amount) external;
}
文件 18 的 31:IOracle.sol
pragma solidity 0.8.28;
interface IOracle {
function decimals() external view returns (uint8);
function getPrices(address _vault) external view returns (uint256 _price);
function name() external view returns (string memory);
}
文件 19 的 31:IRateCalculator.sol
pragma solidity 0.8.28;
interface IRateCalculator {
function name() external view returns (string memory);
function version() external view returns (uint256, uint256, uint256);
function getNewRate(
address _vault,
uint256 _deltaTime,
uint256 _previousShares
) external view returns (uint64 _newRatePerSec, uint128 _newShares);
}
文件 20 的 31:IResupplyRegistry.sol
pragma solidity 0.8.28;
interface IResupplyRegistry {
event AddPair(address pairAddress);
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event SetDeployer(address deployer, bool _bool);
function acceptOwnership() external;
function addPair(address _pairAddress) external;
function registeredPairs(uint256) external view returns (address);
function pairsByName(string memory) external view returns (address);
function defaultSwappersLength() external view returns (uint256);
function registeredPairsLength() external view returns (uint256);
function getAllPairAddresses() external view returns (address[] memory _deployedPairsArray);
function getAllDefaultSwappers() external view returns (address[] memory _defaultSwappers);
function owner() external view returns (address);
function pendingOwner() external view returns (address);
function renounceOwnership() external;
function transferOwnership(address newOwner) external;
function claimFees(address _pair) external;
function claimRewards(address _pair) external;
function claimInsuranceRewards() external;
function withdrawTo(address _asset, uint256 _amount, address _to) external;
function mint( address receiver, uint256 amount) external;
function burn( address target, uint256 amount) external;
function liquidationHandler() external view returns(address);
function feeDeposit() external view returns(address);
function redemptionHandler() external view returns(address);
function rewardHandler() external view returns(address);
function insurancePool() external view returns(address);
function setRewardClaimer(address _newAddress) external;
function setRedemptionHandler(address _newAddress) external;
function setFeeDeposit(address _newAddress) external;
function setLiquidationHandler(address _newAddress) external;
function setInsurancePool(address _newAddress) external;
function setStaker(address _newAddress) external;
function setTreasury(address _newAddress) external;
function staker() external view returns(address);
function token() external view returns(address);
function treasury() external view returns(address);
function govToken() external view returns(address);
function l2manager() external view returns(address);
function setRewardHandler(address _newAddress) external;
function setVestManager(address _newAddress) external;
function setDefaultSwappers(address[] memory _swappers) external;
function collateralId(address _collateral) external view returns(uint256);
}
文件 21 的 31:ISwapper.sol
pragma solidity 0.8.28;
interface ISwapper {
function swap(
address account,
uint256 amountIn,
address[] calldata path,
address to
) external;
function swapPools(address tokenIn, address tokenOut) external view returns(address swappool, int32 tokenInIndex, int32 tokenOutIndex, uint32 swaptype);
}
文件 22 的 31:ReentrancyGuard.sol
pragma solidity ^0.8.20;
abstract contract ReentrancyGuard {
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
_status = ENTERED;
}
function _nonReentrantAfter() private {
_status = NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
文件 23 的 31:ResupplyPair.sol
pragma solidity 0.8.28;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { ResupplyPairConstants } from "./pair/ResupplyPairConstants.sol";
import { ResupplyPairCore } from "./pair/ResupplyPairCore.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { VaultAccount, VaultAccountingLibrary } from "../libraries/VaultAccount.sol";
import { IRateCalculator } from "../interfaces/IRateCalculator.sol";
import { ISwapper } from "../interfaces/ISwapper.sol";
import { IFeeDeposit } from "../interfaces/IFeeDeposit.sol";
import { IResupplyRegistry } from "../interfaces/IResupplyRegistry.sol";
import { IConvexStaking } from "../interfaces/IConvexStaking.sol";
import { EpochTracker } from "../dependencies/EpochTracker.sol";
contract ResupplyPair is ResupplyPairCore, EpochTracker {
using VaultAccountingLibrary for VaultAccount;
using SafeERC20 for IERC20;
using SafeCast for uint256;
uint256 public lastFeeEpoch;
address public constant CRV = 0xD533a949740bb3306d119CC777fa900bA034cd52;
address public constant CVX = 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B;
address public immutable convexBooster;
uint256 public convexPid;
error FeesAlreadyDistributed();
error IncorrectStakeBalance();
constructor(
address _core,
bytes memory _configData,
bytes memory _immutables,
bytes memory _customConfigData
) ResupplyPairCore(_core, _configData, _immutables, _customConfigData) EpochTracker(_core) {
(, address _govToken, address _convexBooster, uint256 _convexpid) = abi.decode(
_customConfigData,
(string, address, address, uint256)
);
_insertRewardToken(_govToken);
if(_convexBooster != address(0)){
convexBooster = _convexBooster;
convexPid = _convexpid;
collateral.forceApprove(convexBooster, type(uint256).max);
_insertRewardToken(CRV);
_insertRewardToken(CVX);
emit SetConvexPool(_convexpid);
}
}
function getConstants()
external
pure
returns (
uint256 _LTV_PRECISION,
uint256 _LIQ_PRECISION,
uint256 _EXCHANGE_PRECISION,
uint256 _RATE_PRECISION
)
{
_LTV_PRECISION = LTV_PRECISION;
_LIQ_PRECISION = LIQ_PRECISION;
_EXCHANGE_PRECISION = EXCHANGE_PRECISION;
_RATE_PRECISION = RATE_PRECISION;
}
function getUserSnapshot(
address _address
) external returns (uint256 _borrowShares, uint256 _collateralBalance) {
_collateralBalance = userCollateralBalance(_address);
_borrowShares = userBorrowShares(_address);
}
function getPairAccounting()
external
view
returns (
uint256 _claimableFees,
uint128 _totalBorrowAmount,
uint128 _totalBorrowShares,
uint256 _totalCollateral
)
{
VaultAccount memory _totalBorrow;
(, , _claimableFees, _totalBorrow) = previewAddInterest();
_totalBorrowAmount = _totalBorrow.amount;
_totalBorrowShares = _totalBorrow.shares;
_totalCollateral = totalCollateral();
}
function toBorrowShares(
uint256 _amount,
bool _roundUp,
bool _previewInterest
) external view returns (uint256 _shares) {
if (_previewInterest) {
(, , , VaultAccount memory _totalBorrow) = previewAddInterest();
_shares = _totalBorrow.toShares(_amount, _roundUp);
} else {
_shares = totalBorrow.toShares(_amount, _roundUp);
}
}
function toBorrowAmount(
uint256 _shares,
bool _roundUp,
bool _previewInterest
) external view returns (uint256 _amount) {
if (_previewInterest) {
(, , , VaultAccount memory _totalBorrow) = previewAddInterest();
_amount = _totalBorrow.toAmount(_shares, _roundUp);
} else {
_amount = totalBorrow.toAmount(_shares, _roundUp);
}
}
event SetOracleInfo(
address oldOracle,
address newOracle
);
function setOracle(address _newOracle) external onlyOwner{
ExchangeRateInfo memory _exchangeRateInfo = exchangeRateInfo;
emit SetOracleInfo(
_exchangeRateInfo.oracle,
_newOracle
);
_exchangeRateInfo.oracle = _newOracle;
exchangeRateInfo = _exchangeRateInfo;
}
event SetMaxLTV(uint256 oldMaxLTV, uint256 newMaxLTV);
function setMaxLTV(uint256 _newMaxLTV) external onlyOwner{
if (_newMaxLTV > LTV_PRECISION) revert InvalidParameter();
emit SetMaxLTV(maxLTV, _newMaxLTV);
maxLTV = _newMaxLTV;
}
event SetRateCalculator(address oldRateCalculator, address newRateCalculator);
function setRateCalculator(address _newRateCalculator, bool _updateInterest) external onlyOwner{
if(_updateInterest){
_addInterest();
}
emit SetRateCalculator(address(rateCalculator), _newRateCalculator);
rateCalculator = IRateCalculator(_newRateCalculator);
}
event SetLiquidationFees(
uint256 oldLiquidationFee,
uint256 newLiquidationFee
);
function setLiquidationFees(
uint256 _newLiquidationFee
) external onlyOwner{
if (_newLiquidationFee > LIQ_PRECISION) revert InvalidParameter();
emit SetLiquidationFees(
liquidationFee,
_newLiquidationFee
);
liquidationFee = _newLiquidationFee;
}
event SetMintFees(
uint256 oldMintFee,
uint256 newMintFee
);
function setMintFees(
uint256 _newMintFee
) external onlyOwner{
emit SetMintFees(
mintFee,
_newMintFee
);
mintFee = _newMintFee;
}
function setBorrowLimit(uint256 _limit) external onlyOwner{
_setBorrowLimit(_limit);
}
event SetBorrowLimit(uint256 limit);
function _setBorrowLimit(uint256 _limit) internal {
if(_limit > type(uint128).max){
revert InvalidParameter();
}
borrowLimit = _limit;
emit SetBorrowLimit(_limit);
}
event SetMinimumRedemption(uint256 min);
function setMinimumRedemption(uint256 _min) external onlyOwner{
if(_min < 100 * PAIR_DECIMALS ){
revert InvalidParameter();
}
minimumRedemption = _min;
emit SetMinimumRedemption(_min);
}
event SetMinimumLeftover(uint256 min);
function setMinimumLeftoverDebt(uint256 _min) external onlyOwner{
minimumLeftoverDebt = _min;
emit SetMinimumLeftover(_min);
}
event SetMinimumBorrowAmount(uint256 min);
function setMinimumBorrowAmount(uint256 _min) external onlyOwner{
minimumBorrowAmount = _min;
emit SetMinimumBorrowAmount(_min);
}
event SetProtocolRedemptionFee(uint256 fee);
function setProtocolRedemptionFee(uint256 _fee) external onlyOwner{
if(_fee > EXCHANGE_PRECISION) revert InvalidParameter();
protocolRedemptionFee = _fee;
emit SetProtocolRedemptionFee(_fee);
}
event WithdrawFees(address recipient, uint256 interestFees, uint256 otherFees);
function withdrawFees() external nonReentrant returns (uint256 _fees, uint256 _otherFees) {
_addInterest();
address feeDeposit = IResupplyRegistry(registry).feeDeposit();
uint256 lastDistributedEpoch = IFeeDeposit(feeDeposit).lastDistributedEpoch();
uint256 currentEpoch = getEpoch();
if(currentEpoch <= lastFeeEpoch || currentEpoch != lastDistributedEpoch){
revert FeesAlreadyDistributed();
}
lastFeeEpoch = currentEpoch;
_fees = claimableFees;
_otherFees = claimableOtherFees;
claimableFees = 0;
claimableOtherFees = 0;
IResupplyRegistry(registry).mint(feeDeposit,_fees+_otherFees);
IFeeDeposit(feeDeposit).incrementPairRevenue(_fees,_otherFees);
emit WithdrawFees(feeDeposit, _fees, _otherFees);
}
event SetSwapper(address swapper, bool approval);
function setSwapper(address _swapper, bool _approval) external{
if(msg.sender == owner() || msg.sender == registry){
swappers[_swapper] = _approval;
emit SetSwapper(_swapper, _approval);
}else{
revert OnlyProtocolOrOwner();
}
}
event SetConvexPool(uint256 pid);
function setConvexPool(uint256 pid) external onlyOwner{
_updateConvexPool(pid);
emit SetConvexPool(pid);
}
function _updateConvexPool(uint256 _pid) internal{
uint256 currentPid = convexPid;
if(currentPid != _pid){
(,,,address _rewards,,) = IConvexStaking(convexBooster).poolInfo(currentPid);
uint256 stakedBalance = IConvexStaking(_rewards).balanceOf(address(this));
if(stakedBalance > 0){
IConvexStaking(_rewards).withdrawAndUnwrap(stakedBalance,false);
if(collateral.balanceOf(address(this)) < stakedBalance){
revert IncorrectStakeBalance();
}
}
IConvexStaking(convexBooster).deposit(_pid, stakedBalance, true);
convexPid = _pid;
}
}
function _stakeUnderlying(uint256 _amount) internal override{
uint256 currentPid = convexPid;
if(currentPid != 0){
IConvexStaking(convexBooster).deposit(currentPid, _amount, true);
}
}
function _unstakeUnderlying(uint256 _amount) internal override{
uint256 currentPid = convexPid;
if(currentPid != 0){
(,,,address _rewards,,) = IConvexStaking(convexBooster).poolInfo(currentPid);
IConvexStaking(_rewards).withdrawAndUnwrap(_amount, false);
}
}
function totalCollateral() public view override returns(uint256 _totalCollateralBalance){
uint256 currentPid = convexPid;
if(currentPid != 0){
(,,,address _rewards,,) = IConvexStaking(convexBooster).poolInfo(currentPid);
_totalCollateralBalance = IConvexStaking(_rewards).balanceOf(address(this));
}else{
_totalCollateralBalance = collateral.balanceOf(address(this));
}
}
uint256 previousBorrowLimit;
function pause() external onlyOwner{
if (borrowLimit > 0) {
previousBorrowLimit = borrowLimit;
_setBorrowLimit(0);
}
}
function unpause() external onlyOwner{
if (borrowLimit == 0) _setBorrowLimit(previousBorrowLimit);
}
}
文件 24 的 31:ResupplyPairConstants.sol
pragma solidity 0.8.28;
abstract contract ResupplyPairConstants {
uint256 public constant LTV_PRECISION = 1e5;
uint256 public constant LIQ_PRECISION = 1e5;
uint256 public constant EXCHANGE_PRECISION = 1e18;
uint256 public constant RATE_PRECISION = 1e18;
uint256 public constant SHARE_REFACTOR_PRECISION = 1e12;
uint256 public constant PAIR_DECIMALS = 1e18;
error Insolvent(uint256 _borrow, uint256 _collateral, uint256 _exchangeRate);
error BorrowerSolvent();
error InsufficientDebtAvailable(uint256 _assets, uint256 _request);
error SlippageTooHigh(uint256 _minOut, uint256 _actual);
error BadSwapper();
error InvalidPath(address _expected, address _actual);
error InvalidReceiver();
error InvalidLiquidator();
error InvalidRedemptionHandler();
error InvalidParameter();
error InsufficientDebtToRedeem();
error MinimumRedemption();
error InsufficientBorrowAmount();
error OnlyProtocolOrOwner();
}
文件 25 的 31:ResupplyPairCore.sol
pragma solidity 0.8.28;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { ResupplyPairConstants } from "./ResupplyPairConstants.sol";
import { VaultAccount, VaultAccountingLibrary } from "../../libraries/VaultAccount.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IOracle } from "../../interfaces/IOracle.sol";
import { IRateCalculator } from "../../interfaces/IRateCalculator.sol";
import { ISwapper } from "../../interfaces/ISwapper.sol";
import { IResupplyRegistry } from "../../interfaces/IResupplyRegistry.sol";
import { ILiquidationHandler } from "../../interfaces/ILiquidationHandler.sol";
import { RewardDistributorMultiEpoch } from "../RewardDistributorMultiEpoch.sol";
import { WriteOffToken } from "../WriteOffToken.sol";
import { IERC4626 } from "../../interfaces/IERC4626.sol";
import { CoreOwnable } from "../../dependencies/CoreOwnable.sol";
import { IMintable } from "../../interfaces/IMintable.sol";
abstract contract ResupplyPairCore is CoreOwnable, ResupplyPairConstants, RewardDistributorMultiEpoch {
using VaultAccountingLibrary for VaultAccount;
using SafeERC20 for IERC20;
using SafeCast for uint256;
function version() external pure returns (uint256 _major, uint256 _minor, uint256 _patch) {
_major = 3;
_minor = 0;
_patch = 0;
}
address public immutable registry;
IERC20 internal immutable debtToken;
IERC20 public immutable collateral;
IERC20 public immutable underlying;
uint256 public maxLTV;
uint256 public borrowLimit;
uint256 public mintFee;
uint256 public liquidationFee;
uint256 public protocolRedemptionFee;
uint256 public minimumRedemption = 100 * PAIR_DECIMALS;
uint256 public minimumLeftoverDebt = 10000 * PAIR_DECIMALS;
uint256 public minimumBorrowAmount = 1000 * PAIR_DECIMALS;
IRateCalculator public rateCalculator;
mapping(address => bool) public swappers;
string public name;
CurrentRateInfo public currentRateInfo;
struct CurrentRateInfo {
uint64 lastTimestamp;
uint64 ratePerSec;
uint128 lastShares;
}
ExchangeRateInfo public exchangeRateInfo;
struct ExchangeRateInfo {
address oracle;
uint96 lastTimestamp;
uint256 exchangeRate;
}
VaultAccount public totalBorrow;
uint256 public claimableFees;
uint256 public claimableOtherFees;
WriteOffToken immutable public redemptionWriteOff;
mapping(address => uint256) internal _userCollateralBalance;
mapping(address => uint256) internal _userBorrowShares;
constructor(
address _core,
bytes memory _configData,
bytes memory _immutables,
bytes memory _customConfigData
) CoreOwnable(_core){
(address _registry) = abi.decode(
_immutables,
(address)
);
registry = _registry;
debtToken = IERC20(IResupplyRegistry(registry).token());
{
(
address _collateral,
address _oracle,
address _rateCalculator,
uint256 _maxLTV,
uint256 _initialBorrowLimit,
uint256 _liquidationFee,
uint256 _mintFee,
uint256 _protocolRedemptionFee
) = abi.decode(
_configData,
(address, address, address, uint256, uint256, uint256, uint256, uint256)
);
collateral = IERC20(_collateral);
if(IERC20Metadata(_collateral).decimals() != 18){
revert InvalidParameter();
}
underlying = IERC20(IERC4626(_collateral).asset());
if(IERC20Metadata(address(underlying)).decimals() != 18){
revert InvalidParameter();
}
underlying.forceApprove(_collateral, type(uint256).max);
currentRateInfo.lastShares = uint128(IERC4626(_collateral).convertToShares(PAIR_DECIMALS));
exchangeRateInfo.oracle = _oracle;
rateCalculator = IRateCalculator(_rateCalculator);
borrowLimit = _initialBorrowLimit;
liquidationFee = _liquidationFee;
mintFee = _mintFee;
protocolRedemptionFee = _protocolRedemptionFee;
maxLTV = _maxLTV;
}
redemptionWriteOff = new WriteOffToken(address(this));
_insertRewardToken(address(redemptionWriteOff));
rewards[0].is_non_claimable = true;
{
(string memory _name,,,) = abi.decode(
_customConfigData,
(string, address, address, uint256)
);
name = _name;
_addInterest();
_updateExchangeRate();
}
}
function totalCollateral() public view virtual returns(uint256 _totalCollateralBalance);
function userBorrowShares(address _account) public view returns(uint256 borrowShares){
borrowShares = _userBorrowShares[_account];
uint256 globalEpoch = currentRewardEpoch;
uint256 userEpoch = userRewardEpoch[_account];
if(userEpoch < globalEpoch){
for(;;){
borrowShares /= SHARE_REFACTOR_PRECISION;
unchecked {
userEpoch += 1;
}
if(userEpoch == globalEpoch){
break;
}
}
}
}
function userCollateralBalance(address _account) public nonReentrant returns(uint256 _collateralAmount){
_syncUserRedemptions(_account);
_collateralAmount = _userCollateralBalance[_account];
uint256 total = totalCollateral();
_collateralAmount = _collateralAmount > total ? total : _collateralAmount;
}
function totalDebtAvailable() external view returns (uint256) {
(,,, VaultAccount memory _totalBorrow) = previewAddInterest();
return _totalDebtAvailable(_totalBorrow);
}
function _totalDebtAvailable(VaultAccount memory _totalBorrow) internal view returns (uint256) {
uint256 _borrowLimit = borrowLimit;
uint256 borrowable = _borrowLimit > _totalBorrow.amount ? _borrowLimit - _totalBorrow.amount : 0;
return borrowable > type(uint128).max ? type(uint128).max : borrowable;
}
function currentUtilization() external view returns (uint256) {
uint256 _borrowLimit = borrowLimit;
if(_borrowLimit == 0){
return PAIR_DECIMALS;
}
(,,, VaultAccount memory _totalBorrow) = previewAddInterest();
return _totalBorrow.amount * PAIR_DECIMALS / _borrowLimit;
}
function _isSolvent(address _borrower, uint256 _exchangeRate) internal view returns (bool) {
uint256 _maxLTV = maxLTV;
if (_maxLTV == 0) return true;
uint256 _borrowerAmount = totalBorrow.toAmount(_userBorrowShares[_borrower], true);
if (_borrowerAmount == 0) return true;
uint256 _collateralAmount = _userCollateralBalance[_borrower];
if (_collateralAmount == 0) return false;
uint256 _ltv = ((_borrowerAmount * _exchangeRate * LTV_PRECISION) / EXCHANGE_PRECISION) / _collateralAmount;
return _ltv <= _maxLTV;
}
function _isSolventSync(address _borrower, uint256 _exchangeRate) internal returns (bool){
_syncUserRedemptions(_borrower);
return _isSolvent(_borrower, _exchangeRate);
}
modifier isSolvent(address _borrower) {
_syncUserRedemptions(_borrower);
_;
ExchangeRateInfo memory _exchangeRateInfo = exchangeRateInfo;
if (!_isSolvent(_borrower, _exchangeRateInfo.exchangeRate)) {
revert Insolvent(
totalBorrow.toAmount(_userBorrowShares[_borrower], true),
_userCollateralBalance[_borrower],
_exchangeRateInfo.exchangeRate
);
}
}
function _isRewardManager() internal view override returns(bool){
return msg.sender == address(core) || msg.sender == IResupplyRegistry(registry).rewardHandler();
}
function _fetchIncentives() internal override{
IResupplyRegistry(registry).claimRewards(address(this));
}
function _totalRewardShares() internal view override returns(uint256){
return totalBorrow.shares;
}
function _userRewardShares(address _account) internal view override returns(uint256){
return _userBorrowShares[_account];
}
function _increaseUserRewardEpoch(address _account, uint256 _currentUserEpoch) internal override{
_userBorrowShares[_account] = _userBorrowShares[_account] / SHARE_REFACTOR_PRECISION;
userRewardEpoch[_account] = _currentUserEpoch + 1;
}
function earned(address _account) public override returns(EarnedData[] memory claimable){
EarnedData[] memory earneddata = super.earned(_account);
uint256 rewardCount = earneddata.length - 1;
claimable = new EarnedData[](rewardCount);
for (uint256 i = 1; i <= rewardCount; ) {
claimable[i-1].amount = earneddata[i].amount;
claimable[i-1].token = earneddata[i].token;
unchecked{ i += 1; }
}
}
function _checkAddToken(address _address) internal view virtual override returns(bool){
if(_address == address(collateral)) return false;
if(_address == address(debtToken)) return false;
return true;
}
function _stakeUnderlying(uint256 _amount) internal virtual;
function _unstakeUnderlying(uint256 _amount) internal virtual;
event AddInterest(uint256 interestEarned, uint256 rate);
event UpdateRate(
uint256 oldRatePerSec,
uint128 oldShares,
uint256 newRatePerSec,
uint128 newShares
);
function addInterest(
bool _returnAccounting
)
external
nonReentrant
returns (
uint256 _interestEarned,
CurrentRateInfo memory _currentRateInfo,
uint256 _claimableFees,
VaultAccount memory _totalBorrow
)
{
(, _interestEarned, _currentRateInfo) = _addInterest();
if (_returnAccounting) {
_claimableFees = claimableFees;
_totalBorrow = totalBorrow;
}
}
function previewAddInterest()
public
view
returns (
uint256 _interestEarned,
CurrentRateInfo memory _newCurrentRateInfo,
uint256 _claimableFees,
VaultAccount memory _totalBorrow
)
{
_newCurrentRateInfo = currentRateInfo;
_newCurrentRateInfo.lastTimestamp = uint64(block.timestamp);
InterestCalculationResults memory _results = _calculateInterest(_newCurrentRateInfo);
if (_results.isInterestUpdated) {
_interestEarned = _results.interestEarned;
_newCurrentRateInfo.ratePerSec = _results.newRate;
_newCurrentRateInfo.lastShares = _results.newShares;
_claimableFees = claimableFees + uint128(_interestEarned);
_totalBorrow = _results.totalBorrow;
} else {
_claimableFees = claimableFees;
_totalBorrow = totalBorrow;
}
}
struct InterestCalculationResults {
bool isInterestUpdated;
uint64 newRate;
uint128 newShares;
uint256 interestEarned;
VaultAccount totalBorrow;
}
function _calculateInterest(
CurrentRateInfo memory _currentRateInfo
) internal view returns (InterestCalculationResults memory _results) {
if (_currentRateInfo.lastTimestamp < block.timestamp) {
_results.isInterestUpdated = true;
_results.totalBorrow = totalBorrow;
uint256 _deltaTime = block.timestamp - _currentRateInfo.lastTimestamp;
(_results.newRate, _results.newShares) = IRateCalculator(rateCalculator).getNewRate(
address(collateral),
_deltaTime,
_currentRateInfo.lastShares
);
_results.interestEarned = (_deltaTime * _results.totalBorrow.amount * _results.newRate) / RATE_PRECISION;
if (
_results.interestEarned > 0 &&
_results.interestEarned + _results.totalBorrow.amount <= type(uint128).max
) {
_results.totalBorrow.amount += uint128(_results.interestEarned);
}else{
_results.interestEarned = 0;
}
}
}
function _addInterest()
internal
returns (
bool _isInterestUpdated,
uint256 _interestEarned,
CurrentRateInfo memory _currentRateInfo
)
{
_currentRateInfo = currentRateInfo;
InterestCalculationResults memory _results = _calculateInterest(_currentRateInfo);
if (_results.isInterestUpdated) {
_isInterestUpdated = _results.isInterestUpdated;
_interestEarned = _results.interestEarned;
emit UpdateRate(
_currentRateInfo.ratePerSec,
_currentRateInfo.lastShares,
_results.newRate,
_results.newShares
);
emit AddInterest(_interestEarned, _results.newRate);
_currentRateInfo.ratePerSec = _results.newRate;
_currentRateInfo.lastShares = _results.newShares;
_currentRateInfo.lastTimestamp = uint64(block.timestamp);
currentRateInfo = _currentRateInfo;
claimableFees += _interestEarned;
totalBorrow = _results.totalBorrow;
}
}
event UpdateExchangeRate(uint256 exchangeRate);
function updateExchangeRate()
external
nonReentrant
returns (uint256 _exchangeRate)
{
return _updateExchangeRate();
}
function _updateExchangeRate()
internal
returns (uint256 _exchangeRate)
{
ExchangeRateInfo memory _exchangeRateInfo = exchangeRateInfo;
if (_exchangeRateInfo.lastTimestamp != block.timestamp) {
_exchangeRate = IOracle(_exchangeRateInfo.oracle).getPrices(address(collateral));
_exchangeRate = 1e36 / _exchangeRate;
_exchangeRateInfo.lastTimestamp = uint96(block.timestamp);
_exchangeRateInfo.exchangeRate = _exchangeRate;
exchangeRateInfo = _exchangeRateInfo;
emit UpdateExchangeRate(_exchangeRate);
} else {
_exchangeRate = _exchangeRateInfo.exchangeRate;
}
}
function _syncUserRedemptions(address _account) internal{
_checkpoint(_account);
uint256 rTokens = claimable_reward[address(redemptionWriteOff)][_account] / LTV_PRECISION;
claimable_reward[address(redemptionWriteOff)][_account] = 0;
uint256 currentUserBalance = _userCollateralBalance[_account];
_userCollateralBalance[_account] = currentUserBalance >= rTokens ? currentUserBalance - rTokens : 0;
}
event Borrow(
address indexed _borrower,
address indexed _receiver,
uint256 _borrowAmount,
uint256 _sharesAdded,
uint256 _mintFees
);
function _borrow(uint128 _borrowAmount, address _receiver) internal returns (uint256 _sharesAdded) {
VaultAccount memory _totalBorrow = totalBorrow;
if(_borrowAmount < minimumBorrowAmount){
revert InsufficientBorrowAmount();
}
uint256 debtForMint = (_borrowAmount * (LIQ_PRECISION + mintFee) / LIQ_PRECISION);
uint256 _assetsAvailable = _totalDebtAvailable(_totalBorrow);
if (_assetsAvailable < debtForMint) {
revert InsufficientDebtAvailable(_assetsAvailable, debtForMint);
}
_sharesAdded = _totalBorrow.toShares(debtForMint, true);
uint256 newTotalShares = _totalBorrow.shares + _sharesAdded;
_totalBorrow.amount += debtForMint.toUint128();
_totalBorrow.shares = newTotalShares.toUint128();
totalBorrow = _totalBorrow;
_userBorrowShares[msg.sender] += _sharesAdded;
uint256 otherFees = debtForMint > _borrowAmount ? debtForMint - _borrowAmount : 0;
if (otherFees > 0) claimableOtherFees += otherFees;
IResupplyRegistry(registry).mint(_receiver, _borrowAmount);
emit Borrow(msg.sender, _receiver, _borrowAmount, _sharesAdded, otherFees);
}
function borrow(
uint256 _borrowAmount,
uint256 _underlyingAmount,
address _receiver
) external nonReentrant isSolvent(msg.sender) returns (uint256 _shares) {
if (_receiver == address(0)) revert InvalidReceiver();
_addInterest();
_updateExchangeRate();
if (_underlyingAmount > 0) {
underlying.safeTransferFrom(msg.sender, address(this), _underlyingAmount);
uint256 collateralShares = IERC4626(address(collateral)).deposit(_underlyingAmount, address(this));
_addCollateral(address(this), collateralShares, msg.sender);
}
_shares = _borrow(_borrowAmount.toUint128(), _receiver);
}
event AddCollateral(address indexed borrower, uint256 collateralAmount);
function _addCollateral(address _sender, uint256 _collateralAmount, address _borrower) internal {
_userCollateralBalance[_borrower] += _collateralAmount;
if (_sender != address(this)) {
collateral.safeTransferFrom(_sender, address(this), _collateralAmount);
}
_stakeUnderlying(_collateralAmount);
emit AddCollateral(_borrower, _collateralAmount);
}
function addCollateralVault(uint256 _collateralAmount, address _borrower) external nonReentrant {
if (_borrower == address(0)) revert InvalidReceiver();
_addInterest();
_addCollateral(msg.sender, _collateralAmount, _borrower);
}
function addCollateral(uint256 _amount, address _borrower) external nonReentrant {
if (_borrower == address(0)) revert InvalidReceiver();
_addInterest();
underlying.safeTransferFrom(msg.sender, address(this), _amount);
uint256 collateralShares = IERC4626(address(collateral)).deposit(_amount, address(this));
_addCollateral(address(this), collateralShares, _borrower);
}
event RemoveCollateral(
uint256 _collateralAmount,
address indexed _receiver,
address indexed _borrower
);
function _removeCollateral(uint256 _collateralAmount, address _receiver, address _borrower) internal {
_userCollateralBalance[_borrower] -= _collateralAmount;
_unstakeUnderlying(_collateralAmount);
if (_receiver != address(this)) {
collateral.safeTransfer(_receiver, _collateralAmount);
}
emit RemoveCollateral(_collateralAmount, _receiver, _borrower);
}
function removeCollateralVault(
uint256 _collateralAmount,
address _receiver
) external nonReentrant isSolvent(msg.sender) {
if (_receiver == address(0)) revert InvalidReceiver();
_addInterest();
if (_userBorrowShares[msg.sender] > 0) {
_updateExchangeRate();
}
_removeCollateral(_collateralAmount, _receiver, msg.sender);
}
function removeCollateral(
uint256 _collateralAmount,
address _receiver
) external nonReentrant isSolvent(msg.sender) {
if (_receiver == address(0)) revert InvalidReceiver();
_addInterest();
if (_userBorrowShares[msg.sender] > 0) {
_updateExchangeRate();
}
_removeCollateral(_collateralAmount, address(this), msg.sender);
IERC4626(address(collateral)).redeem(_collateralAmount, _receiver, address(this));
}
event Repay(address indexed payer, address indexed borrower, uint256 amountToRepay, uint256 shares);
function _repay(
VaultAccount memory _totalBorrow,
uint128 _amountToRepay,
uint128 _shares,
address _payer,
address _borrower
) internal {
_checkpoint(_borrower);
_totalBorrow.amount -= _amountToRepay;
_totalBorrow.shares -= _shares;
uint256 usershares = _userBorrowShares[_borrower] - _shares;
_userBorrowShares[_borrower] = usershares;
if(usershares > 0 && _totalBorrow.toAmount(usershares, true) < minimumBorrowAmount){
revert InsufficientBorrowAmount();
}
totalBorrow = _totalBorrow;
if (_payer != address(0)) {
IMintable(address(debtToken)).burn(_payer, _amountToRepay);
}
emit Repay(_payer, _borrower, _amountToRepay, _shares);
}
function repay(uint256 _shares, address _borrower) external nonReentrant returns (uint256 _amountToRepay) {
if (_borrower == address(0)) revert InvalidReceiver();
_addInterest();
VaultAccount memory _totalBorrow = totalBorrow;
_amountToRepay = _totalBorrow.toAmount(_shares, true);
_repay(_totalBorrow, _amountToRepay.toUint128(), _shares.toUint128(), msg.sender, _borrower);
}
event Redeemed(
address indexed _caller,
uint256 _amount,
uint256 _collateralFreed,
uint256 _protocolFee,
uint256 _debtReduction
);
function redeemCollateral(
address _caller,
uint256 _amount,
uint256 _totalFeePct,
address _receiver
) external nonReentrant returns(address _collateralToken, uint256 _collateralFreed){
if(msg.sender != IResupplyRegistry(registry).redemptionHandler()) revert InvalidRedemptionHandler();
if (_receiver == address(0) || _receiver == address(this)) revert InvalidReceiver();
if(_amount < minimumRedemption){
revert MinimumRedemption();
}
_addInterest();
uint256 valueToRedeem = _amount * (EXCHANGE_PRECISION - _totalFeePct) / EXCHANGE_PRECISION;
uint256 protocolFee = (_amount - valueToRedeem) * protocolRedemptionFee / EXCHANGE_PRECISION;
uint256 debtReduction = _amount - protocolFee;
VaultAccount memory _totalBorrow = totalBorrow;
if(debtReduction > _totalBorrow.amount || _totalBorrow.amount - debtReduction < minimumLeftoverDebt ){
revert InsufficientDebtToRedeem();
}
_totalBorrow.amount -= uint128(debtReduction);
if(uint256(_totalBorrow.amount) * SHARE_REFACTOR_PRECISION < _totalBorrow.shares){
_increaseRewardEpoch();
_totalBorrow.shares /= uint128(SHARE_REFACTOR_PRECISION);
}
totalBorrow = _totalBorrow;
claimableOtherFees += protocolFee;
uint256 _exchangeRate = _updateExchangeRate();
_collateralFreed = ((valueToRedeem * _exchangeRate) / EXCHANGE_PRECISION);
_unstakeUnderlying(_collateralFreed);
_collateralToken = address(collateral);
IERC20(_collateralToken).safeTransfer(_receiver, _collateralFreed);
redemptionWriteOff.mint(_collateralFreed * LTV_PRECISION);
emit Redeemed(_caller, _amount, _collateralFreed, protocolFee, debtReduction);
}
event Liquidate(
address indexed _borrower,
uint256 _collateralForLiquidator,
uint256 _sharesLiquidated,
uint256 _amountLiquidatorToRepay
);
function liquidate(
address _borrower
) external nonReentrant returns (uint256 _collateralForLiquidator) {
address liquidationHandler = IResupplyRegistry(registry).liquidationHandler();
if(msg.sender != liquidationHandler) revert InvalidLiquidator();
if (_borrower == address(0)) revert InvalidReceiver();
_addInterest();
uint256 _exchangeRate = _updateExchangeRate();
if (_isSolventSync(_borrower, _exchangeRate)) {
revert BorrowerSolvent();
}
VaultAccount memory _totalBorrow = totalBorrow;
uint256 _collateralBalance = _userCollateralBalance[_borrower];
uint128 _borrowerShares = _userBorrowShares[_borrower].toUint128();
uint256 _liquidationAmountInCollateralUnits = ((_totalBorrow.toAmount(_borrowerShares, false) *
_exchangeRate) / EXCHANGE_PRECISION);
_collateralForLiquidator = (_liquidationAmountInCollateralUnits *
(LIQ_PRECISION + liquidationFee)) / LIQ_PRECISION;
_collateralForLiquidator = _collateralForLiquidator > _collateralBalance ? _collateralBalance : _collateralForLiquidator;
uint128 _amountLiquidatorToRepay = (_totalBorrow.toAmount(_borrowerShares, true)).toUint128();
emit Liquidate(
_borrower,
_collateralForLiquidator,
_borrowerShares,
_amountLiquidatorToRepay
);
_repay(
_totalBorrow,
_amountLiquidatorToRepay,
_borrowerShares,
address(0),
_borrower
);
_removeCollateral(_collateralForLiquidator, liquidationHandler, _borrower);
ILiquidationHandler(liquidationHandler).processLiquidationDebt(address(collateral), _collateralForLiquidator, _amountLiquidatorToRepay);
}
event LeveragedPosition(
address indexed _borrower,
address _swapperAddress,
uint256 _borrowAmount,
uint256 _borrowShares,
uint256 _initialUnderlyingAmount,
uint256 _amountCollateralOut
);
function leveragedPosition(
address _swapperAddress,
uint256 _borrowAmount,
uint256 _initialUnderlyingAmount,
uint256 _amountCollateralOutMin,
address[] memory _path
) external nonReentrant isSolvent(msg.sender) returns (uint256 _totalCollateralBalance) {
_addInterest();
_updateExchangeRate();
IERC20 _debtToken = debtToken;
IERC20 _collateral = collateral;
if (!swappers[_swapperAddress]) {
revert BadSwapper();
}
if (_path[0] != address(_debtToken)) {
revert InvalidPath(address(_debtToken), _path[0]);
}
if (_path[_path.length - 1] != address(_collateral)) {
revert InvalidPath(address(_collateral), _path[_path.length - 1]);
}
if (_initialUnderlyingAmount > 0) {
underlying.safeTransferFrom(msg.sender, address(this), _initialUnderlyingAmount);
uint256 collateralShares = IERC4626(address(collateral)).deposit(_initialUnderlyingAmount, address(this));
_addCollateral(address(this), collateralShares, msg.sender);
_totalCollateralBalance = collateralShares;
}
uint256 _borrowShares = _borrow(_borrowAmount.toUint128(), _swapperAddress);
uint256 _initialCollateralBalance = _collateral.balanceOf(address(this));
ISwapper(_swapperAddress).swap(
msg.sender,
_borrowAmount,
_path,
address(this)
);
uint256 _finalCollateralBalance = _collateral.balanceOf(address(this));
uint256 _amountCollateralOut = _finalCollateralBalance - _initialCollateralBalance;
if (_amountCollateralOut < _amountCollateralOutMin) {
revert SlippageTooHigh(_amountCollateralOutMin, _amountCollateralOut);
}
_addCollateral(address(this), _amountCollateralOut, msg.sender);
_totalCollateralBalance += _amountCollateralOut;
emit LeveragedPosition(
msg.sender,
_swapperAddress,
_borrowAmount,
_borrowShares,
_initialUnderlyingAmount,
_amountCollateralOut
);
}
event RepayWithCollateral(
address indexed _borrower,
address _swapperAddress,
uint256 _collateralToSwap,
uint256 _amountAssetOut,
uint256 _sharesRepaid
);
function repayWithCollateral(
address _swapperAddress,
uint256 _collateralToSwap,
uint256 _amountOutMin,
address[] calldata _path
) external nonReentrant isSolvent(msg.sender) returns (uint256 _amountOut) {
_addInterest();
_updateExchangeRate();
IERC20 _debtToken = debtToken;
IERC20 _collateral = collateral;
VaultAccount memory _totalBorrow = totalBorrow;
if (!swappers[_swapperAddress]) {
revert BadSwapper();
}
if (_path[0] != address(_collateral)) {
revert InvalidPath(address(_collateral), _path[0]);
}
if (_path[_path.length - 1] != address(_debtToken)) {
revert InvalidPath(address(_debtToken), _path[_path.length - 1]);
}
if(_totalBorrow.amount == 0){
revert InsufficientBorrowAmount();
}
_removeCollateral(_collateralToSwap, _swapperAddress, msg.sender);
uint256 _initialBalance = _debtToken.balanceOf(address(this));
ISwapper(_swapperAddress).swap(
msg.sender,
_collateralToSwap,
_path,
address(this)
);
_amountOut = _debtToken.balanceOf(address(this)) - _initialBalance;
if (_amountOut < _amountOutMin) {
revert SlippageTooHigh(_amountOutMin, _amountOut);
}
uint256 _sharesToRepay = _totalBorrow.toShares(_amountOut, false);
uint256 currentUserBorrowShares = _userBorrowShares[msg.sender];
if(_sharesToRepay > currentUserBorrowShares){
_sharesToRepay = currentUserBorrowShares;
_amountOut = _totalBorrow.toAmount(_sharesToRepay, true);
}
_repay(_totalBorrow, _amountOut.toUint128(), _sharesToRepay.toUint128(), address(this), msg.sender);
uint256 leftover = debtToken.balanceOf(address(this)) - _initialBalance;
if(leftover > 0){
debtToken.transfer(msg.sender, leftover);
}
emit RepayWithCollateral(msg.sender, _swapperAddress, _collateralToSwap, _amountOut, _sharesToRepay);
}
}
文件 26 的 31:RewardDistributorMultiEpoch.sol
pragma solidity 0.8.28;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
abstract contract RewardDistributorMultiEpoch is ReentrancyGuard{
using SafeERC20 for IERC20;
struct EarnedData {
address token;
uint256 amount;
}
struct RewardType {
address reward_token;
bool is_non_claimable;
uint256 reward_remaining;
}
RewardType[] public rewards;
uint256 public currentRewardEpoch;
mapping(address => uint256) public userRewardEpoch;
mapping(uint256 => mapping(address => uint256)) public global_reward_integral;
mapping(uint256 => mapping(address => mapping(address => uint256))) public reward_integral_for;
mapping(address => mapping(address => uint256)) public claimable_reward;
mapping(address => uint256) public rewardMap;
mapping(address => address) public rewardRedirect;
uint256 constant private PRECISION = 1e22;
event RewardPaid(address indexed _user, address indexed _rewardToken, address indexed _receiver, uint256 _rewardAmount);
event RewardAdded(address indexed _rewardToken);
event RewardInvalidated(address indexed _rewardToken);
event RewardRedirected(address indexed _account, address _forward);
event NewEpoch(uint256 indexed _epoch);
constructor() {
}
modifier onlyRewardManager() {
require(_isRewardManager(), "!rewardManager");
_;
}
function _isRewardManager() internal view virtual returns(bool);
function _fetchIncentives() internal virtual;
function _totalRewardShares() internal view virtual returns(uint256);
function _userRewardShares(address _account) internal view virtual returns(uint256);
function _increaseUserRewardEpoch(address _account, uint256 _currentUserEpoch) internal virtual;
function _checkAddToken(address _address) internal view virtual returns(bool);
function maxRewards() public pure virtual returns(uint256){
return 15;
}
function addExtraReward(address _token) external onlyRewardManager nonReentrant{
_insertRewardToken(_token);
}
function _insertRewardToken(address _token) internal{
if(_token == address(this) || _token == address(0) || !_checkAddToken(_token)){
return;
}
if(rewardMap[_token] == 0){
require(rewards.length < maxRewards(), "max rewards");
RewardType storage r = rewards.push();
r.reward_token = _token;
rewardMap[_token] = rewards.length;
emit RewardAdded(_token);
if(_token.code.length > 0){
IERC20(_token).safeTransfer(address(this), 0);
}else{
_invalidateReward(_token);
}
}else{
uint256 index = rewardMap[_token];
RewardType storage reward = rewards[index-1];
if(reward.reward_token == address(0)){
reward.reward_token = _token;
emit RewardAdded(_token);
}
}
}
function invalidateReward(address _token) external onlyRewardManager nonReentrant{
_invalidateReward(_token);
}
function _invalidateReward(address _token) internal{
uint256 index = rewardMap[_token];
if(index > 0){
RewardType storage reward = rewards[index-1];
require(reward.reward_token == _token, "!mismatch");
reward.reward_token = address(0);
emit RewardInvalidated(_token);
}
}
function rewardLength() external view returns(uint256) {
return rewards.length;
}
function _calcRewardIntegral(uint256 _epoch, uint256 _currentEpoch, uint256 _index, address _account, address _claimTo) internal{
RewardType storage reward = rewards[_index];
address rewardToken = reward.reward_token;
if(rewardToken == address(0)){
return;
}
uint256 bal = IERC20(rewardToken).balanceOf(address(this));
uint256 remainingRewards = reward.reward_remaining;
if (_epoch == _currentEpoch && _totalRewardShares() > 0 && bal > remainingRewards) {
uint256 rewardPerToken = ((bal - remainingRewards) * PRECISION / _totalRewardShares());
if(rewardPerToken > 0){
global_reward_integral[_epoch][rewardToken] += rewardPerToken;
}else{
bal = remainingRewards;
}
}
uint256 reward_global = global_reward_integral[_epoch][rewardToken];
if(_account != address(0)){
uint userI = reward_integral_for[_epoch][rewardToken][_account];
if(_claimTo != address(0) || userI < reward_global){
if(_epoch == _currentEpoch && _claimTo != address(0) && !reward.is_non_claimable){
uint256 receiveable = claimable_reward[rewardToken][_account] + (_userRewardShares(_account) * (reward_global - userI) / PRECISION);
if(receiveable > 0){
claimable_reward[rewardToken][_account] = 0;
IERC20(rewardToken).safeTransfer(_claimTo, receiveable);
emit RewardPaid(_account, rewardToken, _claimTo, receiveable);
bal -= receiveable;
}
}else{
claimable_reward[rewardToken][_account] = claimable_reward[rewardToken][_account] + ( _userRewardShares(_account) * (reward_global - userI) / PRECISION);
}
reward_integral_for[_epoch][rewardToken][_account] = reward_global;
}
}
if(_epoch == _currentEpoch && bal != remainingRewards){
reward.reward_remaining = bal;
}
}
function _increaseRewardEpoch() internal{
_checkpoint(address(0), address(0), type(uint256).max);
uint256 newEpoch = currentRewardEpoch + 1;
currentRewardEpoch = newEpoch;
emit NewEpoch(newEpoch);
}
function _checkpoint(address _account) internal {
_checkpoint(_account, address(0), type(uint256).max);
}
function _checkpoint(address _account, address _claimTo, uint256 _maxloops) internal {
_fetchIncentives();
uint256 globalEpoch = currentRewardEpoch;
uint256 rewardCount = rewards.length;
for (uint256 loops = 0; loops < _maxloops;) {
uint256 userEpoch = globalEpoch;
if(_account != address(0)){
userEpoch = userRewardEpoch[_account];
if(userEpoch != globalEpoch && _userRewardShares(_account) == 0){
userEpoch = globalEpoch;
userRewardEpoch[_account] = userEpoch;
}
}
for(uint256 i = 0; i < rewardCount;){
_calcRewardIntegral(userEpoch, globalEpoch, i,_account,_claimTo);
unchecked { i += 1; }
}
if(userEpoch < globalEpoch){
_increaseUserRewardEpoch(_account, userEpoch);
}else{
return;
}
unchecked { loops += 1; }
}
}
function user_checkpoint(address _account, uint256 _epochloops) external nonReentrant returns(bool) {
_checkpoint(_account, address(0), _epochloops);
return true;
}
function earned(address _account) public nonReentrant virtual returns(EarnedData[] memory claimable) {
_checkpoint(_account);
uint256 rewardCount = rewards.length;
claimable = new EarnedData[](rewardCount);
for (uint256 i = 0; i < rewardCount;) {
RewardType storage reward = rewards[i];
if(reward.reward_token == address(0) || reward.is_non_claimable){
unchecked{ i += 1; }
continue;
}
claimable[i].amount = claimable_reward[reward.reward_token][_account];
claimable[i].token = reward.reward_token;
unchecked{ i += 1; }
}
return claimable;
}
function setRewardRedirect(address _to) external nonReentrant{
rewardRedirect[msg.sender] = _to;
emit RewardRedirected(msg.sender, _to);
}
function getReward(address _account) public virtual nonReentrant {
address redirect = rewardRedirect[_account];
if(redirect != address(0)){
_checkpoint(_account, redirect, type(uint256).max);
}else{
_checkpoint(_account, _account, type(uint256).max);
}
}
function getReward(address _account, address _forwardTo) public virtual nonReentrant{
require(msg.sender == _account, "!self");
require(_forwardTo != address(0), "fwd address cannot be 0");
_checkpoint(_account, _forwardTo, type(uint256).max);
}
}
文件 27 的 31:SafeCast.sol
pragma solidity ^0.8.20;
library SafeCast {
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
error SafeCastOverflowedIntToUint(int256 value);
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
error SafeCastOverflowedUintToInt(uint256 value);
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
function toInt256(uint256 value) internal pure returns (int256) {
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}
文件 28 的 31:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}
文件 29 的 31:VaultAccount.sol
pragma solidity ^0.8.19;
struct VaultAccount {
uint128 amount;
uint128 shares;
}
library VaultAccountingLibrary {
function toShares(VaultAccount memory total, uint256 amount, bool roundUp) internal pure returns (uint256 shares) {
if (total.amount == 0) {
shares = amount;
} else {
shares = (amount * total.shares) / total.amount;
if (roundUp && (shares * total.amount) / total.shares < amount) {
shares = shares + 1;
}
}
}
function toAmount(VaultAccount memory total, uint256 shares, bool roundUp) internal pure returns (uint256 amount) {
if (total.shares == 0) {
amount = shares;
} else {
amount = (shares * total.amount) / total.shares;
if (roundUp && total.amount > 0 && (amount * total.shares) / total.amount < shares) {
amount = amount + 1;
}
}
}
}
文件 30 的 31:WriteOffToken.sol
pragma solidity 0.8.28;
contract WriteOffToken {
address public immutable owner;
uint256 public totalSupply;
constructor(address _owner)
{
owner = _owner;
}
function name() external pure returns (string memory){
return "WriteOffToken";
}
function symbol() external pure returns (string memory){
return "WOT";
}
function decimals() external pure returns (uint8){
return 18;
}
function mint(uint256 _amount) external{
if(msg.sender == owner){
totalSupply += _amount;
}
}
function transfer(address to, uint256 amount) external returns (bool){
return true;
}
function balanceOf(address) external view returns (uint256){
return totalSupply;
}
}
文件 31 的 31:draft-IERC6093.sol
pragma solidity ^0.8.20;
interface IERC20Errors {
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address receiver);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
error ERC20InvalidApprover(address approver);
error ERC20InvalidSpender(address spender);
}
interface IERC721Errors {
error ERC721InvalidOwner(address owner);
error ERC721NonexistentToken(uint256 tokenId);
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
error ERC721InvalidSender(address sender);
error ERC721InvalidReceiver(address receiver);
error ERC721InsufficientApproval(address operator, uint256 tokenId);
error ERC721InvalidApprover(address approver);
error ERC721InvalidOperator(address operator);
}
interface IERC1155Errors {
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
error ERC1155InvalidSender(address sender);
error ERC1155InvalidReceiver(address receiver);
error ERC1155MissingApprovalForAll(address operator, address owner);
error ERC1155InvalidApprover(address approver);
error ERC1155InvalidOperator(address operator);
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
{
"compilationTarget": {
"src/protocol/ResupplyPair.sol": "ResupplyPair"
},
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@axelar-network/=node_modules/@axelar-network/",
":@chainlink/=node_modules/@chainlink/",
":@eth-optimism/=node_modules/@eth-optimism/",
":@layerzerolabs/=node_modules/@layerzerolabs/",
":@mean-finance/=node_modules/@mean-finance/",
":@openzeppelin/=node_modules/@openzeppelin/",
":@rari-capital/=node_modules/@rari-capital/",
":@uniswap/=node_modules/@uniswap/",
":base64-sol/=node_modules/base64-sol/",
":ds-test/=node_modules/ds-test/src/",
":forge-std/=node_modules/forge-std/src/",
":frax-standard-solidity/=node_modules/frax-standard-solidity/",
":frax-std/=node_modules/frax-standard-solidity/src/",
":hardhat-deploy/=node_modules/hardhat-deploy/",
":hardhat/=node_modules/hardhat/",
":solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
":solidity-stringutils/=lib/surl/lib/solidity-stringutils/",
":surl/=lib/surl/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"address","name":"_core","type":"address"},{"internalType":"bytes","name":"_configData","type":"bytes"},{"internalType":"bytes","name":"_immutables","type":"bytes"},{"internalType":"bytes","name":"_customConfigData","type":"bytes"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadSwapper","type":"error"},{"inputs":[],"name":"BorrowerSolvent","type":"error"},{"inputs":[],"name":"FeesAlreadyDistributed","type":"error"},{"inputs":[],"name":"IncorrectStakeBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"_borrow","type":"uint256"},{"internalType":"uint256","name":"_collateral","type":"uint256"},{"internalType":"uint256","name":"_exchangeRate","type":"uint256"}],"name":"Insolvent","type":"error"},{"inputs":[],"name":"InsufficientBorrowAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"uint256","name":"_request","type":"uint256"}],"name":"InsufficientDebtAvailable","type":"error"},{"inputs":[],"name":"InsufficientDebtToRedeem","type":"error"},{"inputs":[],"name":"InvalidLiquidator","type":"error"},{"inputs":[],"name":"InvalidParameter","type":"error"},{"inputs":[{"internalType":"address","name":"_expected","type":"address"},{"internalType":"address","name":"_actual","type":"address"}],"name":"InvalidPath","type":"error"},{"inputs":[],"name":"InvalidReceiver","type":"error"},{"inputs":[],"name":"InvalidRedemptionHandler","type":"error"},{"inputs":[],"name":"MinimumRedemption","type":"error"},{"inputs":[],"name":"OnlyProtocolOrOwner","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint256","name":"_minOut","type":"uint256"},{"internalType":"uint256","name":"_actual","type":"uint256"}],"name":"SlippageTooHigh","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralAmount","type":"uint256"}],"name":"AddCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"interestEarned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"AddInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_sharesAdded","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_mintFees","type":"uint256"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"address","name":"_swapperAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_borrowShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_initialUnderlyingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountCollateralOut","type":"uint256"}],"name":"LeveragedPosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"_collateralForLiquidator","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_sharesLiquidated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountLiquidatorToRepay","type":"uint256"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"NewEpoch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_collateralFreed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_protocolFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_debtReduction","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":true,"internalType":"address","name":"_borrower","type":"address"}],"name":"RemoveCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountToRepay","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_borrower","type":"address"},{"indexed":false,"internalType":"address","name":"_swapperAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_collateralToSwap","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amountAssetOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_sharesRepaid","type":"uint256"}],"name":"RepayWithCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_rewardToken","type":"address"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_rewardToken","type":"address"}],"name":"RewardInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_rewardToken","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_rewardAmount","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"},{"indexed":false,"internalType":"address","name":"_forward","type":"address"}],"name":"RewardRedirected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"limit","type":"uint256"}],"name":"SetBorrowLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pid","type":"uint256"}],"name":"SetConvexPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLiquidationFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidationFee","type":"uint256"}],"name":"SetLiquidationFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxLTV","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxLTV","type":"uint256"}],"name":"SetMaxLTV","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"min","type":"uint256"}],"name":"SetMinimumBorrowAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"min","type":"uint256"}],"name":"SetMinimumLeftover","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"min","type":"uint256"}],"name":"SetMinimumRedemption","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMintFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMintFee","type":"uint256"}],"name":"SetMintFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOracle","type":"address"},{"indexed":false,"internalType":"address","name":"newOracle","type":"address"}],"name":"SetOracleInfo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"SetProtocolRedemptionFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldRateCalculator","type":"address"},{"indexed":false,"internalType":"address","name":"newRateCalculator","type":"address"}],"name":"SetRateCalculator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"swapper","type":"address"},{"indexed":false,"internalType":"bool","name":"approval","type":"bool"}],"name":"SetSwapper","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"name":"UpdateExchangeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRatePerSec","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"oldShares","type":"uint128"},{"indexed":false,"internalType":"uint256","name":"newRatePerSec","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"newShares","type":"uint128"}],"name":"UpdateRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"interestFees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"otherFees","type":"uint256"}],"name":"WithdrawFees","type":"event"},{"inputs":[],"name":"CRV","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CVX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXCHANGE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIQ_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LTV_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAIR_DECIMALS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARE_REFACTOR_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_borrower","type":"address"}],"name":"addCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"internalType":"address","name":"_borrower","type":"address"}],"name":"addCollateralVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"addExtraReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_returnAccounting","type":"bool"}],"name":"addInterest","outputs":[{"internalType":"uint256","name":"_interestEarned","type":"uint256"},{"components":[{"internalType":"uint64","name":"lastTimestamp","type":"uint64"},{"internalType":"uint64","name":"ratePerSec","type":"uint64"},{"internalType":"uint128","name":"lastShares","type":"uint128"}],"internalType":"struct ResupplyPairCore.CurrentRateInfo","name":"_currentRateInfo","type":"tuple"},{"internalType":"uint256","name":"_claimableFees","type":"uint256"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"shares","type":"uint128"}],"internalType":"struct VaultAccount","name":"_totalBorrow","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_borrowAmount","type":"uint256"},{"internalType":"uint256","name":"_underlyingAmount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimableFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimableOtherFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"claimable_reward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"convexBooster","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"convexPid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"core","outputs":[{"internalType":"contract ICore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRateInfo","outputs":[{"internalType":"uint64","name":"lastTimestamp","type":"uint64"},{"internalType":"uint64","name":"ratePerSec","type":"uint64"},{"internalType":"uint128","name":"lastShares","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRewardEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentUtilization","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"earned","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct RewardDistributorMultiEpoch.EarnedData[]","name":"claimable","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"epochLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateInfo","outputs":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint96","name":"lastTimestamp","type":"uint96"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getConstants","outputs":[{"internalType":"uint256","name":"_LTV_PRECISION","type":"uint256"},{"internalType":"uint256","name":"_LIQ_PRECISION","type":"uint256"},{"internalType":"uint256","name":"_EXCHANGE_PRECISION","type":"uint256"},{"internalType":"uint256","name":"_RATE_PRECISION","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getEpoch","outputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPairAccounting","outputs":[{"internalType":"uint256","name":"_claimableFees","type":"uint256"},{"internalType":"uint128","name":"_totalBorrowAmount","type":"uint128"},{"internalType":"uint128","name":"_totalBorrowShares","type":"uint128"},{"internalType":"uint256","name":"_totalCollateral","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_forwardTo","type":"address"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getUserSnapshot","outputs":[{"internalType":"uint256","name":"_borrowShares","type":"uint256"},{"internalType":"uint256","name":"_collateralBalance","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"global_reward_integral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"invalidateReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastFeeEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_swapperAddress","type":"address"},{"internalType":"uint256","name":"_borrowAmount","type":"uint256"},{"internalType":"uint256","name":"_initialUnderlyingAmount","type":"uint256"},{"internalType":"uint256","name":"_amountCollateralOutMin","type":"uint256"},{"internalType":"address[]","name":"_path","type":"address[]"}],"name":"leveragedPosition","outputs":[{"internalType":"uint256","name":"_totalCollateralBalance","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_borrower","type":"address"}],"name":"liquidate","outputs":[{"internalType":"uint256","name":"_collateralForLiquidator","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidationFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLTV","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"minimumBorrowAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumLeftoverDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumRedemption","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"previewAddInterest","outputs":[{"internalType":"uint256","name":"_interestEarned","type":"uint256"},{"components":[{"internalType":"uint64","name":"lastTimestamp","type":"uint64"},{"internalType":"uint64","name":"ratePerSec","type":"uint64"},{"internalType":"uint128","name":"lastShares","type":"uint128"}],"internalType":"struct ResupplyPairCore.CurrentRateInfo","name":"_newCurrentRateInfo","type":"tuple"},{"internalType":"uint256","name":"_claimableFees","type":"uint256"},{"components":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"shares","type":"uint128"}],"internalType":"struct VaultAccount","name":"_totalBorrow","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolRedemptionFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rateCalculator","outputs":[{"internalType":"contract IRateCalculator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_caller","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_totalFeePct","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"redeemCollateral","outputs":[{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"uint256","name":"_collateralFreed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redemptionWriteOff","outputs":[{"internalType":"contract WriteOffToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"removeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_collateralAmount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"removeCollateralVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_borrower","type":"address"}],"name":"repay","outputs":[{"internalType":"uint256","name":"_amountToRepay","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapperAddress","type":"address"},{"internalType":"uint256","name":"_collateralToSwap","type":"uint256"},{"internalType":"uint256","name":"_amountOutMin","type":"uint256"},{"internalType":"address[]","name":"_path","type":"address[]"}],"name":"repayWithCollateral","outputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardMap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardRedirect","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"reward_integral_for","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewards","outputs":[{"internalType":"address","name":"reward_token","type":"address"},{"internalType":"bool","name":"is_non_claimable","type":"bool"},{"internalType":"uint256","name":"reward_remaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"setBorrowLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"setConvexPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newLiquidationFee","type":"uint256"}],"name":"setLiquidationFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMaxLTV","type":"uint256"}],"name":"setMaxLTV","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_min","type":"uint256"}],"name":"setMinimumBorrowAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_min","type":"uint256"}],"name":"setMinimumLeftoverDebt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_min","type":"uint256"}],"name":"setMinimumRedemption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMintFee","type":"uint256"}],"name":"setMintFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOracle","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setProtocolRedemptionFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newRateCalculator","type":"address"},{"internalType":"bool","name":"_updateInterest","type":"bool"}],"name":"setRateCalculator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"setRewardRedirect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapper","type":"address"},{"internalType":"bool","name":"_approval","type":"bool"}],"name":"setSwapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"swappers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"bool","name":"_roundUp","type":"bool"},{"internalType":"bool","name":"_previewInterest","type":"bool"}],"name":"toBorrowAmount","outputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_roundUp","type":"bool"},{"internalType":"bool","name":"_previewInterest","type":"bool"}],"name":"toBorrowShares","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrow","outputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint128","name":"shares","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCollateral","outputs":[{"internalType":"uint256","name":"_totalCollateralBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebtAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateExchangeRate","outputs":[{"internalType":"uint256","name":"_exchangeRate","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"userBorrowShares","outputs":[{"internalType":"uint256","name":"borrowShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"userCollateralBalance","outputs":[{"internalType":"uint256","name":"_collateralAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRewardEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_epochloops","type":"uint256"}],"name":"user_checkpoint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"_major","type":"uint256"},{"internalType":"uint256","name":"_minor","type":"uint256"},{"internalType":"uint256","name":"_patch","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"withdrawFees","outputs":[{"internalType":"uint256","name":"_fees","type":"uint256"},{"internalType":"uint256","name":"_otherFees","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]