Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/zaps/FlashLoanLoopingFactory.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import {ISizeFactory} from "@size/src/factory/interfaces/ISizeFactory.sol";
import {Errors} from "@size/src/market/libraries/Errors.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {PauseUnpause} from "src/utils/PauseUnpause.sol";
import {RecoverTokens} from "src/utils/RecoverTokens.sol";
import {PAUSER_ROLE} from "@size/src/factory/interfaces/ISizeFactory.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {IMorpho} from "@morpho/src/interfaces/IMorpho.sol";
import {IUniswapV2Router02} from "src/interfaces/dex/IUniswapV2Router02.sol";
import {IUniswapV3Router} from "src/interfaces/dex/IUniswapV3Router.sol";
import {IPAllActionV3} from "@pendle/contracts/interfaces/IPAllActionV3.sol";
import {IPMarketFactoryV3} from "@pendle/contracts/interfaces/IPMarketFactoryV3.sol";
import {IFlashLoanLoopingFactory} from "src/zaps/IFlashLoanLoopingFactory.sol";
import {ISafe} from "@size/script/interfaces/ISafe.sol";
import {Math, PERCENT, YEAR} from "@size/src/market/libraries/Math.sol";
import {Math as MathUtils} from "@openzeppelin/contracts/utils/math/Math.sol";
import {DataView} from "@size/src/market/SizeViewData.sol";
import {ISize} from "@size/src/market/interfaces/ISize.sol";
import {IPriceFeed} from "@size/src/oracle/IPriceFeed.sol";
import {IFlashLoanLooping} from "src/zaps/IFlashLoanLooping.sol";
contract FlashLoanLoopingFactory is
AccessControlUpgradeable,
RecoverTokens,
PauseUnpause,
UUPSUpgradeable,
IFlashLoanLoopingFactory
{
using SafeERC20 for IERC20;
using SafeERC20 for IERC20Metadata;
uint256 public constant MAX_LEVERAGE_PERCENT_BUFFER = 0.02e18;
uint256 public constant FLASH_LOAN_AMOUNT_DUST = 10;
// STORAGE
/// @custom:storage-location erc7201:size.storage.FlashLoanLoopingFactory
struct FlashLoanLoopingFactoryStorage {
ISizeFactory _sizeFactory;
IFlashLoanLooping _flashLoanLoopingImplementation;
IMorpho _morpho;
IUniswapV2Router02 _uniswapV2Router;
IUniswapV3Router _uniswapV3Router;
IPAllActionV3 _pendleRouter;
IPMarketFactoryV3 _pendleMarketFactory;
address _cashStrategyVault;
}
// keccak256(abi.encode(uint256(keccak256("size.storage.FlashLoanLoopingFactory")) - 1)) & ~bytes32(uint256(0xff));
// forge-lint: disable-next-line(screaming-snake-case-const)
bytes32 private constant FlashLoanLoopingFactoryStorageLocation =
0x5801605739543a14df67a3af524d619d76ce8995e89cf0f4e54ba3c5d66ca000;
function _getFlashLoanLoopingFactoryStorage() private pure returns (FlashLoanLoopingFactoryStorage storage $) {
assembly {
$.slot := FlashLoanLoopingFactoryStorageLocation
}
}
// CONSTRUCTOR/INITIALIZER
constructor() {
/// @custom:oz-upgrades-unsafe-allow constructor
_disableInitializers();
}
function initialize(
address _admin,
ISizeFactory _sizeFactory,
IFlashLoanLooping _flashLoanLoopingImplementation,
IMorpho _morpho,
IUniswapV2Router02 _uniswapV2Router,
IUniswapV3Router _uniswapV3Router,
IPAllActionV3 _pendleRouter,
IPMarketFactoryV3 _pendleMarketFactory,
address _cashStrategyVault
) public initializer {
if (
address(_admin) == address(0) || address(_sizeFactory) == address(0)
|| address(_flashLoanLoopingImplementation) == address(0) || address(_morpho) == address(0)
|| address(_uniswapV2Router) == address(0) || address(_uniswapV3Router) == address(0)
|| address(_pendleRouter) == address(0) || address(_pendleMarketFactory) == address(0)
|| address(_cashStrategyVault) == address(0)
) {
revert Errors.NULL_ADDRESS();
}
__AccessControl_init();
__Pausable_init();
__UUPSUpgradeable_init();
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
_grantRole(PAUSER_ROLE, _admin);
FlashLoanLoopingFactoryStorage storage $ = _getFlashLoanLoopingFactoryStorage();
$._sizeFactory = _sizeFactory;
$._flashLoanLoopingImplementation = _flashLoanLoopingImplementation;
$._morpho = _morpho;
$._uniswapV2Router = _uniswapV2Router;
$._uniswapV3Router = _uniswapV3Router;
$._pendleRouter = _pendleRouter;
$._pendleMarketFactory = _pendleMarketFactory;
$._cashStrategyVault = _cashStrategyVault;
_setPauserRole(_admin);
}
function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) {}
function setFlashLoanLoopingImplementation(IFlashLoanLooping _flashLoanLoopingImplementation)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
if (address(_flashLoanLoopingImplementation) == address(0)) {
revert Errors.NULL_ADDRESS();
}
FlashLoanLoopingFactoryStorage storage $ = _getFlashLoanLoopingFactoryStorage();
$._flashLoanLoopingImplementation = _flashLoanLoopingImplementation;
}
function deploy(address onBehalfOf, bytes32 extraSalt)
public
whenNotPaused
returns (IFlashLoanLooping flashLoanLooping)
{
bytes32 salt = _salt(onBehalfOf, extraSalt);
flashLoanLooping =
IFlashLoanLooping(Clones.cloneDeterministic(address(flashLoanLoopingImplementation()), salt, 0));
IFlashLoanLooping(flashLoanLooping).initialize(this, onBehalfOf);
}
function deploy(bytes32 extraSalt) external /*whenNotPaused*/ returns (IFlashLoanLooping flashLoanLooping) {
return deploy(msg.sender, extraSalt);
}
function _salt(address onBehalfOf, bytes32 extraSalt) private pure returns (bytes32) {
return keccak256(abi.encode(onBehalfOf, extraSalt));
}
function _setPauserRole(address _admin) private {
(bool success, bytes memory data) = address(_admin).staticcall(abi.encodeWithSelector(ISafe.getOwners.selector));
if (success) {
address[] memory owners = abi.decode(data, (address[]));
for (uint256 i = 0; i < owners.length; i++) {
_grantRole(PAUSER_ROLE, owners[i]);
}
}
}
// VIEW
function computeAddress(address onBehalfOf, bytes32 extraSalt) public view returns (address) {
bytes32 salt = _salt(onBehalfOf, extraSalt);
return Clones.predictDeterministicAddress(address(flashLoanLoopingImplementation()), salt, address(this));
}
function exists(address onBehalfOf, bytes32 extraSalt) external view returns (bool) {
address expectedAddress = computeAddress(onBehalfOf, extraSalt);
return expectedAddress.code.length > 0;
}
function currentLeveragePercent(ISize size, address account) public view returns (uint256) {
if (!sizeFactory().isMarket(address(size))) {
revert Errors.INVALID_MARKET(address(size));
}
DataView memory dataView = size.data();
uint256 totalCollateral = dataView.collateralToken.balanceOf(account);
uint256 totalDebt = dataView.debtToken.balanceOf(account);
// Convert debt to collateral terms to get K (additional collateral from borrowed amount)
uint256 debtInCollateral = size.debtTokenAmountToCollateralTokenAmount(totalDebt);
uint256 initialCollateral = MathUtils.saturatingSub(totalCollateral, debtInCollateral);
// L = (C + K) / C where C is initial collateral, K is additional collateral from leverage
if (initialCollateral == 0) {
return PERCENT; // L = 1 (100%) when no initial collateral
}
return Math.mulDivDown(totalCollateral, PERCENT, initialCollateral);
}
function theoreticalMaxLeveragePercent(ISize size) public view returns (uint256) {
if (!sizeFactory().isMarket(address(size))) {
revert Errors.INVALID_MARKET(address(size));
}
uint256 crOpening = size.riskConfig().crOpening;
return Math.mulDivDown(crOpening, PERCENT, crOpening - PERCENT);
}
/// @notice Calculate maximum achievable leverage given market conditions
/// @dev Implements: L_m = 1 + [R_o(1-s)] / [(1+r)/(1-k*ΔT) - R_o(1-s)]
function maxLeveragePercent(ISize size, uint256 dexSlippagePercent, uint256 apr, uint256 tenor)
public
view
returns (uint256)
{
if (!sizeFactory().isMarket(address(size))) {
revert Errors.INVALID_MARKET(address(size));
}
uint256 R_0 = Math.mulDivDown(PERCENT, PERCENT, size.riskConfig().crOpening);
uint256 numerator = Math.mulDivDown(R_0, PERCENT - dexSlippagePercent, PERCENT);
uint256 swapFeePercent = Math.mulDivDown(size.feeConfig().swapFeeAPR, tenor, YEAR);
uint256 ratePerTenor = Math.aprToRatePerTenor(apr, tenor);
uint256 sizeSlippage = Math.mulDivDown(PERCENT + ratePerTenor, PERCENT, PERCENT - swapFeePercent);
uint256 denominator = sizeSlippage - numerator;
uint256 L_m = PERCENT + Math.mulDivDown(numerator, PERCENT, denominator);
return Math.mulDivDown(L_m, PERCENT - MAX_LEVERAGE_PERCENT_BUFFER, PERCENT);
}
/// @notice Calculate the borrow amount B needed from Size to achieve target leverage
/// @dev This is the amount that will be borrowed from Size (SellCreditMarket amount parameter)
/// @dev From specs: L = (C + K) / C where K = C * (L - 1), and B is K converted to debt token
function estimateSellCreditMarketAmount(ISize size, address user, uint256 targetLeveragePercent)
public
view
returns (uint256)
{
DataView memory dataView = size.data();
return estimateSellCreditMarketAmount(
size, dataView.collateralToken.balanceOf(user), dataView.debtToken.balanceOf(user), targetLeveragePercent
);
}
/// @dev Same as estimateSellCreditMarketAmount, but
function estimateSellCreditMarketAmount(
ISize size,
uint256 currentCollateral,
uint256 currentDebt,
uint256 targetLeveragePercent
) public view returns (uint256) {
if (!sizeFactory().isMarket(address(size))) {
revert Errors.INVALID_MARKET(address(size));
}
// Calculate initial collateral C (current collateral minus debt converted to collateral)
uint256 currentDebtInCollateral = size.debtTokenAmountToCollateralTokenAmount(currentDebt);
uint256 initialCollateral = MathUtils.saturatingSub(currentCollateral, currentDebtInCollateral);
// From L = (C + K) / C, we get K = C * (L - 1)
// where K is additional collateral needed
uint256 additionalCollateralNeeded = Math.mulDivUp(initialCollateral, targetLeveragePercent - PERCENT, PERCENT);
// B = K converted to debt token amount
return collateralTokenAmountToDebtTokenAmount(size, additionalCollateralNeeded);
}
/// @notice Calculate the flash loan amount needed to achieve target leverage
/// @dev In theory, this should be equal to the SellCreditMarket amount. However, due to slippage in fullWithdraw, we may receive less than the borrowed amount
function estimateFlashLoanAmount(ISize size, address user, uint256 targetLeveragePercent)
public
view
returns (uint256)
{
uint256 theoreticalFlashLoanAmount = estimateSellCreditMarketAmount(size, user, targetLeveragePercent);
return MathUtils.saturatingSub(theoreticalFlashLoanAmount, FLASH_LOAN_AMOUNT_DUST);
}
/// @dev Same as estimateFlashLoanAmount, but with estimated initial collateral
function estimateFlashLoanAmount(
ISize size,
uint256 estimatedInitialCollateral,
uint256 estimatedInitialDebt,
uint256 targetLeveragePercent
) public view returns (uint256) {
uint256 theoreticalFlashLoanAmount = estimateSellCreditMarketAmount(
size, estimatedInitialCollateral, estimatedInitialDebt, targetLeveragePercent
);
return MathUtils.saturatingSub(theoreticalFlashLoanAmount, FLASH_LOAN_AMOUNT_DUST);
}
// CR = (C + D * (1-s) + D_0) / (D + D_0)
function estimateCollateralRatio(
ISize size,
address user,
uint256 targetLeveragePercent,
uint256 dexSlippagePercent,
uint256 apr,
uint256 tenor
) public view returns (uint256) {
DataView memory dataView = size.data();
return estimateCollateralRatio(
size,
dataView.collateralToken.balanceOf(user),
dataView.debtToken.balanceOf(user),
targetLeveragePercent,
dexSlippagePercent,
apr,
tenor
);
}
function estimateCollateralRatio(
ISize size,
uint256 currentCollateral,
uint256 currentDebt,
uint256 targetLeveragePercent,
uint256 dexSlippagePercent,
uint256 apr,
uint256 tenor
) public view returns (uint256) {
uint256 sellCreditMarketAmount =
estimateSellCreditMarketAmount(size, currentCollateral, currentDebt, targetLeveragePercent);
uint256 swapFeePercent = Math.mulDivDown(size.feeConfig().swapFeeAPR, tenor, YEAR);
uint256 ratePerTenor = Math.aprToRatePerTenor(apr, tenor);
uint256 sizeSlippage = Math.mulDivDown(PERCENT + ratePerTenor, PERCENT, PERCENT - swapFeePercent);
uint256 additionalDebt = Math.mulDivDown(sellCreditMarketAmount, sizeSlippage, PERCENT);
uint256 initialCollateralInCash = collateralTokenAmountToDebtTokenAmount(size, currentCollateral);
uint256 initialDebt = currentDebt;
uint256 additionalCollateralInCash = Math.mulDivDown(additionalDebt, PERCENT - dexSlippagePercent, PERCENT);
return Math.mulDivDown(
initialCollateralInCash + additionalCollateralInCash + initialDebt, PERCENT, additionalDebt + initialDebt
);
}
function collateralTokenAmountToDebtTokenAmount(ISize size, uint256 collateralTokenAmount)
public
view
returns (uint256)
{
if (!sizeFactory().isMarket(address(size))) {
revert Errors.INVALID_MARKET(address(size));
}
DataView memory dataView = size.data();
IPriceFeed priceFeed = IPriceFeed(size.oracle().priceFeed);
return Math.mulDivUp(
collateralTokenAmount * priceFeed.getPrice(),
10 ** dataView.underlyingBorrowToken.decimals(),
10 ** priceFeed.decimals() * 10 ** dataView.underlyingCollateralToken.decimals()
);
}
// STORAGE VIEW
function sizeFactory() public view override returns (ISizeFactory) {
FlashLoanLoopingFactoryStorage storage $ = _getFlashLoanLoopingFactoryStorage();
return $._sizeFactory;
}
function flashLoanLoopingImplementation() public view override returns (IFlashLoanLooping) {
FlashLoanLoopingFactoryStorage storage $ = _getFlashLoanLoopingFactoryStorage();
return $._flashLoanLoopingImplementation;
}
function morpho() public view override returns (IMorpho) {
FlashLoanLoopingFactoryStorage storage $ = _getFlashLoanLoopingFactoryStorage();
return $._morpho;
}
function uniswapV2Router() public view override returns (IUniswapV2Router02) {
FlashLoanLoopingFactoryStorage storage $ = _getFlashLoanLoopingFactoryStorage();
return $._uniswapV2Router;
}
function uniswapV3Router() public view override returns (IUniswapV3Router) {
FlashLoanLoopingFactoryStorage storage $ = _getFlashLoanLoopingFactoryStorage();
return $._uniswapV3Router;
}
function pendleRouter() public view override returns (IPAllActionV3) {
FlashLoanLoopingFactoryStorage storage $ = _getFlashLoanLoopingFactoryStorage();
return $._pendleRouter;
}
function pendleMarketFactory() public view override returns (IPMarketFactoryV3) {
FlashLoanLoopingFactoryStorage storage $ = _getFlashLoanLoopingFactoryStorage();
return $._pendleMarketFactory;
}
function cashStrategyVault() public view override returns (address) {
FlashLoanLoopingFactoryStorage storage $ = _getFlashLoanLoopingFactoryStorage();
return $._cashStrategyVault;
}
}
"
},
"lib/size-solidity/src/factory/interfaces/ISizeFactory.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import {IPool} from "@aave/interfaces/IPool.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {
InitializeDataParams,
InitializeFeeConfigParams,
InitializeOracleParams,
InitializeRiskConfigParams
} from "@src/market/libraries/actions/Initialize.sol";
import {ISize} from "@src/market/interfaces/ISize.sol";
import {NonTransferrableRebasingTokenVault} from "@src/market/token/NonTransferrableRebasingTokenVault.sol";
import {PriceFeed, PriceFeedParams} from "@src/oracle/v1.5.1/PriceFeed.sol";
import {ISizeFactoryOffchainGetters} from "@src/factory/interfaces/ISizeFactoryOffchainGetters.sol";
import {ISizeFactoryV1_7} from "@src/factory/interfaces/ISizeFactoryV1_7.sol";
import {ISizeFactoryV1_8} from "@src/factory/interfaces/ISizeFactoryV1_8.sol";
bytes32 constant KEEPER_ROLE = keccak256("KEEPER_ROLE");
bytes32 constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 constant BORROW_RATE_UPDATER_ROLE = keccak256("BORROW_RATE_UPDATER_ROLE");
bytes32 constant DEFAULT_ADMIN_ROLE = 0x00;
/// @title ISizeFactory
/// @custom:security-contact security@size.credit
/// @author Size (https://size.credit/)
/// @notice The interface for the size factory
interface ISizeFactory is ISizeFactoryOffchainGetters, ISizeFactoryV1_7, ISizeFactoryV1_8 {
/// @notice Set the size implementation
/// @param _sizeImplementation The new size implementation
function setSizeImplementation(address _sizeImplementation) external;
/// @notice Set the non-transferrable token vault implementation
/// @param _nonTransferrableTokenVaultImplementation The new non-transferrable token vault implementation
function setNonTransferrableRebasingTokenVaultImplementation(address _nonTransferrableTokenVaultImplementation)
external;
/// @notice Creates a new market
/// @dev The contract owner is set as the owner of the market
function createMarket(
InitializeFeeConfigParams calldata feeConfigParams,
InitializeRiskConfigParams calldata riskConfigParams,
InitializeOracleParams calldata oracleParams,
InitializeDataParams calldata dataParams
) external returns (ISize);
/// @notice Creates a new borrow token vault
/// @dev The contract owner is set as the owner of the borrow token vault
/// The borrow token vault needs to have adapters set after initialization
function createBorrowTokenVault(IPool variablePool, IERC20Metadata underlyingBorrowToken)
external
returns (NonTransferrableRebasingTokenVault);
/// @notice Creates a new price feed
function createPriceFeed(PriceFeedParams calldata priceFeedParams) external returns (PriceFeed);
/// @notice Check if an address is a registered market
/// @param candidate The candidate to check
/// @return True if the candidate is a registered market
function isMarket(address candidate) external view returns (bool);
}
"
},
"lib/size-solidity/src/market/libraries/Errors.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
/// @title Errors
/// @custom:security-contact security@size.credit
/// @author Size (https://size.credit/)
library Errors {
error MUST_IMPROVE_COLLATERAL_RATIO(address account, uint256 crBefore, uint256 crAfter);
error NULL_ADDRESS();
error NULL_AMOUNT();
error NULL_TENOR();
error NULL_MAX_DUE_DATE();
error NULL_ARRAY();
error NULL_OFFER();
error INVALID_MSG_VALUE(uint256 value);
error INVALID_AMOUNT(uint256 amount);
error INVALID_VAULT(address vault);
error INVALID_ADAPTER(uint256 adapter);
error TENORS_NOT_STRICTLY_INCREASING();
error ARRAY_LENGTHS_MISMATCH();
error INVALID_TOKEN(address token);
error INVALID_KEY(string key);
error INVALID_COLLATERAL_RATIO(uint256 cr);
error INVALID_COLLATERAL_PERCENTAGE_PREMIUM(uint256 percentage);
error INVALID_MAXIMUM_TENOR(uint256 maxTenor);
error VALUE_GREATER_THAN_MAX(uint256 value, uint256 max);
error INVALID_LIQUIDATION_COLLATERAL_RATIO(uint256 crOpening, uint256 crLiquidation);
error INVALID_TENOR_RANGE(uint256 minTenor, uint256 maxTenor);
error INVALID_APR_RANGE(uint256 minAPR, uint256 maxAPR);
error INVALID_ADDRESS(address account);
error PAST_DEADLINE(uint256 deadline);
error PAST_MAX_DUE_DATE(uint256 maxDueDate);
error APR_LOWER_THAN_MIN_APR(uint256 apr, uint256 minAPR);
error APR_GREATER_THAN_MAX_APR(uint256 apr, uint256 maxAPR);
error DUE_DATE_NOT_COMPATIBLE(uint256 dueDate1, uint256 dueDate2);
error DUE_DATE_GREATER_THAN_MAX_DUE_DATE(uint256 dueDate, uint256 maxDueDate);
error TENOR_OUT_OF_RANGE(uint256 tenor, uint256 minTenor, uint256 maxTenor);
error INVERTED_CURVES(address account, uint256 tenor);
error INVALID_POSITION_ID(uint256 positionId);
error INVALID_DEBT_POSITION_ID(uint256 debtPositionId);
error INVALID_CREDIT_POSITION_ID(uint256 creditPositionId);
error INVALID_LENDER(address account);
error INVALID_BORROWER(address account);
error INVALID_OFFER_CONFIGS(
uint256 minTenorBorrowOffer,
uint256 maxTenorBorrowOffer,
uint256 minAPRBorrowOffer,
uint256 maxAPRBorrowOffer,
uint256 minTenorLoanOffer,
uint256 maxTenorLoanOffer,
uint256 minAPRLoanOffer,
uint256 maxAPRLoanOffer
);
error INVALID_LOAN_OFFER(address lender);
error INVALID_BORROW_OFFER(address borrower);
error INVALID_OFFER(address account);
error CREDIT_NOT_FOR_SALE(uint256 creditPositionId);
error NOT_ENOUGH_CREDIT(uint256 credit, uint256 required);
error NOT_ENOUGH_CASH(uint256 cash, uint256 required);
error BORROWER_IS_NOT_LENDER(address borrower, address lender);
error COMPENSATOR_IS_NOT_BORROWER(address compensator, address borrower);
error LIQUIDATOR_IS_NOT_LENDER(address liquidator, address lender);
error NOT_ENOUGH_BORROW_ATOKEN_BALANCE(address account, uint256 balance, uint256 required);
error CREDIT_LOWER_THAN_MINIMUM_CREDIT(uint256 credit, uint256 minimumCreditBorrowToken);
error CREDIT_LOWER_THAN_MINIMUM_CREDIT_OPENING(uint256 credit, uint256 minimumCreditBorrowToken);
error CREDIT_POSITION_ALREADY_CLAIMED(uint256 positionId);
error CREDIT_POSITION_NOT_TRANSFERRABLE(uint256 creditPositionId, uint8 loanStatus, uint256 borrowerCR);
error LOAN_ALREADY_REPAID(uint256 positionId);
error LOAN_NOT_REPAID(uint256 positionId);
error LOAN_NOT_ACTIVE(uint256 positionId);
error LOAN_NOT_LIQUIDATABLE(uint256 debtPositionId, uint256 cr, uint8 loanStatus);
error LOAN_NOT_SELF_LIQUIDATABLE(uint256 creditPositionId, uint256 cr, uint8 loanStatus);
error LIQUIDATE_PROFIT_BELOW_MINIMUM_COLLATERAL_PROFIT(
uint256 liquidatorProfitCollateralToken, uint256 minimumCollateralProfit
);
error CR_BELOW_OPENING_LIMIT_BORROW_CR(address account, uint256 cr, uint256 riskCollateralRatio);
error INVALID_DECIMALS(uint8 decimals);
error INVALID_PRICE(address aggregator, int256 price);
error STALE_PRICE(address aggregator, uint256 updatedAt);
error INVALID_STALE_PRICE_INTERVAL(uint256 a, uint256 b);
error NULL_STALE_PRICE();
error NULL_STALE_RATE();
error STALE_RATE(uint128 updatedAt);
error BORROW_TOKEN_INCREASE_EXCEEDS_DEBT_TOKEN_DECREASE(uint256 borrowTokenIncrease, uint256 debtTokenDecrease);
error NOT_SUPPORTED();
error REINITIALIZE_MIGRATION_EXPECTED_IN_ONE_TRANSACTION(uint256 totalSupply);
error REINITIALIZE_ALL_CLAIMS_PRESERVED(
uint256 newScaledTotalSupplyAfter, uint256 newScaledTotalSupplyBefore, uint256 oldScaledTotalSupply
);
error REINITIALIZE_INSOLVENT(uint256 newTotalSupplyAfter, uint256 newTotalSupplyBefore, uint256 aTokenBalance);
error REINITIALIZE_PER_USER_CHECK(uint256 expected, uint256 actual);
error REINITIALIZE_PER_USER_CHECK_DELTA(uint256 expected, uint256 actual);
error SEQUENCER_DOWN();
error GRACE_PERIOD_NOT_OVER();
error ALREADY_INITIALIZED(address account);
error UNAUTHORIZED(address account);
error UNAUTHORIZED_ACTION(address account, address onBehalfOf, uint8 action);
error INVALID_ACTION(uint8 action);
error INVALID_ACTIONS_BITMAP(uint256 actionsBitmap);
error INVALID_TWAP_WINDOW();
error INVALID_AVERAGE_BLOCK_TIME();
error INVALID_MARKET(address market);
error PAUSED_MARKET(address market);
}
"
},
"lib/size-solidity/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
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);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
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);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
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));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
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));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
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));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
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)
// bubble errors
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));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
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);
}
}
"
},
"lib/size-solidity/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
"
},
"lib/size-solidity/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
"
},
"lib/size-solidity/lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
struct AccessControlStorage {
mapping(bytes32 role => RoleData) _roles;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
assembly {
$.slot := AccessControlStorageLocation
}
}
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
AccessControlStorage storage $ = _getAccessControlStorage();
return $._roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
AccessControlStorage storage $ = _getAccessControlStorage();
bytes32 previousAdminRole = getRoleAdmin(role);
$._roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (!hasRole(role, account)) {
$._roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
AccessControlStorage storage $ = _getAccessControlStorage();
if (hasRole(role, account)) {
$._roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
"
},
"lib/size-solidity/lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.22;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC-1967 compliant implementation pointing to self.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC-1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}
"
},
"src/utils/PauseUnpause.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import {PAUSER_ROLE} from "@src/factory/interfaces/ISizeFactory.sol";
abstract contract PauseUnpause is AccessControlUpgradeable, PausableUpgradeable {
function pause() external onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() external onlyRole(PAUSER_ROLE) {
_unpause();
}
}
"
},
"src/utils/RecoverTokens.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;
import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
abstract contract RecoverTokens is AccessControlUpgradeable, PausableUpgradeable {
using SafeERC20 for IERC20;
function recover(address token, address to, uint256 amount) external whenNotPaused onlyRole(DEFAULT_ADMIN_ROLE) {
IERC20(token).safeTransfer(to, amount);
}
}
"
},
"lib/size-solidity/lib/openzeppelin-contracts/contracts/proxy/Clones.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/Clones.sol)
pragma solidity ^0.8.20;
import {Create2} from "../utils/Create2.sol";
import {Errors} from "../utils/Errors.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library Clones {
error CloneArgumentsTooLong();
/**
* @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
return clone(implementation, 0);
}
/**
* @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency
* to the new contract.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function clone(address implementation, uint256 value) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
assembly ("memory-safe") {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(value, 0x09, 0x37)
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple times will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
return cloneDeterministic(implementation, salt, 0);
}
/**
* @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with
* a `value` parameter to send native currency to the new contract.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function cloneDeterministic(
address implementation,
bytes32 salt,
uint256 value
) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
assembly ("memory-safe") {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(value, 0x09, 0x37, salt)
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
/**
* @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
* immutable arguments. These are provided through `args` and cannot be changed after deployment. To
* access the arguments within the implementation, use {fetchCloneArgs}.
*
* This function uses the create opcode, which should never revert.
*/
function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {
return cloneWithImmutableArgs(implementation, args, 0);
}
/**
* @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`
* parameter to send native currency to the new contract.
*
* NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
* to always have enough balance for new deployments. Consider exposing this function under a payable method.
*/
function cloneWithImmutableArgs(
address implementation,
bytes memory args,
uint256 value
) internal returns (address instance) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
assembly ("memory-safe") {
instance := create(value, add(bytecode, 0x20), mload(bytecode))
}
if (instance == address(0)) {
revert Errors.FailedDeployment();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
* immutable arguments. These are provided through `args` and cannot be changed after deployment. To
* access the arguments within the implementation, use {fetchCloneArgs}.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same
* `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice
* at the same address.
*/
function cloneDeterm
Submitted on: 2025-10-29 18:51:08
Comments
Log in to comment.
No comments yet.