// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Constants} from "../Constants.sol";
import {DataTypesPeerToPeer} from "./DataTypesPeerToPeer.sol";
import {Errors} from "../Errors.sol";
import {IAddressRegistry} from "./interfaces/IAddressRegistry.sol";
import {IBaseCompartment} from "./interfaces/compartments/IBaseCompartment.sol";
import {IBorrowerGateway} from "./interfaces/IBorrowerGateway.sol";
import {ILenderVaultImpl} from "./interfaces/ILenderVaultImpl.sol";
import {IMysoTokenManager} from "../interfaces/IMysoTokenManager.sol";
import {IQuoteHandler} from "./interfaces/IQuoteHandler.sol";
import {IVaultCallback} from "./interfaces/IVaultCallback.sol";
contract BorrowerGateway is ReentrancyGuard, IBorrowerGateway {
using SafeERC20 for IERC20Metadata;
// putting fee info in borrow gateway since borrower always pays this upfront
address public immutable addressRegistry;
// index 0: base protocol fee is paid even for swap (no tenor)
// index 1: protocol fee slope scales protocol fee with tenor
uint128[2] internal protocolFeeParams;
constructor(address _addressRegistry) {
if (_addressRegistry == address(0)) {
revert Errors.InvalidAddress();
}
addressRegistry = _addressRegistry;
}
function borrowWithOffChainQuote(
address lenderVault,
DataTypesPeerToPeer.BorrowTransferInstructions
calldata borrowInstructions,
DataTypesPeerToPeer.OffChainQuote calldata offChainQuote,
DataTypesPeerToPeer.QuoteTuple calldata quoteTuple,
bytes32[] calldata proof
) external nonReentrant returns (DataTypesPeerToPeer.Loan memory) {
_checkDeadlineAndRegisteredVault(
borrowInstructions.deadline,
lenderVault
);
{
address quoteHandler = IAddressRegistry(addressRegistry)
.quoteHandler();
IQuoteHandler(quoteHandler).checkAndRegisterOffChainQuote(
msg.sender,
lenderVault,
offChainQuote,
quoteTuple,
proof
);
}
(
DataTypesPeerToPeer.Loan memory loan,
uint256 loanId,
uint256 upfrontFee
) = _processBorrowTransaction(
borrowInstructions,
offChainQuote.generalQuoteInfo,
quoteTuple,
lenderVault
);
emit Borrowed(
lenderVault,
loan.borrower,
loan,
upfrontFee,
loanId,
borrowInstructions.callbackAddr,
borrowInstructions.callbackData
);
return loan;
}
function borrowWithOnChainQuote(
address lenderVault,
DataTypesPeerToPeer.BorrowTransferInstructions
calldata borrowInstructions,
DataTypesPeerToPeer.OnChainQuote calldata onChainQuote,
uint256 quoteTupleIdx
) external nonReentrant returns (DataTypesPeerToPeer.Loan memory) {
// borrow gateway just forwards data to respective vault and orchestrates transfers
// borrow gateway is oblivious towards and specific borrow details, and only fwds info
// vaults needs to check details of given quote and whether it's valid
// all lenderVaults need to approve BorrowGateway
// 1. BorrowGateway "optimistically" pulls loanToken from lender vault: either transfers directly to (a) borrower or (b) callbacker for further processing
// 2. BorrowGateway then pulls collToken from borrower to lender vault
// 3. Finally, BorrowGateway updates lender vault storage state
_checkDeadlineAndRegisteredVault(
borrowInstructions.deadline,
lenderVault
);
{
address quoteHandler = IAddressRegistry(addressRegistry)
.quoteHandler();
IQuoteHandler(quoteHandler).checkAndRegisterOnChainQuote(
msg.sender,
lenderVault,
quoteTupleIdx,
onChainQuote
);
}
DataTypesPeerToPeer.QuoteTuple calldata quoteTuple = onChainQuote
.quoteTuples[quoteTupleIdx];
(
DataTypesPeerToPeer.Loan memory loan,
uint256 loanId,
uint256 upfrontFee
) = _processBorrowTransaction(
borrowInstructions,
onChainQuote.generalQuoteInfo,
quoteTuple,
lenderVault
);
emit Borrowed(
lenderVault,
loan.borrower,
loan,
upfrontFee,
loanId,
borrowInstructions.callbackAddr,
borrowInstructions.callbackData
);
return loan;
}
function repay(
DataTypesPeerToPeer.LoanRepayInstructions
calldata loanRepayInstructions,
address vaultAddr
) external nonReentrant {
_checkDeadlineAndRegisteredVault(
loanRepayInstructions.deadline,
vaultAddr
);
if (
loanRepayInstructions.callbackAddr != address(0) &&
IAddressRegistry(addressRegistry).whitelistState(
loanRepayInstructions.callbackAddr
) !=
DataTypesPeerToPeer.WhitelistState.CALLBACK
) {
revert Errors.NonWhitelistedCallback();
}
ILenderVaultImpl lenderVault = ILenderVaultImpl(vaultAddr);
DataTypesPeerToPeer.Loan memory loan = lenderVault.loan(
loanRepayInstructions.targetLoanId
);
if (msg.sender != loan.borrower) {
revert Errors.InvalidBorrower();
}
if (
block.timestamp < loan.earliestRepay ||
block.timestamp >= loan.expiry
) {
revert Errors.OutsideValidRepayWindow();
}
// checks repayAmount <= remaining loan balance
if (
loanRepayInstructions.targetRepayAmount == 0 ||
loanRepayInstructions.targetRepayAmount + loan.amountRepaidSoFar >
loan.initRepayAmount
) {
revert Errors.InvalidRepayAmount();
}
bool noCompartment = loan.collTokenCompartmentAddr == address(0);
// @dev: amountReclaimedSoFar cannot exceed initCollAmount for non-compartmentalized assets
uint256 maxReclaimableCollAmount = noCompartment
? loan.initCollAmount - loan.amountReclaimedSoFar
: IBaseCompartment(loan.collTokenCompartmentAddr)
.getReclaimableBalance(loan.collToken);
// @dev: amountRepaidSoFar cannot exceed initRepayAmount
uint128 leftRepaymentAmount = loan.initRepayAmount -
loan.amountRepaidSoFar;
uint128 reclaimCollAmount = SafeCast.toUint128(
(maxReclaimableCollAmount *
uint256(loanRepayInstructions.targetRepayAmount)) /
uint256(leftRepaymentAmount)
);
if (reclaimCollAmount == 0) {
revert Errors.ReclaimAmountIsZero();
}
lenderVault.updateLoanInfo(
loanRepayInstructions.targetRepayAmount,
loanRepayInstructions.targetLoanId,
reclaimCollAmount,
noCompartment,
loan.collToken
);
_processRepayTransfers(
vaultAddr,
loanRepayInstructions,
loan,
leftRepaymentAmount,
reclaimCollAmount,
noCompartment
);
emit Repaid(
vaultAddr,
loanRepayInstructions.targetLoanId,
loanRepayInstructions.targetRepayAmount
);
}
/**
* @notice Protocol fee is allowed to be zero, so no min fee checks, only max fee checks
*/
function setProtocolFeeParams(uint128[2] calldata _newFeeParams) external {
if (msg.sender != IAddressRegistry(addressRegistry).owner()) {
revert Errors.InvalidSender();
}
if (
_newFeeParams[0] > Constants.MAX_SWAP_PROTOCOL_FEE ||
_newFeeParams[1] > Constants.MAX_FEE_PER_ANNUM ||
(_newFeeParams[0] == protocolFeeParams[0] &&
_newFeeParams[1] == protocolFeeParams[1])
) {
revert Errors.InvalidFee();
}
protocolFeeParams = _newFeeParams;
emit ProtocolFeeSet(_newFeeParams);
}
function getProtocolFeeParams() external view returns (uint128[2] memory) {
return protocolFeeParams;
}
function _processBorrowTransaction(
DataTypesPeerToPeer.BorrowTransferInstructions
calldata borrowInstructions,
DataTypesPeerToPeer.GeneralQuoteInfo calldata generalQuoteInfo,
DataTypesPeerToPeer.QuoteTuple calldata quoteTuple,
address lenderVault
) internal returns (DataTypesPeerToPeer.Loan memory, uint256, uint256) {
(
DataTypesPeerToPeer.Loan memory loan,
uint256 loanId,
DataTypesPeerToPeer.TransferInstructions memory transferInstructions
) = ILenderVaultImpl(lenderVault).processQuote(
msg.sender,
borrowInstructions,
generalQuoteInfo,
quoteTuple
);
_processTransfers(
lenderVault,
borrowInstructions,
loan,
transferInstructions
);
return (loan, loanId, transferInstructions.upfrontFee);
}
// solhint-disable code-complexity
function _processTransfers(
address lenderVault,
DataTypesPeerToPeer.BorrowTransferInstructions
calldata borrowInstructions,
DataTypesPeerToPeer.Loan memory loan,
DataTypesPeerToPeer.TransferInstructions memory transferInstructions
) internal {
if (
borrowInstructions.callbackAddr != address(0) &&
IAddressRegistry(addressRegistry).whitelistState(
borrowInstructions.callbackAddr
) !=
DataTypesPeerToPeer.WhitelistState.CALLBACK
) {
revert Errors.NonWhitelistedCallback();
}
ILenderVaultImpl(lenderVault).transferTo(
loan.loanToken,
borrowInstructions.callbackAddr == address(0)
? loan.borrower
: borrowInstructions.callbackAddr,
loan.initLoanAmount
);
if (borrowInstructions.callbackAddr != address(0)) {
IVaultCallback(borrowInstructions.callbackAddr).borrowCallback(
loan,
borrowInstructions.callbackData
);
}
uint128[2] memory currProtocolFeeParams = protocolFeeParams;
uint128[2] memory applicableProtocolFeeParams = currProtocolFeeParams;
address mysoTokenManager = IAddressRegistry(addressRegistry)
.mysoTokenManager();
if (mysoTokenManager != address(0)) {
applicableProtocolFeeParams = IMysoTokenManager(mysoTokenManager)
.processP2PBorrow(
applicableProtocolFeeParams,
borrowInstructions,
loan,
lenderVault
);
for (uint256 i; i < 2; ) {
if (applicableProtocolFeeParams[i] > currProtocolFeeParams[i]) {
revert Errors.InvalidFee();
}
unchecked {
++i;
}
}
}
// Note: Collateral and fees flow and breakdown is as follows:
//
// collSendAmount ("collSendAmount")
// |
// |-- protocolFeeAmount ("protocolFeeAmount")
// |
// |-- gross pledge amount
// |
// |-- gross upfront fee
// | |
// | |-- net upfront fee ("upfrontFee")
// | |
// | |-- transfer fee 1
// |
// |-- gross reclaimable collateral
// |
// |-- net reclaimable collateral ("initCollAmount")
// |
// |-- transfer fee 2 ("expectedCompartmentTransferFee")
//
// where expectedProtocolAndVaultTransferFee = protocolFeeAmount + transfer fee 1
uint256 protocolFeeAmount = _calculateProtocolFeeAmount(
applicableProtocolFeeParams,
borrowInstructions.collSendAmount,
loan.initCollAmount == 0 ? 0 : loan.expiry - block.timestamp
);
// check protocolFeeAmount <= expectedProtocolAndVaultTransferFee
if (
protocolFeeAmount >
borrowInstructions.expectedProtocolAndVaultTransferFee
) {
revert Errors.InsufficientSendAmount();
}
if (protocolFeeAmount != 0) {
// note: if coll token has a transfer fee, then protocolFeeAmount received by the protocol will be less than
// protocolFeeAmount; this is by design to not tax borrowers or lenders for transfer fees on protocol fees
IERC20Metadata(loan.collToken).safeTransferFrom(
loan.borrower,
IAddressRegistry(addressRegistry).owner(),
protocolFeeAmount
);
}
// determine any transfer fee for sending collateral to vault
uint256 collTransferFeeForSendingToVault = borrowInstructions
.expectedProtocolAndVaultTransferFee - protocolFeeAmount;
// Note: initialize the coll amount that is sent to vault in case there's no compartment
uint256 grossCollTransferAmountToVault = loan.initCollAmount +
transferInstructions.upfrontFee +
collTransferFeeForSendingToVault;
// Note: initialize the vault's expected coll balance increase in case there's no compartment
uint256 expVaultCollBalIncrease = loan.initCollAmount +
transferInstructions.upfrontFee;
if (transferInstructions.collReceiver != lenderVault) {
// Note: if there's a compartment then adjust the coll amount that is sent to vault by deducting the amount
// that goes to the compartment, i.e., the borrower's reclaimable coll amount and any associated transfer fees
grossCollTransferAmountToVault -= loan.initCollAmount;
// Note: similarly, adjust the vault's expected coll balance diff by deducting the reclaimable coll amount that
// goes to the compartment
expVaultCollBalIncrease -= loan.initCollAmount;
uint256 collReceiverPreBal = IERC20Metadata(loan.collToken)
.balanceOf(transferInstructions.collReceiver);
IERC20Metadata(loan.collToken).safeTransferFrom(
loan.borrower,
transferInstructions.collReceiver,
loan.initCollAmount +
borrowInstructions.expectedCompartmentTransferFee
);
// check that compartment balance increase matches the intended reclaimable collateral amount
if (
IERC20Metadata(loan.collToken).balanceOf(
transferInstructions.collReceiver
) != loan.initCollAmount + collReceiverPreBal
) {
revert Errors.InvalidSendAmount();
}
}
if (grossCollTransferAmountToVault > 0) {
// @dev: grossCollTransferAmountToVault can be zero in case no upfront fee and compartment is used
if (expVaultCollBalIncrease == 0) {
revert Errors.InconsistentExpVaultBalIncrease();
}
uint256 vaultPreBal = IERC20Metadata(loan.collToken).balanceOf(
lenderVault
);
IERC20Metadata(loan.collToken).safeTransferFrom(
loan.borrower,
lenderVault,
grossCollTransferAmountToVault
);
if (
IERC20Metadata(loan.collToken).balanceOf(lenderVault) !=
vaultPreBal + expVaultCollBalIncrease
) {
revert Errors.InvalidSendAmount();
}
}
}
function _processRepayTransfers(
address lenderVault,
DataTypesPeerToPeer.LoanRepayInstructions memory loanRepayInstructions,
DataTypesPeerToPeer.Loan memory loan,
uint128 leftRepaymentAmount,
uint128 reclaimCollAmount,
bool noCompartment
) internal {
noCompartment
? ILenderVaultImpl(lenderVault).transferTo(
loan.collToken,
loanRepayInstructions.callbackAddr == address(0)
? loan.borrower
: loanRepayInstructions.callbackAddr,
reclaimCollAmount
)
: ILenderVaultImpl(lenderVault).transferCollFromCompartment(
loanRepayInstructions.targetRepayAmount,
leftRepaymentAmount,
reclaimCollAmount,
loan.borrower,
loan.collToken,
loanRepayInstructions.callbackAddr,
loan.collTokenCompartmentAddr
);
if (loanRepayInstructions.callbackAddr != address(0)) {
IVaultCallback(loanRepayInstructions.callbackAddr).repayCallback(
loan,
loanRepayInstructions.callbackData
);
}
uint256 loanTokenReceived = IERC20Metadata(loan.loanToken).balanceOf(
lenderVault
);
IERC20Metadata(loan.loanToken).safeTransferFrom(
loan.borrower,
lenderVault,
loanRepayInstructions.targetRepayAmount +
loanRepayInstructions.expectedTransferFee
);
loanTokenReceived =
IERC20Metadata(loan.loanToken).balanceOf(lenderVault) -
loanTokenReceived;
if (loanTokenReceived != loanRepayInstructions.targetRepayAmount) {
revert Errors.InvalidSendAmount();
}
}
function _checkDeadlineAndRegisteredVault(
uint256 deadline,
address lenderVault
) internal view {
if (block.timestamp > deadline) {
revert Errors.DeadlinePassed();
}
if (!IAddressRegistry(addressRegistry).isRegisteredVault(lenderVault)) {
revert Errors.UnregisteredVault();
}
}
function _calculateProtocolFeeAmount(
uint128[2] memory _protocolFeeParams,
uint256 collSendAmount,
uint256 borrowDuration
) internal pure returns (uint256 protocolFeeAmount) {
bool useMaxProtocolFee = _protocolFeeParams[0] +
((_protocolFeeParams[1] * borrowDuration) /
Constants.YEAR_IN_SECONDS) >
Constants.MAX_TOTAL_PROTOCOL_FEE;
protocolFeeAmount = useMaxProtocolFee
? (collSendAmount * Constants.MAX_TOTAL_PROTOCOL_FEE) /
Constants.BASE
: ((_protocolFeeParams[0] * collSendAmount) / Constants.BASE) +
((collSendAmount * _protocolFeeParams[1] * borrowDuration) /
(Constants.YEAR_IN_SECONDS * Constants.BASE));
}
}
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.19;
library Constants {
uint256 internal constant YEAR_IN_SECONDS = 365 days;
uint256 internal constant BASE = 1e18;
uint256 internal constant MAX_FEE_PER_ANNUM = 0.05e18; // 5% max in base
uint256 internal constant MAX_SWAP_PROTOCOL_FEE = 0.01e18; // 1% max in base
uint256 internal constant MAX_TOTAL_PROTOCOL_FEE = 0.05e18; // 5% max in base
uint256 internal constant MAX_P2POOL_PROTOCOL_FEE = 0.05e18; // 5% max in base
uint256 internal constant MIN_TIME_BETWEEN_EARLIEST_REPAY_AND_EXPIRY =
1 days;
uint256 internal constant MAX_PRICE_UPDATE_TIMESTAMP_DIVERGENCE = 1 days;
uint256 internal constant SEQUENCER_GRACE_PERIOD = 1 hours;
uint256 internal constant MIN_UNSUBSCRIBE_GRACE_PERIOD = 1 days;
uint256 internal constant MAX_UNSUBSCRIBE_GRACE_PERIOD = 14 days;
uint256 internal constant MIN_CONVERSION_GRACE_PERIOD = 1 days;
uint256 internal constant MIN_REPAYMENT_GRACE_PERIOD = 1 days;
uint256 internal constant LOAN_EXECUTION_GRACE_PERIOD = 1 days;
uint256 internal constant MAX_CONVERSION_AND_REPAYMENT_GRACE_PERIOD =
30 days;
uint256 internal constant MIN_TIME_UNTIL_FIRST_DUE_DATE = 1 days;
uint256 internal constant MIN_TIME_BETWEEN_DUE_DATES = 7 days;
uint256 internal constant MIN_WAIT_UNTIL_EARLIEST_UNSUBSCRIBE = 60 seconds;
uint256 internal constant MAX_ARRANGER_FEE = 0.5e18; // 50% max in base
uint256 internal constant LOAN_TERMS_UPDATE_COOL_OFF_PERIOD = 15 minutes;
uint256 internal constant MAX_REPAYMENT_SCHEDULE_LENGTH = 20;
uint256 internal constant SINGLE_WRAPPER_MIN_MINT = 1000; // in wei
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
library DataTypesPeerToPeer {
struct Loan {
// address of borrower
address borrower;
// address of coll token
address collToken;
// address of loan token
address loanToken;
// timestamp after which any portion of loan unpaid defaults
uint40 expiry;
// timestamp before which borrower cannot repay
uint40 earliestRepay;
// initial collateral amount of loan
uint128 initCollAmount;
// loan amount given
uint128 initLoanAmount;
// full repay amount at start of loan
uint128 initRepayAmount;
// amount repaid (loan token) up until current time
// note: partial repayments are allowed
uint128 amountRepaidSoFar;
// amount reclaimed (coll token) up until current time
// note: partial repayments are allowed
uint128 amountReclaimedSoFar;
// flag tracking if collateral has been unlocked by vault
bool collUnlocked;
// address of the compartment housing the collateral
address collTokenCompartmentAddr;
}
struct QuoteTuple {
// loan amount per one unit of collateral if no oracle
// LTV in terms of the constant BASE (10 ** 18) if using oracle
uint256 loanPerCollUnitOrLtv;
// interest rate percentage in BASE (can be negative but greater than -BASE)
// i.e. -100% < interestRatePct since repay amount of 0 is not allowed
// also interestRatePctInBase is not annualized
int256 interestRatePctInBase;
// fee percentage,in BASE, which will be paid in upfront in collateral
uint256 upfrontFeePctInBase;
// length of the loan in seconds
uint256 tenor;
}
struct GeneralQuoteInfo {
// address of collateral token
address collToken;
// address of loan token
address loanToken;
// address of oracle (optional)
address oracleAddr;
// min loan amount (in loan token) prevent griefing attacks or
// amounts lender feels isn't worth unlocking on default
uint256 minLoan;
// max loan amount (in loan token) if lender wants a cap
uint256 maxLoan;
// timestamp after which quote automatically invalidates
uint256 validUntil;
// time, in seconds, that loan cannot be exercised
uint256 earliestRepayTenor;
// address of compartment implementation (optional)
address borrowerCompartmentImplementation;
// will invalidate quote after one use
// if false, will be a standing quote
bool isSingleUse;
// whitelist address (optional)
address whitelistAddr;
// flag indicating whether whitelistAddr refers to a single whitelisted
// borrower or to a whitelist authority that can whitelist multiple addresses
bool isWhitelistAddrSingleBorrower;
}
struct OnChainQuote {
// general quote info
GeneralQuoteInfo generalQuoteInfo;
// array of quote parameters
QuoteTuple[] quoteTuples;
// provides more distinguishability of quotes to reduce
// likelihood of collisions w.r.t. quote creations and invalidations
bytes32 salt;
}
struct OffChainQuote {
// general quote info
GeneralQuoteInfo generalQuoteInfo;
// root of the merkle tree, where the merkle tree encodes all QuoteTuples the lender accepts
bytes32 quoteTuplesRoot;
// provides more distinguishability of quotes to reduce
// likelihood of collisions w.r.t. quote creations and invalidations
bytes32 salt;
// for invalidating multiple parallel quotes in one click
uint256 nonce;
// array of compact signatures from vault signers
bytes[] compactSigs;
}
struct LoanRepayInstructions {
// loan id being repaid
uint256 targetLoanId;
// repay amount after transfer fees in loan token
uint128 targetRepayAmount;
// expected transfer fees in loan token (=0 for tokens without transfer fee)
// note: amount that borrower sends is targetRepayAmount + expectedTransferFee
uint128 expectedTransferFee;
// deadline to prevent stale transactions
uint256 deadline;
// e.g., for using collateral to payoff debt via DEX
address callbackAddr;
// any data needed by callback
bytes callbackData;
}
struct BorrowTransferInstructions {
// amount of collateral sent
uint256 collSendAmount;
// sum of (i) protocol fee and (ii) transfer fees (if any) associated with sending any collateral to vault
uint256 expectedProtocolAndVaultTransferFee;
// transfer fees associated with sending any collateral to compartment (if used)
uint256 expectedCompartmentTransferFee;
// deadline to prevent stale transactions
uint256 deadline;
// slippage protection if oracle price is too loose
uint256 minLoanAmount;
// e.g., for one-click leverage
address callbackAddr;
// any data needed by callback
bytes callbackData;
// any data needed by myso token manager
bytes mysoTokenManagerData;
}
struct TransferInstructions {
// collateral token receiver
address collReceiver;
// effective upfront fee in collateral tokens (vault or compartment)
uint256 upfrontFee;
}
struct WrappedERC721TokenInfo {
// address of the ERC721_TOKEN
address tokenAddr;
// array of ERC721_TOKEN ids
uint256[] tokenIds;
}
struct WrappedERC20TokenInfo {
// token addresse
address tokenAddr;
// token amounts
uint256 tokenAmount;
}
struct OnChainQuoteInfo {
// hash of on chain quote
bytes32 quoteHash;
// valid until timestamp
uint256 validUntil;
}
enum WhitelistState {
// not whitelisted
NOT_WHITELISTED,
// can be used as loan or collateral token
ERC20_TOKEN,
// can be be used as oracle
ORACLE,
// can be used as compartment
COMPARTMENT,
// can be used as callback contract
CALLBACK,
// can be used as loan or collateral token, but if collateral then must
// be used in conjunction with a compartment (e.g., for stETH with possible
// negative rebase that could otherwise affect other borrowers in the vault)
ERC20_TOKEN_REQUIRING_COMPARTMENT,
// can be used in conjunction with an ERC721 wrapper
ERC721_TOKEN,
// can be used as ERC721 wrapper contract
ERC721WRAPPER,
// can be used as ERC20 wrapper contract
ERC20WRAPPER,
// can be used as MYSO token manager contract
MYSO_TOKEN_MANAGER,
// can be used as quote policy manager contract
QUOTE_POLICY_MANAGER
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
library DataTypesPeerToPool {
struct Repayment {
// The loan token amount due for given period; initially, expressed in relative terms (100%=BASE), once
// finalized in absolute terms (in loanToken)
uint128 loanTokenDue;
// The coll token amount that can be converted for given period; initially, expressed in relative terms w.r.t.
// loanTokenDue (e.g., convert every 1 loanToken for 8 collToken), once finalized in absolute terms (in collToken)
uint128 collTokenDueIfConverted;
// Timestamp when repayment is due
uint40 dueTimestamp;
}
struct LoanTerms {
// Min subscription amount (in loan token) that the borrower deems acceptable
uint128 minTotalSubscriptions;
// Max subscription amount (in loan token) that the borrower deems acceptable
uint128 maxTotalSubscriptions;
// The number of collateral tokens the borrower pledges per loan token borrowed as collateral for default case
uint128 collPerLoanToken;
// Borrower who can finalize given loan proposal
address borrower;
// Array of scheduled repayments
Repayment[] repaymentSchedule;
}
struct StaticLoanProposalData {
// Factory address from which the loan proposal is created
address factory;
// Funding pool address that is associated with given loan proposal and from which loan liquidity can be
// sourced
address fundingPool;
// Address of collateral token to be used for given loan proposal
address collToken;
// Address of arranger who can manage the loan proposal contract
address arranger;
// Address of whitelist authority who can manage the lender whitelist (optional)
address whitelistAuthority;
// Unsubscribe grace period (in seconds), i.e., after acceptance by borrower lenders can unsubscribe and
// remove liquidity for this duration before being locked-in
uint256 unsubscribeGracePeriod;
// Conversion grace period (in seconds), i.e., lenders can exercise their conversion right between
// [dueTimeStamp, dueTimeStamp+conversionGracePeriod]
uint256 conversionGracePeriod;
// Repayment grace period (in seconds), i.e., borrowers can repay between
// [dueTimeStamp+conversionGracePeriod, dueTimeStamp+conversionGracePeriod+repaymentGracePeriod]
uint256 repaymentGracePeriod;
}
struct DynamicLoanProposalData {
// Arranger fee charged on final loan amount, initially in relative terms (100%=BASE), and after finalization
// in absolute terms (in loan token)
uint256 arrangerFee;
// The gross loan amount; initially this is zero and gets set once loan proposal gets accepted and finalized;
// note that the borrower receives the gross loan amount minus any arranger and protocol fees
uint256 grossLoanAmount;
// Final collateral amount reserved for defaults; initially this is zero and gets set once loan proposal got
// accepted and finalized
uint256 finalCollAmountReservedForDefault;
// Final collateral amount reserved for conversions; initially this is zero and gets set once loan proposal got
// accepted and finalized
uint256 finalCollAmountReservedForConversions;
// Timestamp when the loan terms get accepted by borrower and after which they cannot be changed anymore
uint256 loanTermsLockedTime;
// Current repayment index, mapping to currently relevant repayment schedule element; note the
// currentRepaymentIdx (initially 0) only ever gets incremented on repay
uint256 currentRepaymentIdx;
// Status of current loan proposal
DataTypesPeerToPool.LoanStatus status;
// Protocol fee, initially in relative terms (100%=BASE), and after finalization in absolute terms (in loan token);
// note that the relative protocol fee is locked in at the time when the loan proposal is created
uint256 protocolFee;
}
enum LoanStatus {
WITHOUT_LOAN_TERMS,
IN_NEGOTIATION,
LOAN_TERMS_LOCKED,
READY_TO_EXECUTE,
ROLLBACK,
LOAN_DEPLOYED,
DEFAULTED
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
library Errors {
error UnregisteredVault();
error InvalidDelegatee();
error InvalidSender();
error InvalidFee();
error InsufficientSendAmount();
error NoOracle();
error InvalidOracleAnswer();
error InvalidOracleDecimals();
error InvalidOracleVersion();
error InvalidAddress();
error InvalidArrayLength();
error InvalidQuote();
error OutdatedQuote();
error InvalidOffChainSignature();
error InvalidOffChainMerkleProof();
error InvalidCollUnlock();
error InvalidAmount();
error UnknownOnChainQuote();
error NeitherTokenIsGOHM();
error NoLpTokens();
error ZeroReserve();
error IncorrectGaugeForLpToken();
error InvalidGaugeIndex();
error AlreadyStaked();
error InvalidWithdrawAmount();
error InvalidBorrower();
error OutsideValidRepayWindow();
error InvalidRepayAmount();
error ReclaimAmountIsZero();
error UnregisteredGateway();
error NonWhitelistedOracle();
error NonWhitelistedCompartment();
error NonWhitelistedCallback();
error NonWhitelistedToken();
error LtvHigherThanMax();
error InsufficientVaultFunds();
error InvalidInterestRateFactor();
error InconsistentUnlockTokenAddresses();
error InvalidEarliestRepay();
error InvalidNewMinNumOfSigners();
error AlreadySigner();
error InvalidArrayIndex();
error InvalidSignerRemoveInfo();
error InvalidSendAmount();
error TooSmallLoanAmount();
error DeadlinePassed();
error WithdrawEntered();
error DuplicateAddresses();
error OnChainQuoteAlreadyAdded();
error OffChainQuoteHasBeenInvalidated();
error Uninitialized();
error InvalidRepaymentScheduleLength();
error FirstDueDateTooCloseOrPassed();
error InvalidGracePeriod();
error UnregisteredLoanProposal();
error NotInSubscriptionPhase();
error NotInUnsubscriptionPhase();
error InsufficientBalance();
error InsufficientFreeSubscriptionSpace();
error BeforeEarliestUnsubscribe();
error InconsistentLastLoanTermsUpdateTime();
error InvalidActionForCurrentStatus();
error FellShortOfTotalSubscriptionTarget();
error InvalidRollBackRequest();
error UnsubscriptionAmountTooLarge();
error InvalidSubscriptionRange();
error InvalidMaxTotalSubscriptions();
error OutsideConversionTimeWindow();
error OutsideRepaymentTimeWindow();
error NoDefault();
error LoanIsFullyRepaid();
error RepaymentIdxTooLarge();
error AlreadyClaimed();
error AlreadyConverted();
error InvalidDueDates();
error LoanTokenDueIsZero();
error WaitForLoanTermsCoolOffPeriod();
error ZeroConversionAmount();
error InvalidNewOwnerProposal();
error CollateralMustBeCompartmentalized();
error InvalidCompartmentForToken();
error InvalidSignature();
error InvalidUpdate();
error CannotClaimOutdatedStatus();
error DelegateReducedBalance();
error FundingPoolAlreadyExists();
error InvalidLender();
error NonIncreasingTokenAddrs();
error NonIncreasingNonFungibleTokenIds();
error TransferToWrappedTokenFailed();
error TransferFromWrappedTokenFailed();
error StateAlreadySet();
error ReclaimableCollateralAmountZero();
error InvalidSwap();
error InvalidUpfrontFee();
error InvalidOracleTolerance();
error ReserveRatiosSkewedFromOraclePrice();
error SequencerDown();
error GracePeriodNotOver();
error LoanExpired();
error NoDsEth();
error TooShortTwapInterval();
error TooLongTwapInterval();
error TwapExceedsThreshold();
error Reentrancy();
error TokenNotStuck();
error InconsistentExpTransferFee();
error InconsistentExpVaultBalIncrease();
error DepositLockActive();
error DisallowedSubscriptionLockup();
error IncorrectLoanAmount();
error Disabled();
error CannotRemintUnlessZeroSupply();
error TokensStillMissingFromWrapper();
error OnlyMintFromSingleTokenWrapper();
error NonMintableTokenState();
error NoTokensTransferred();
error TokenAlreadyCountedInWrapper();
error TokenNotOwnedByWrapper();
error TokenDoesNotBelongInWrapper(address tokenAddr, uint256 tokenId);
error InvalidMintAmount();
error QuoteViolatesPolicy();
error AlreadyPublished();
error PolicyAlreadySet();
error NoPolicyToDelete();
error InvalidTenorBounds();
error InvalidLtvBounds();
error InvalidLoanPerCollBounds();
error InvalidMinApr();
error NoPolicy();
error InvalidMinFee();
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {DataTypesPeerToPeer} from "../DataTypesPeerToPeer.sol";
interface IAddressRegistry {
event WhitelistStateUpdated(
address[] indexed whitelistAddrs,
DataTypesPeerToPeer.WhitelistState indexed whitelistState
);
event AllowedTokensForCompartmentUpdated(
address indexed compartmentImpl,
address[] tokens,
bool isWhitelisted
);
event BorrowerWhitelistStatusClaimed(
address indexed whitelistAuthority,
address indexed borrower,
uint256 whitelistedUntil
);
event BorrowerWhitelistUpdated(
address indexed whitelistAuthority,
address[] borrowers,
uint256 whitelistedUntil
);
event CreatedWrappedTokenForERC721s(
DataTypesPeerToPeer.WrappedERC721TokenInfo[] wrappedTokensInfo,
string name,
string symbol,
address newErc20Addr
);
event CreatedWrappedTokenForERC20s(
DataTypesPeerToPeer.WrappedERC20TokenInfo[] wrappedTokensInfo,
string name,
string symbol,
address newERC20Addr
);
/**
* @notice initializes factory, gateway, and quote handler contracts
* @param _lenderVaultFactory address of the factory for lender vaults
* @param _borrowerGateway address of the gateway with which borrowers interact
* @param _quoteHandler address of contract which handles quote logic
*/
function initialize(
address _lenderVaultFactory,
address _borrowerGateway,
address _quoteHandler
) external;
/**
* @notice adds new lender vault to registry
* @dev can only be called lender vault factory
* @param addr address of new lender vault
* @return numRegisteredVaults number of registered vaults
*/
function addLenderVault(
address addr
) external returns (uint256 numRegisteredVaults);
/**
* @notice Allows user to claim whitelisted status
* @param whitelistAuthority Address of whitelist authorithy
* @param whitelistedUntil Timestamp until when user is whitelisted
* @param compactSig Compact signature from whitelist authority
* @param salt Salt to make signature unique
*/
function claimBorrowerWhitelistStatus(
address whitelistAuthority,
uint256 whitelistedUntil,
bytes calldata compactSig,
bytes32 salt
) external;
/**
* @notice Allows user to wrap (multiple) ERC721 into one ERC20
* @param tokensToBeWrapped Array of WrappedERC721TokenInfo
* @param name Name of the new wrapper token
* @param symbol Symbol of the new wrapper token
* @param mysoTokenManagerData Data to be passed to MysoTokenManager
*/
function createWrappedTokenForERC721s(
DataTypesPeerToPeer.WrappedERC721TokenInfo[] calldata tokensToBeWrapped,
string calldata name,
string calldata symbol,
bytes calldata mysoTokenManagerData
) external;
/**
* @notice Allows user to wrap multiple ERC20 into one ERC20
* @param tokensToBeWrapped Array of WrappedERC20TokenInfo
* @param name Name of the new wrapper token
* @param symbol Symbol of the new wrapper token
* @param mysoTokenManagerData Data to be passed to MysoTokenManager
*/
function createWrappedTokenForERC20s(
DataTypesPeerToPeer.WrappedERC20TokenInfo[] calldata tokensToBeWrapped,
string calldata name,
string calldata symbol,
bytes calldata mysoTokenManagerData
) external;
/**
* @notice Allows a whitelist authority to set the whitelistedUntil state for a given borrower
* @dev Anyone can create their own whitelist, and lenders can decide if and which whitelist they want to use
* @param borrowers Array of borrower addresses
* @param whitelistedUntil Timestamp until which borrowers shall be whitelisted under given whitelist authority
*/
function updateBorrowerWhitelist(
address[] calldata borrowers,
uint256 whitelistedUntil
) external;
/**
* @notice Sets the whitelist state for a given address
* @dev Can only be called by registry owner
* @param addrs Addresses for which whitelist state shall be set
* @param whitelistState The whitelist state to which addresses shall be set
*/
function setWhitelistState(
address[] calldata addrs,
DataTypesPeerToPeer.WhitelistState whitelistState
) external;
/**
* @notice Sets the allowed tokens for a given compartment implementation
* @dev Can only be called by registry owner
* @param compartmentImpl Compartment implementations for which allowed tokens shall be set
* @param tokens List of tokens that shall be allowed for given compartment implementation
* @param allowTokensForCompartment Boolean flag indicating whether tokens shall be allowed for compartment
implementation
*/
function setAllowedTokensForCompartment(
address compartmentImpl,
address[] calldata tokens,
bool allowTokensForCompartment
) external;
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
* @param newOwner the proposed new owner address
*/
function transferOwnership(address newOwner) external;
/**
* @notice Returns boolean flag indicating whether the borrower has been whitelisted by whitelistAuthority
* @param whitelistAuthority Addresses of the whitelist authority
* @param borrower Addresses of the borrower
* @return Boolean flag indicating whether the borrower has been whitelisted by whitelistAuthority
*/
function isWhitelistedBorrower(
address whitelistAuthority,
address borrower
) external view returns (bool);
/**
* @notice Returns boolean flag indicating whether token is whitelisted
* @param token Addresses of the given token to check
* @return Boolean flag indicating whether the token is whitelisted
*/
function isWhitelistedERC20(address token) external view returns (bool);
/**
* @notice Returns the address of the vault factory
* @return Address of the vault factory contract
*/
function lenderVaultFactory() external view returns (address);
/**
* @notice Returns the address of the borrower gateway
* @return Address of the borrower gateway contract
*/
function borrowerGateway() external view returns (address);
/**
* @notice Returns the address of the quote handler
* @return Address of the quote handler contract
*/
function quoteHandler() external view returns (address);
/**
* @notice Returns the address of the MYSO token manager
* @return Address of the MYSO token manager contract
*/
function mysoTokenManager() external view returns (address);
/**
* @notice Returns boolean flag indicating whether given address is a registered vault
* @param addr Address to check if it is a registered vault
* @return Boolean flag indicating whether given address is a registered vault
*/
function isRegisteredVault(address addr) external view returns (bool);
/**
* @notice Returns whitelist state for given address
* @param addr Address to check whitelist state for
* @return whitelistState Whitelist state for given address
*/
function whitelistState(
address addr
) external view returns (DataTypesPeerToPeer.WhitelistState whitelistState);
/**
* @notice Returns an array of registered vault addresses
* @return vaultAddrs The array of registered vault addresses
*/
function registeredVaults()
external
view
returns (address[] memory vaultAddrs);
/**
* @notice Returns address of the owner
* @return Address of the owner
*/
function owner() external view returns (address);
/**
* @notice Returns address of the pending owner
* @return Address of the pending owner
*/
function pendingOwner() external view returns (address);
/**
* @notice Returns boolean flag indicating whether given compartment implementation and token combination is whitelisted
* @param compartmentImpl Address of compartment implementation to check if it is allowed for token
* @param token Address of token to check if compartment implementation is allowed
* @return isWhitelisted Boolean flag indicating whether compartment implementation is whitelisted for given token
*/
function isWhitelistedCompartment(
address compartmentImpl,
address token
) external view returns (bool isWhitelisted);
/**
* @notice Returns current number of vaults registered
* @return numVaults Current number of vaults registered
*/
function numRegisteredVaults() external view returns (uint256 numVaults);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IBaseCompartment {
event Staked(uint256 gaugeIndex, address liqGaugeAddr, uint256 amount);
event Delegated(address delegator, address delegatee);
event UpdatedApprovedStaker(address staker, bool approvalState);
event UpdatedApprovedDelegator(address delegator, bool approvalState);
/**
* @notice function to initialize collateral compartment
* @dev factory creates clone and then initializes implementation contract
* @param vaultAddr address of vault
* @param loanId index of the loan
*/
function initialize(address vaultAddr, uint256 loanId) external;
/**
* @notice function to transfer some amount of collateral to borrower on repay
* @dev this function can only be called by vault and tranfers proportional amount
* of compartment collTokenBalance to borrower address. This needs use a proportion
* and not the amount to account for possible changes due to rewards accruing
* @param repayAmount amount of loan token to be repaid
* @param repayAmountLeft amount of loan token still outstanding
* @param reclaimCollAmount amount of collateral token to be reclaimed
* @param borrowerAddr address of borrower receiving transfer
* @param collTokenAddr address of collateral token being transferred
* @param callbackAddr address to send collateral to instead of borrower if using callback
*/
function transferCollFromCompartment(
uint256 repayAmount,
uint256 repayAmountLeft,
uint128 reclaimCollAmount,
address borrowerAddr,
address collTokenAddr,
address callbackAddr
) external;
/**
* @notice function to unlock all collateral left in compartment
* @dev this function can only be called by vault and returns all collateral to vault
* @param collTokenAddr pass in collToken addr to avoid callback reads gas cost
*/
function unlockCollToVault(address collTokenAddr) external;
/**
* @notice function returns the potentially reclaimable collateral token balance
* @param collTokenAddr address of collateral token for which reclaimable balance is being retrieved
* @dev depending on compartment implementation this could be simple balanceOf or eg staked balance call
*/
function getReclaimableBalance(
address collTokenAddr
) external view returns (uint256 reclaimableBalance);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {DataTypesPeerToPeer} from "../DataTypesPeerToPeer.sol";
interface IBorrowerGateway {
event Borrowed(
address indexed vaultAddr,
address indexed borrower,
DataTypesPeerToPeer.Loan loan,
uint256 upfrontFee,
uint256 indexed loanId,
address callbackAddr,
bytes callbackData
);
event Repaid(
address indexed vaultAddr,
uint256 indexed loanId,
uint256 repayAmount
);
event ProtocolFeeSet(uint128[2] newFeeParams);
/**
* @notice function which allows a borrower to use an offChain quote to borrow
* @param lenderVault address of the vault whose owner(s) signed the offChain quote
* @param borrowInstructions data needed for borrow (see DataTypesPeerToPeer comments)
* @param offChainQuote quote data (see DataTypesPeerToPeer comments)
* @param quoteTuple quote data (see DataTypesPeerToPeer comments)
* @param proof array of bytes needed for merkle tree verification of quote
* @return loan data
*/
function borrowWithOffChainQuote(
address lenderVault,
DataTypesPeerToPeer.BorrowTransferInstructions
calldata borrowInstructions,
DataTypesPeerToPeer.OffChainQuote calldata offChainQuote,
DataTypesPeerToPeer.QuoteTuple calldata quoteTuple,
bytes32[] memory proof
) external returns (DataTypesPeerToPeer.Loan memory);
/**
* @notice function which allows a borrower to use an onChain quote to borrow
* @param lenderVault address of the vault whose owner(s) enacted onChain quote
* @param borrowInstructions data needed for borrow (see DataTypesPeerToPeer comments)
* @param onChainQuote quote data (see DataTypesPeerToPeer comments)
* @param quoteTupleIdx index of quote tuple array
* @return loan data
*/
function borrowWithOnChainQuote(
address lenderVault,
DataTypesPeerToPeer.BorrowTransferInstructions
calldata borrowInstructions,
DataTypesPeerToPeer.OnChainQuote calldata onChainQuote,
uint256 quoteTupleIdx
) external returns (DataTypesPeerToPeer.Loan memory);
/**
* @notice function which allows a borrower to repay a loan
* @param loanRepayInstructions data needed for loan repay (see DataTypesPeerToPeer comments)
* @param vaultAddr address of the vault in which loan was taken out
*/
function repay(
DataTypesPeerToPeer.LoanRepayInstructions
calldata loanRepayInstructions,
address vaultAddr
) external;
/**
* @notice function which allows owner to set new protocol fee params
* @dev protocolFee params are in units of BASE constant (10**18) and variable portion is annualized
* @param _newFeeParams new base fee (constant) and fee slope (variable) in BASE
*/
function setProtocolFeeParams(uint128[2] calldata _newFeeParams) external;
/**
* @notice function returns address registry
* @return address of registry
*/
function addressRegistry() external view returns (address);
/**
* @notice function returns protocol fee
* @return protocolFeeParams protocol fee Params in Base
*/
function getProtocolFeeParams()
external
view
returns (uint128[2] memory protocolFeeParams);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` 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 amount) external returns (bool);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
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);
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {DataTypesPeerToPeer} from "../DataTypesPeerToPeer.sol";
interface ILenderVaultImpl {
event AddedSigners(address[] _signers);
event MinNumberOfSignersSet(uint256 minNumSigners);
event RemovedSigner(
address signerRemoved,
uint256 signerIdx,
address signerMovedFromEnd
);
event CollateralUnlocked(
address indexed vaultOwner,
address indexed collToken,
uint256[] loanIds,
uint256 amountUnlocked
);
event QuoteProcessed(
uint256 netPledgeAmount,
DataTypesPeerToPeer.TransferInstructions transferInstructions
);
event Withdrew(address indexed tokenAddr, uint256 withdrawAmount);
event CircuitBreakerUpdated(
address indexed newCircuitBreaker,
address indexed oldCircuitBreaker
);
event ReverseCircuitBreakerUpdated(
address indexed newReverseCircuitBreaker,
address indexed oldReverseCircuitBreaker
);
event OnChainQuotingDelegateUpdated(
address indexed newOnChainQuotingDelegate,
address indexed oldOnChainQuotingDelegate
);
/**
* @notice function to initialize lender vault
* @dev factory creates clone and then initializes the vault
* @param vaultOwner address of vault owner
* @param addressRegistry registry address
*/
function initialize(address vaultOwner, address addressRegistry) external;
/**
* @notice function to unlock defaulted collateral
* @dev only loans with same collateral token can be unlocked in one call
* function will revert if mismatch in coll token to a loan.collToken.
* @param collToken address of the collateral token
* @param _loanIds array of indices of the loans to unlock
*/
function unlockCollateral(
address collToken,
uint256[] calldata _loanIds
) external;
/**
* @notice function to update loan info on a reoay
* @dev only borrower gateway can call this function
* loanId is needed by vault to store updated loan info
* @param repayAmount amount of loan repaid
* @param loanId index of loan in loans array
* @param collAmount amount of collateral to unlock
* @param noCompartment boolean flag indicating whether loan has no compartment
* @param collToken address of the collateral token
*/
function updateLoanInfo(
uint128 repayAmount,
uint256 loanId,
uint128 collAmount,
bool noCompartment,
address collToken
) external;
/**
* @notice function to processQuote on a borrow
* @dev only borrower gateway can call this function
* @param borrower address of the borrower
* @param borrowInstructions struct containing all info for borrow (see DataTypesPeerToPeer.sol notes)
* @param generalQuoteInfo struct containing quote info (see Datatypes.sol notes)
* @param quoteTuple struct containing specific quote tuple info (see DataTypesPeerToPeer.sol notes)
* @return loan loan information after processing the quote
* @return loanId index of loans in the loans array
* @return transferInstructions struct containing transfer instruction info (see DataTypesPeerToPeer.sol notes)
*/
function processQuote(
address borrower,
DataTypesPeerToPeer.BorrowTransferInstructions
calldata borrowInstructions,
DataTypesPeerToPeer.GeneralQuoteInfo calldata generalQuoteInfo,
DataTypesPeerToPeer.QuoteTuple calldata quoteTuple
)
external
returns (
DataTypesPeerToPeer.Loan calldata loan,
uint256 loanId,
DataTypesPeerToPeer.TransferInstructions memory transferInstructions
);
/**
* @notice function to withdraw a token from a vault
* @dev only vault owner can withdraw
* @param token address of the token to withdraw
* @param amount amount of token to withdraw
*/
function withdraw(address token, uint256 amount) external;
/**
* @notice function to transfer token from vault
* @dev only borrow gateway can call this function
* @param token address of the token to transfer
* @param recipient address which receives the tokens
* @param amount amount of token to transfer
*/
function transferTo(
address token,
address recipient,
uint256 amount
) external;
/**
* @notice function to transfer token from a compartment
* @dev only borrow gateway can call this function, if callbackAddr, then
* the collateral will be transferred to the callback address
* @param repayAmount amount of loan token to be repaid
* @param repayAmountLeft amount of loan token still outstanding
* @param reclaimCollAmount amount of collateral to be reclaimed
* @param borrowerAddr address of the borrower
* @param collTokenAddr address of the coll token to transfer to compartment
* @param callbackAddr address of callback
* @param collTokenCompartmentAddr address of the coll token compartment
*/
function transferCollFromCompartment(
uint256 repayAmount,
uint256 repayAmountLeft,
uint128 reclaimCollAmount,
address borrowerAddr,
address collTokenAddr,
address callbackAddr,
address collTokenCompartmentAddr
) external;
/**
* @notice function to set minimum number of signers required for an offchain quote
* @dev this function allows a multi-sig quorum to sign a quote offchain
* @param _minNumOfSigners minimum number of signatures borrower needs to provide
*/
function setMinNumOfSigners(uint256 _minNumOfSigners) external;
/**
* @notice function to add a signer
* @dev this function only can be called by vault owner
* @param _signers array of signers to add
*/
function addSigners(address[] calldata _signers) external;
/**
* @notice function to remove a signer
* @dev this function only can be called by vault owner
* @param signer address of signer to be removed
* @param signerIdx index of the signers array at which signer resides
*/
function removeSigner(address signer, uint256 signerIdx) external;
/**
* @notice function to set a circuit breaker
* @dev the circuit breaker (and vault owner) can pause all loan offers;
* note: circuit breaker and reverse circuit breaker can be the same account
* @param circuitBreaker address of the circuit breaker
*/
function setCircuitBreaker(address circuitBreaker) external;
/**
* @notice function to set a reverse circuit breaker
* @dev the reverse circuit breaker (and vault owner) can unpause all loan offers;
* note: circuit breaker and reverse circuit breaker can be the same account
* @param reverseCircuitBreaker address of the reverse circuit breaker
*/
function setReverseCircuitBreaker(address reverseCircuitBreaker) external;
/**
* @notice function to set a delegate for on chain quoting
* @dev the quote handler (and vault owner) can add, delete and update on chain quotes
* @param onChainQuotingDelegate address of the delegate
*/
function setOnChainQuotingDelegate(address onChainQuotingDelegate) external;
/**
* @notice function to pause all quotes from lendervault
* @dev only vault owner and circuit breaker can pause quotes
*/
function pauseQuotes() external;
/**
* @notice function to unpause all quotes from lendervault
* @dev only vault owner and reverse circuit breaker can unpause quotes again
*/
function unpauseQuotes() external;
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
* @param newOwner the proposed new owner address
*/
function transferOwnership(address newOwner) external;
/**
* @notice function to retrieve loan from loans array in vault
* @dev this function reverts on invalid index
* @param index index of loan
* @return loan loan stored at that index in vault
*/
function loan(
uint256 index
) external view returns (DataTypesPeerToPeer.Loan memory loan);
/**
* @notice function to return owner address
* @return owner address
*/
function owner() external view returns (address);
/**
* @notice Returns address of the pending owner
* @return Address of the pending owner
*/
function pendingOwner() external view returns (address);
/**
* @notice function to return the total number of signers
* @return number of signers
*/
function totalNumSigners() external view returns (uint256);
/**
* @notice function to return unlocked token balances
* @param tokens array of token addresses
* @return balances the vault balances of the token addresses
* @return _lockedAmounts the vault locked amounts of the token addresses
*/
function getTokenBalancesAndLockedAmounts(
address[] calldata tokens
)
external
view
returns (uint256[] memory balances, uint256[] memory _lockedAmounts);
/**
* @notice function to return address of registry
* @return registry address
*/
function addressRegistry() external view returns (address);
/**
* @notice function to return address of the circuit breaker
* @return circuit breaker address
*/
function circuitBreaker() external view returns (address);
/**
* @notice function to return address of the reverse circuit breaker
* @return reverse circuit breaker address
*/
function reverseCircuitBreaker() external view returns (address);
/**
* @notice function to return address of the delegate for on chain quoting
* @return approved delegate address
*/
function onChainQuotingDelegate() external view returns (address);
/**
* @notice function returns signer at given index
* @param index of the signers array
* @return signer address
*/
function signers(uint256 index) external view returns (address);
/**
* @notice function returns minimum number of signers
* @return minimum number of signers
*/
function minNumOfSigners() external view returns (uint256);
/**
* @notice function returns if address is a signer
* @return true, if a signer, else false
*/
function isSigner(address signer) external view returns (bool);
/**
* @notice function returns if withdraw mutex is activated
* @return true, if withdraw already called, else false
*/
function withdrawEntered() external view returns (bool);
/**
* @notice function returns current locked amounts of given token
* @param token address of the token
* @return amount of token locked
*/
function lockedAmounts(address token) external view returns (uint256);
/**
* @notice function returns total number of loans
* @return total number of loans
*/
function totalNumLoans() external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {DataTypesPeerToPeer} from "../peer-to-peer/DataTypesPeerToPeer.sol";
import {DataTypesPeerToPool} from "../peer-to-pool/DataTypesPeerToPool.sol";
interface IMysoTokenManager {
function processP2PBorrow(
uint128[2] memory currProtocolFeeParams,
DataTypesPeerToPeer.BorrowTransferInstructions
calldata borrowInstructions,
DataTypesPeerToPeer.Loan calldata loan,
address lenderVault
) external returns (uint128[2] memory applicableProtocolFeeParams);
function processP2PCreateVault(
uint256 numRegisteredVaults,
address vaultCreator,
address newLenderVaultAddr
) external;
function processP2PCreateWrappedTokenForERC721s(
address tokenCreator,
DataTypesPeerToPeer.WrappedERC721TokenInfo[] calldata tokensToBeWrapped,
bytes calldata mysoTokenManagerData
) external;
function processP2PCreateWrappedTokenForERC20s(
address tokenCreator,
DataTypesPeerToPeer.WrappedERC20TokenInfo[] calldata tokensToBeWrapped,
bytes calldata mysoTokenManagerData
) external;
function processP2PoolDeposit(
address fundingPool,
address depositor,
uint256 depositAmount,
uint256 depositLockupDuration,
uint256 transferFee
) external;
function processP2PoolSubscribe(
address fundingPool,
address subscriber,
address loanProposal,
uint256 subscriptionAmount,
uint256 subscriptionLockupDuration,
uint256 totalSubscriptions,
DataTypesPeerToPool.LoanTerms calldata loanTerms
) external;
function processP2PoolLoanFinalization(
address loanProposal,
address fundingPool,
address arranger,
address borrower,
uint256 grossLoanAmount,
bytes calldata mysoTokenManagerData
) external;
function processP2PoolCreateLoanProposal(
address fundingPool,
address proposalCreator,
address collToken,
uint256 arrangerFee,
uint256 numLoanProposals
) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {DataTypesPeerToPeer} from "../DataTypesPeerToPeer.sol";
interface IQuoteHandler {
event OnChainQuoteAdded(
address indexed lenderVault,
DataTypesPeerToPeer.OnChainQuote onChainQuote,
bytes32 indexed onChainQuoteHash
);
event OnChainQuoteDeleted(
address indexed lenderVault,
bytes32 indexed onChainQuoteHash
);
event OnChainQuoteInvalidated(
address indexed lenderVault,
bytes32 indexed onChainQuoteHash
);
event OffChainQuoteNonceIncremented(
address indexed lenderVault,
uint256 newNonce
);
event OffChainQuoteInvalidated(
address indexed lenderVault,
bytes32 indexed offChainQuoteHash
);
event OnChainQuoteUsed(
address indexed lenderVault,
bytes32 indexed onChainQuoteHash,
uint256 indexed toBeRegisteredLoanId,
uint256 quoteTupleIdx
);
event OffChainQuoteUsed(
address indexed lenderVault,
bytes32 indexed offChainQuoteHash,
uint256 indexed toBeRegisteredLoanId,
DataTypesPeerToPeer.QuoteTuple quoteTuple
);
event QuotePolicyManagerUpdated(
address indexed lenderVault,
address indexed newPolicyManagerAddress
);
event OnChainQuotePublished(
DataTypesPeerToPeer.OnChainQuote onChainQuote,
bytes32 indexed onChainQuoteHash,
address indexed proposer
);
event OnChainQuoteCopied(
address indexed lenderVault,
bytes32 indexed onChainQuoteHash
);
/**
* @notice function adds on chain quote
* @dev function can only be called by vault owner or on chain quote delegate
* @param lenderVault address of the vault adding quote
* @param onChainQuote data for the onChain quote (See notes in DataTypesPeerToPeer.sol)
*/
function addOnChainQuote(
address lenderVault,
DataTypesPeerToPeer.OnChainQuote calldata onChainQuote
) external;
/**
* @notice function updates on chain quote
* @dev function can only be called by vault owner or on chain quote delegate
* @param lenderVault address of the vault updating quote
* @param oldOnChainQuoteHash quote hash for the old onChain quote marked for deletion
* @param newOnChainQuote data for the new onChain quote (See notes in DataTypesPeerToPeer.sol)
*/
function updateOnChainQuote(
address lenderVault,
bytes32 oldOnChainQuoteHash,
DataTypesPeerToPeer.OnChainQuote calldata newOnChainQuote
) external;
/**
* @notice function deletes on chain quote
* @dev function can only be called by vault owner or on chain quote delegate
* @param lenderVault address of the vault deleting
* @param onChainQuoteHash quote hash for the onChain quote marked for deletion
*/
function deleteOnChainQuote(
address lenderVault,
bytes32 onChainQuoteHash
) external;
/**
* @notice function to copy a published on chain quote
* @dev function can only be called by vault owner or on chain quote delegate
* @param lenderVault address of the vault approving
* @param onChainQuoteHash quote hash of a published onChain quote
*/
function copyPublishedOnChainQuote(
address lenderVault,
bytes32 onChainQuoteHash
) external;
/**
* @notice function to publish an on chain quote
* @dev function can be called by anyone and used by any vault
* @param onChainQuote data for the onChain quote (See notes in DataTypesPeerToPeer.sol)
*/
function publishOnChainQuote(
DataTypesPeerToPeer.OnChainQuote calldata onChainQuote
) external;
/**
* @notice function increments the nonce for a vault
* @dev function can only be called by vault owner
* incrementing the nonce can bulk invalidate any
* off chain quotes with that nonce in one txn
* @param lenderVault address of the vault
*/
function incrementOffChainQuoteNonce(address lenderVault) external;
/**
* @notice function invalidates off chain quote
* @dev function can only be called by vault owner
* this function invalidates one specific quote
* @param lenderVault address of the vault
* @param offChainQuoteHash hash of the off chain quote to be invalidated
*/
function invalidateOffChainQuote(
address lenderVault,
bytes32 offChainQuoteHash
) external;
/**
* @notice function performs checks on quote and, if valid, updates quotehandler's state
* @dev function can only be called by borrowerGateway
* @param borrower address of borrower
* @param lenderVault address of the vault
* @param quoteTupleIdx index of the quote tuple in the vault's quote array
* @param onChainQuote data for the onChain quote (See notes in DataTypesPeerToPeer.sol)
*/
function checkAndRegisterOnChainQuote(
address borrower,
address lenderVault,
uint256 quoteTupleIdx,
DataTypesPeerToPeer.OnChainQuote memory onChainQuote
) external;
/**
* @notice function performs checks on quote and, if valid, updates quotehandler's state
* @dev function can only be called by borrowerGateway
* @param borrower address of borrower
* @param lenderVault address of the vault
* @param offChainQuote data for the offChain quote (See notes in DataTypesPeerToPeer.sol)
* @param quoteTuple quote data (see notes in DataTypesPeerToPeer.sol)
* @param proof array of bytes needed to verify merkle proof
*/
function checkAndRegisterOffChainQuote(
address borrower,
address lenderVault,
DataTypesPeerToPeer.OffChainQuote calldata offChainQuote,
DataTypesPeerToPeer.QuoteTuple calldata quoteTuple,
bytes32[] memory proof
) external;
/**
* @notice function to update the quote policy manager for a vault
* @param lenderVault address for which quote policy manager is being updated
* @param newPolicyManagerAddress address of new quote policy manager
* @dev function can only be called by vault owner
*/
function updateQuotePolicyManagerForVault(
address lenderVault,
address newPolicyManagerAddress
) external;
/**
* @notice function to return address of registry
* @return registry address
*/
function addressRegistry() external view returns (address);
/**
* @notice function to return the current nonce for offchain quotes
* @param lender address for which nonce is being retrieved
* @return current value of nonce
*/
function offChainQuoteNonce(address lender) external view returns (uint256);
/**
* @notice function returns if offchain quote hash is invalidated
* @param lenderVault address of vault
* @param hashToCheck hash of the offchain quote
* @return true if invalidated, else false
*/
function offChainQuoteIsInvalidated(
address lenderVault,
bytes32 hashToCheck
) external view returns (bool);
/**
* @notice function returns if hash is for an on chain quote
* @param lenderVault address of vault
* @param hashToCheck hash of the on chain quote
* @return true if hash belongs to a valid on-chain quote, else false
*/
function isOnChainQuote(
address lenderVault,
bytes32 hashToCheck
) external view returns (bool);
/**
* @notice function returns if hash belongs to a published on chain quote
* @param hashToCheck hash of the on chain quote
* @return true if hash belongs to a published on-chain quote, else false
*/
function isPublishedOnChainQuote(
bytes32 hashToCheck
) external view returns (bool);
/**
* @notice function returns valid until timestamp of the published on-chain quote
* @param hashToCheck hash of the on chain quote
* @return valid until timestamp of the published on-chain quote
*/
function publishedOnChainQuoteValidUntil(
bytes32 hashToCheck
) external view returns (uint256);
/**
* @notice function returns the address of the policy manager for a vault
* @param lenderVault address of vault
* @return address of quote policy manager for vault
* @dev if policy manager address changes in registry, this function will still return the old address
* unless and until the vault owner calls updateQuotePolicyManagerForVault
*/
function quotePolicyManagerForVault(
address lenderVault
) external view returns (address);
/**
* @notice function returns element of on-chain history
* @param lenderVault address of vault
* @return element of on-chain quote history
*/
function getOnChainQuoteHistory(
address lenderVault,
uint256 idx
) external view returns (DataTypesPeerToPeer.OnChainQuoteInfo memory);
/**
* @notice function returns array of structs containing the on-chain quote hash and validUntil timestamp
* @param lenderVault address of vault
* @param startIdx starting index from on chain quote history array
* @param endIdx ending index of on chain quote history array (non-inclusive)
* @return array of quote hash and validUntil data for on-chain quote history of a vault
*/
function getOnChainQuoteHistorySlice(
address lenderVault,
uint256 startIdx,
uint256 endIdx
) external view returns (DataTypesPeerToPeer.OnChainQuoteInfo[] memory);
/**
* @notice function returns the number of on-chain quotes that were added or updated
* @param lenderVault address of vault
* @return number of on-chain quotes that were added or updated
*/
function getOnChainQuoteHistoryLength(
address lenderVault
) external view returns (uint256);
}
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.19;
import {DataTypesPeerToPeer} from "../DataTypesPeerToPeer.sol";
interface IVaultCallback {
/**
* @notice function which handles borrow side callback
* @param loan loan data passed to the callback
* @param data any extra info needed for the callback functionality
*/
function borrowCallback(
DataTypesPeerToPeer.Loan calldata loan,
bytes calldata data
) external;
/**
* @notice function which handles repay side callback
* @param loan loan data passed to the callback
* @param data any extra info needed for the callback functionality
*/
function repayCallback(
DataTypesPeerToPeer.Loan calldata loan,
bytes calldata data
) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 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 {
using Address for address;
/**
* @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.encodeWithSelector(token.transfer.selector, 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.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 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.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @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.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @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 silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
{
"compilationTarget": {
"contracts/peer-to-peer/BorrowerGateway.sol": "BorrowerGateway"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_addressRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DeadlinePassed","type":"error"},{"inputs":[],"name":"InconsistentExpVaultBalIncrease","type":"error"},{"inputs":[],"name":"InsufficientSendAmount","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidBorrower","type":"error"},{"inputs":[],"name":"InvalidFee","type":"error"},{"inputs":[],"name":"InvalidRepayAmount","type":"error"},{"inputs":[],"name":"InvalidSendAmount","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"NonWhitelistedCallback","type":"error"},{"inputs":[],"name":"OutsideValidRepayWindow","type":"error"},{"inputs":[],"name":"ReclaimAmountIsZero","type":"error"},{"inputs":[],"name":"UnregisteredVault","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vaultAddr","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"components":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collToken","type":"address"},{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"uint40","name":"expiry","type":"uint40"},{"internalType":"uint40","name":"earliestRepay","type":"uint40"},{"internalType":"uint128","name":"initCollAmount","type":"uint128"},{"internalType":"uint128","name":"initLoanAmount","type":"uint128"},{"internalType":"uint128","name":"initRepayAmount","type":"uint128"},{"internalType":"uint128","name":"amountRepaidSoFar","type":"uint128"},{"internalType":"uint128","name":"amountReclaimedSoFar","type":"uint128"},{"internalType":"bool","name":"collUnlocked","type":"bool"},{"internalType":"address","name":"collTokenCompartmentAddr","type":"address"}],"indexed":false,"internalType":"struct DataTypesPeerToPeer.Loan","name":"loan","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"upfrontFee","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"loanId","type":"uint256"},{"indexed":false,"internalType":"address","name":"callbackAddr","type":"address"},{"indexed":false,"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"Borrowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128[2]","name":"newFeeParams","type":"uint128[2]"}],"name":"ProtocolFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vaultAddr","type":"address"},{"indexed":true,"internalType":"uint256","name":"loanId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"Repaid","type":"event"},{"inputs":[],"name":"addressRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lenderVault","type":"address"},{"components":[{"internalType":"uint256","name":"collSendAmount","type":"uint256"},{"internalType":"uint256","name":"expectedProtocolAndVaultTransferFee","type":"uint256"},{"internalType":"uint256","name":"expectedCompartmentTransferFee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"minLoanAmount","type":"uint256"},{"internalType":"address","name":"callbackAddr","type":"address"},{"internalType":"bytes","name":"callbackData","type":"bytes"},{"internalType":"bytes","name":"mysoTokenManagerData","type":"bytes"}],"internalType":"struct DataTypesPeerToPeer.BorrowTransferInstructions","name":"borrowInstructions","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"collToken","type":"address"},{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"oracleAddr","type":"address"},{"internalType":"uint256","name":"minLoan","type":"uint256"},{"internalType":"uint256","name":"maxLoan","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"earliestRepayTenor","type":"uint256"},{"internalType":"address","name":"borrowerCompartmentImplementation","type":"address"},{"internalType":"bool","name":"isSingleUse","type":"bool"},{"internalType":"address","name":"whitelistAddr","type":"address"},{"internalType":"bool","name":"isWhitelistAddrSingleBorrower","type":"bool"}],"internalType":"struct DataTypesPeerToPeer.GeneralQuoteInfo","name":"generalQuoteInfo","type":"tuple"},{"internalType":"bytes32","name":"quoteTuplesRoot","type":"bytes32"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes[]","name":"compactSigs","type":"bytes[]"}],"internalType":"struct DataTypesPeerToPeer.OffChainQuote","name":"offChainQuote","type":"tuple"},{"components":[{"internalType":"uint256","name":"loanPerCollUnitOrLtv","type":"uint256"},{"internalType":"int256","name":"interestRatePctInBase","type":"int256"},{"internalType":"uint256","name":"upfrontFeePctInBase","type":"uint256"},{"internalType":"uint256","name":"tenor","type":"uint256"}],"internalType":"struct DataTypesPeerToPeer.QuoteTuple","name":"quoteTuple","type":"tuple"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"borrowWithOffChainQuote","outputs":[{"components":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collToken","type":"address"},{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"uint40","name":"expiry","type":"uint40"},{"internalType":"uint40","name":"earliestRepay","type":"uint40"},{"internalType":"uint128","name":"initCollAmount","type":"uint128"},{"internalType":"uint128","name":"initLoanAmount","type":"uint128"},{"internalType":"uint128","name":"initRepayAmount","type":"uint128"},{"internalType":"uint128","name":"amountRepaidSoFar","type":"uint128"},{"internalType":"uint128","name":"amountReclaimedSoFar","type":"uint128"},{"internalType":"bool","name":"collUnlocked","type":"bool"},{"internalType":"address","name":"collTokenCompartmentAddr","type":"address"}],"internalType":"struct DataTypesPeerToPeer.Loan","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lenderVault","type":"address"},{"components":[{"internalType":"uint256","name":"collSendAmount","type":"uint256"},{"internalType":"uint256","name":"expectedProtocolAndVaultTransferFee","type":"uint256"},{"internalType":"uint256","name":"expectedCompartmentTransferFee","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"minLoanAmount","type":"uint256"},{"internalType":"address","name":"callbackAddr","type":"address"},{"internalType":"bytes","name":"callbackData","type":"bytes"},{"internalType":"bytes","name":"mysoTokenManagerData","type":"bytes"}],"internalType":"struct DataTypesPeerToPeer.BorrowTransferInstructions","name":"borrowInstructions","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"collToken","type":"address"},{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"oracleAddr","type":"address"},{"internalType":"uint256","name":"minLoan","type":"uint256"},{"internalType":"uint256","name":"maxLoan","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"earliestRepayTenor","type":"uint256"},{"internalType":"address","name":"borrowerCompartmentImplementation","type":"address"},{"internalType":"bool","name":"isSingleUse","type":"bool"},{"internalType":"address","name":"whitelistAddr","type":"address"},{"internalType":"bool","name":"isWhitelistAddrSingleBorrower","type":"bool"}],"internalType":"struct DataTypesPeerToPeer.GeneralQuoteInfo","name":"generalQuoteInfo","type":"tuple"},{"components":[{"internalType":"uint256","name":"loanPerCollUnitOrLtv","type":"uint256"},{"internalType":"int256","name":"interestRatePctInBase","type":"int256"},{"internalType":"uint256","name":"upfrontFeePctInBase","type":"uint256"},{"internalType":"uint256","name":"tenor","type":"uint256"}],"internalType":"struct DataTypesPeerToPeer.QuoteTuple[]","name":"quoteTuples","type":"tuple[]"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"internalType":"struct DataTypesPeerToPeer.OnChainQuote","name":"onChainQuote","type":"tuple"},{"internalType":"uint256","name":"quoteTupleIdx","type":"uint256"}],"name":"borrowWithOnChainQuote","outputs":[{"components":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collToken","type":"address"},{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"uint40","name":"expiry","type":"uint40"},{"internalType":"uint40","name":"earliestRepay","type":"uint40"},{"internalType":"uint128","name":"initCollAmount","type":"uint128"},{"internalType":"uint128","name":"initLoanAmount","type":"uint128"},{"internalType":"uint128","name":"initRepayAmount","type":"uint128"},{"internalType":"uint128","name":"amountRepaidSoFar","type":"uint128"},{"internalType":"uint128","name":"amountReclaimedSoFar","type":"uint128"},{"internalType":"bool","name":"collUnlocked","type":"bool"},{"internalType":"address","name":"collTokenCompartmentAddr","type":"address"}],"internalType":"struct DataTypesPeerToPeer.Loan","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getProtocolFeeParams","outputs":[{"internalType":"uint128[2]","name":"","type":"uint128[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"targetLoanId","type":"uint256"},{"internalType":"uint128","name":"targetRepayAmount","type":"uint128"},{"internalType":"uint128","name":"expectedTransferFee","type":"uint128"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"callbackAddr","type":"address"},{"internalType":"bytes","name":"callbackData","type":"bytes"}],"internalType":"struct DataTypesPeerToPeer.LoanRepayInstructions","name":"loanRepayInstructions","type":"tuple"},{"internalType":"address","name":"vaultAddr","type":"address"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128[2]","name":"_newFeeParams","type":"uint128[2]"}],"name":"setProtocolFeeParams","outputs":[],"stateMutability":"nonpayable","type":"function"}]