ETH Price: $2,366.54 (-4.15%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Repay211166422024-11-04 20:22:111 hr ago1730751731IN
0x74241e1A...29Ab40D53
0 ETH0.001369775.7565184
Repay211166362024-11-04 20:20:591 hr ago1730751659IN
0x74241e1A...29Ab40D53
0 ETH0.001361145.72026183
Repay211165292024-11-04 19:59:231 hr ago1730750363IN
0x74241e1A...29Ab40D53
0 ETH0.001296625.44909812
Repay211155272024-11-04 16:38:115 hrs ago1730738291IN
0x74241e1A...29Ab40D53
0 ETH0.0025140810.44187212
Repay211101342024-11-03 22:34:4723 hrs ago1730673287IN
0x74241e1A...29Ab40D53
0 ETH0.001028794.04319128
Repay211099802024-11-03 22:03:5923 hrs ago1730671439IN
0x74241e1A...29Ab40D53
0 ETH0.001031724.3358621
Repay211099582024-11-03 21:59:3523 hrs ago1730671175IN
0x74241e1A...29Ab40D53
0 ETH0.001041654.37760511
Repay211099392024-11-03 21:55:4724 hrs ago1730670947IN
0x74241e1A...29Ab40D53
0 ETH0.000956784.02090615
Repay211099082024-11-03 21:49:3524 hrs ago1730670575IN
0x74241e1A...29Ab40D53
0 ETH0.000927873.9364699
Repay211098702024-11-03 21:41:5924 hrs ago1730670119IN
0x74241e1A...29Ab40D53
0 ETH0.001077764.52935091
Repay211098502024-11-03 21:37:4724 hrs ago1730669867IN
0x74241e1A...29Ab40D53
0 ETH0.000996184.18651204
Repay211080522024-11-03 15:36:5930 hrs ago1730648219IN
0x74241e1A...29Ab40D53
0 ETH0.002756168.91496861
Repay211069632024-11-03 11:57:3534 hrs ago1730635055IN
0x74241e1A...29Ab40D53
0 ETH0.001404335.47961988
Repay211051452024-11-03 5:53:1140 hrs ago1730613191IN
0x74241e1A...29Ab40D53
0 ETH0.00121055.01502464
Repay211050662024-11-03 5:37:1140 hrs ago1730612231IN
0x74241e1A...29Ab40D53
0 ETH0.001435184.86575579
Repay211045722024-11-03 3:58:1142 hrs ago1730606291IN
0x74241e1A...29Ab40D53
0 ETH0.000895493.40902381
Repay211021122024-11-02 19:41:592 days ago1730576519IN
0x74241e1A...29Ab40D53
0 ETH0.001592876.61576997
Repay211020982024-11-02 19:39:112 days ago1730576351IN
0x74241e1A...29Ab40D53
0 ETH0.002202227.82939076
Repay211020792024-11-02 19:35:232 days ago1730576123IN
0x74241e1A...29Ab40D53
0 ETH0.002118737.87646624
Repay211002992024-11-02 13:37:112 days ago1730554631IN
0x74241e1A...29Ab40D53
0 ETH0.001451035.70261701
Repay210973192024-11-02 3:37:232 days ago1730518643IN
0x74241e1A...29Ab40D53
0 ETH0.000999434.30057414
Repay210957572024-11-01 22:23:232 days ago1730499803IN
0x74241e1A...29Ab40D53
0 ETH0.001589086.6
Repay210957492024-11-01 22:21:472 days ago1730499707IN
0x74241e1A...29Ab40D53
0 ETH0.001520225.97453643
Repay210938162024-11-01 15:52:593 days ago1730476379IN
0x74241e1A...29Ab40D53
0 ETH0.0067182121.79596896
Repay210916922024-11-01 8:46:353 days ago1730450795IN
0x74241e1A...29Ab40D53
0 ETH0.001645296.91441219
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RepaymentController

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : RepaymentController.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "./interfaces/IRepaymentController.sol";
import "./interfaces/IPromissoryNote.sol";
import "./interfaces/ILoanCore.sol";
import "./interfaces/IFeeController.sol";

import "./libraries/InterestCalculator.sol";
import "./libraries/FeeLookups.sol";
import "./libraries/LoanLibrary.sol";

import {
    RC_ZeroAddress,
    RC_CannotDereference,
    RC_InvalidState,
    RC_OnlyLender
} from "./errors/Lending.sol";

/**
 * @title RepaymentController
 * @author Non-Fungible Technologies, Inc.
 *
 * The Repayment Controller is the entry point for all loan lifecycle
 * operations in the Arcade.xyz lending protocol once a loan has begun.
 * This contract allows a caller to calculate an amount due on a loan,
 * repay an open loan, and claim collateral on a defaulted loan. It
 * is this contract's responsibility to verify loan conditions before
 * calling LoanCore.
 */
contract RepaymentController is IRepaymentController, InterestCalculator, FeeLookups {
    using SafeERC20 for IERC20;

    // ============================================ STATE ===============================================

    ILoanCore private immutable loanCore;
    IPromissoryNote private immutable lenderNote;
    IFeeController private immutable feeController;

    // ========================================= CONSTRUCTOR ============================================

    /**
     * @notice Creates a new repayment controller contract.
     *
     * @dev For this controller to work, it needs to be granted the REPAYER_ROLE
     *      in loan core after deployment.
     *
     * @param _loanCore                     The address of the loan core logic of the protocol.
     * @param _feeController                The address of the fee logic of the protocol.
     */
    constructor(address _loanCore, address _feeController) {
        if (_loanCore == address(0)) revert RC_ZeroAddress("loanCore");
        if (_feeController == address(0)) revert RC_ZeroAddress("feeController");

        loanCore = ILoanCore(_loanCore);
        lenderNote = loanCore.lenderNote();
        feeController = IFeeController(_feeController);
    }

    // ==================================== LIFECYCLE OPERATIONS ========================================

    /**
     * @notice Repay an active loan, referenced by borrower note ID (equivalent to loan ID). The interest for a loan
     *         is calculated, and the principal plus interest is withdrawn from the caller.
     *         Anyone can repay a loan. Control is passed to LoanCore to complete repayment.
     *
     * @param  loanId               The ID of the loan.
     */
    function repay(uint256 loanId) external override {
        (uint256 amountFromBorrower, uint256 amountToLender) = _prepareRepay(loanId);

        // call repay function in loan core -  msg.sender will pay the amountFromBorrower
        loanCore.repay(loanId, msg.sender, amountFromBorrower, amountToLender);
    }

    /**
     * @notice Repay an active loan, referenced by borrower note ID (equivalent to loan ID). The interest for a loan
     *         is calculated, and the principal plus interest is withdrawn from the caller. Anyone can repay a loan.
     *         Using forceRepay will not send funds to the lender: instead, those funds will be made
     *         available for withdrawal in LoanCore. Can be used in cases where a borrower has funds to repay
     *         but the lender is not able to receive those tokens (e.g. token blacklist).
     *
     * @param  loanId               The ID of the loan.
     */
    function forceRepay(uint256 loanId) external override {
        (uint256 amountFromBorrower, uint256 amountToLender) = _prepareRepay(loanId);

        // call repay function in loan core -  msg.sender will pay the amountFromBorrower
        loanCore.forceRepay(loanId, msg.sender, amountFromBorrower, amountToLender);
    }

    /**
     * @notice Claim collateral on an active loan, referenced by lender note ID (equivalent to loan ID).
     *         The loan must be past the due date. No funds are collected
     *         from the borrower.
     *
     * @param  loanId               The ID of the loan.
     */
    function claim(uint256 loanId) external override {
        LoanLibrary.LoanData memory data = loanCore.getLoan(loanId);
        if (data.state == LoanLibrary.LoanState.DUMMY_DO_NOT_USE) revert RC_CannotDereference(loanId);

        // make sure that caller owns lender note
        // Implicitly checks if loan is active - if inactive, note will not exist
        address lender = lenderNote.ownerOf(loanId);
        if (lender != msg.sender) revert RC_OnlyLender(lender, msg.sender);

        LoanLibrary.LoanTerms memory terms = data.terms;
        uint256 interest = getInterestAmount(terms.principal, terms.proratedInterestRate);
        uint256 totalOwed = terms.principal + interest;

        uint256 claimFee = (totalOwed * data.feeSnapshot.lenderDefaultFee) / BASIS_POINTS_DENOMINATOR;

        loanCore.claim(loanId, claimFee);
    }

    /**
     * @notice Redeem a lender note for a completed return in return for funds repaid in an earlier
     *         transaction via forceRepay. The lender note must be owned by the caller.
     *
     * @param loanId                    The ID of the lender note to redeem.
     */
    function redeemNote(uint256 loanId, address to) external override {
        if (to == address(0)) revert RC_ZeroAddress("to");

        LoanLibrary.LoanData memory data = loanCore.getLoan(loanId);
        (, uint256 amountOwed) = loanCore.getNoteReceipt(loanId);

        if (data.state != LoanLibrary.LoanState.Repaid) revert RC_InvalidState(data.state);
        address lender = lenderNote.ownerOf(loanId);
        if (lender != msg.sender) revert RC_OnlyLender(lender, msg.sender);

        uint256 redeemFee = (amountOwed * feeController.getLendingFee(FL_08)) / BASIS_POINTS_DENOMINATOR;

        loanCore.redeemNote(loanId, redeemFee, to);
    }

    // =========================================== HELPERS ==============================================

    /**
     * @dev Shared logic to perform validation and calculations for repay and forceRepay.
     *
     * @param loanId               The ID of the loan.
     *
     * @return amountFromBorrower   The amount to collect from the borrower.
     * @return amountToLender       The amount owed to the lender.
     */
    function _prepareRepay(uint256 loanId) internal view returns (uint256 amountFromBorrower, uint256 amountToLender) {
        LoanLibrary.LoanData memory data = loanCore.getLoan(loanId);
        if (data.state == LoanLibrary.LoanState.DUMMY_DO_NOT_USE) revert RC_CannotDereference(loanId);
        if (data.state != LoanLibrary.LoanState.Active) revert RC_InvalidState(data.state);

        LoanLibrary.LoanTerms memory terms = data.terms;

        uint256 interest = getInterestAmount(terms.principal, terms.proratedInterestRate);

        uint256 interestFee = (interest * data.feeSnapshot.lenderInterestFee) / BASIS_POINTS_DENOMINATOR;
        uint256 principalFee = (terms.principal * data.feeSnapshot.lenderPrincipalFee) / BASIS_POINTS_DENOMINATOR;

        amountFromBorrower = terms.principal + interest;
        amountToLender = amountFromBorrower - interestFee - principalFee;
    }
}

File 2 of 16 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.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;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    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));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    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");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @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");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 3 of 16 : IRepaymentController.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

interface IRepaymentController {
    // ============== Lifeycle Operations ==============

    function repay(uint256 loanId) external;

    function forceRepay(uint256 loanId) external;

    function claim(uint256 loanId) external;

    function redeemNote(uint256 loanId, address to) external;
}

File 4 of 16 : IPromissoryNote.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";

import "./INFTWithDescriptor.sol";

interface IPromissoryNote is INFTWithDescriptor, IERC721Enumerable {
    // ============== Token Operations ==============

    function mint(address to, uint256 loanId) external returns (uint256);

    function burn(uint256 tokenId) external;

    // ============== Initializer ==============

    function initialize(address loanCore) external;
}

File 5 of 16 : ILoanCore.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

import "../libraries/LoanLibrary.sol";
import "./IPromissoryNote.sol";

interface ILoanCore {

    // ================ Data Types =================

    struct AffiliateSplit {
        address affiliate;
        uint96 splitBps;
    }

    struct NoteReceipt {
        address token;
        uint256 amount;
    }

    // ================ Events =================

    event LoanStarted(uint256 loanId, address lender, address borrower);
    event LoanRepaid(uint256 loanId);
    event ForceRepay(uint256 loanId);
    event LoanRolledOver(uint256 oldLoanId, uint256 newLoanId);
    event LoanClaimed(uint256 loanId);
    event NoteRedeemed(address indexed token, address indexed caller, address indexed to, uint256 tokenId, uint256 amount);
    event NonceUsed(address indexed user, uint160 nonce);

    event FeesWithdrawn(address indexed token, address indexed caller, address indexed to, uint256 amount);
    event AffiliateSet(bytes32 indexed code, address indexed affiliate, uint96 splitBps);

    // ============== Lifecycle Operations ==============

    function startLoan(
        address lender,
        address borrower,
        LoanLibrary.LoanTerms calldata terms,
        uint256 _amountFromLender,
        uint256 _amountToBorrower,
        LoanLibrary.FeeSnapshot calldata feeSnapshot
    ) external returns (uint256 loanId);

    function repay(
        uint256 loanId,
        address payer,
        uint256 _amountFromPayer,
        uint256 _amountToLender
    ) external;

    function forceRepay(
        uint256 loanId,
        address payer,
        uint256 _amountFromPayer,
        uint256 _amountToLender
    ) external;

    function claim(
        uint256 loanId,
        uint256 _amountFromLender
    ) external;

    function redeemNote(
        uint256 loanId,
        uint256 _amountFromLender,
        address to
    ) external;

    function rollover(
        uint256 oldLoanId,
        address borrower,
        address lender,
        LoanLibrary.LoanTerms calldata terms,
        uint256 _settledAmount,
        uint256 _amountToOldLender,
        uint256 _amountToLender,
        uint256 _amountToBorrower
    ) external returns (uint256 newLoanId);

    // ============== Nonce Management ==============

    function consumeNonce(address user, uint160 nonce) external;

    function cancelNonce(uint160 nonce) external;

    // ============== Fee Management ==============

    function withdraw(address token, uint256 amount, address to) external;

    function withdrawProtocolFees(address token, address to) external;

    // ============== Admin Operations ==============

    function setAffiliateSplits(bytes32[] calldata codes, AffiliateSplit[] calldata splits) external;

    // ============== View Functions ==============

    function getLoan(uint256 loanId) external view returns (LoanLibrary.LoanData calldata loanData);

    function getNoteReceipt(uint256 loanId) external view returns (address token, uint256 amount);

    function isNonceUsed(address user, uint160 nonce) external view returns (bool);

    function borrowerNote() external view returns (IPromissoryNote);

    function lenderNote() external view returns (IPromissoryNote);

}

File 6 of 16 : IFeeController.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

interface IFeeController {
    // ================ Structs ================

    struct FeesOrigination {
        uint16 borrowerOriginationFee;
        uint16 lenderOriginationFee;
        uint16 lenderDefaultFee;
        uint16 lenderInterestFee;
        uint16 lenderPrincipalFee;
    }

    struct FeesRollover {
        uint16 borrowerRolloverFee;
        uint16 lenderRolloverFee;
    }

    // ================ Events =================

    event SetLendingFee(bytes32 indexed id, uint16 fee);

    event SetVaultMintFee(uint64 fee);

    // ================ Getter/Setter =================

    function setLendingFee(bytes32 id, uint16 fee) external;

    function setVaultMintFee(uint64 fee) external;

    function getLendingFee(bytes32 id) external view returns (uint16);

    function getVaultMintFee() external view returns (uint64);

    function getFeesOrigination() external view returns (FeesOrigination memory);

    function getFeesRollover() external view returns (FeesRollover memory);

    function getMaxLendingFee(bytes32 id) external view returns (uint16);

    function getMaxVaultMintFee() external view returns (uint64);
}

File 7 of 16 : InterestCalculator.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

/**
 * @title InterestCalculator
 * @author Non-Fungible Technologies, Inc.
 *
 * Interface for calculating the interest amount
 * given an interest rate and principal amount. Assumes
 * that the interestRate is already expressed over the desired
 * time period.
 */
abstract contract InterestCalculator {
    // ============================================ STATE ==============================================

    /// @dev The units of precision equal to the minimum interest of 1 basis point.
    uint256 public constant INTEREST_RATE_DENOMINATOR = 1e18;

    uint256 public constant BASIS_POINTS_DENOMINATOR = 1e4;

    // ======================================== CALCULATIONS ===========================================

    /**
     * @notice Calculate the interest due over a full term.
     *
     * @dev Interest and principal must be entered with 18 units of
     *      precision from the basis point unit (e.g. 1e18 == 0.01%)
     *
     * @param principal                             Principal amount in the loan terms.
     * @param proratedInterestRate                  Interest rate in the loan terms, prorated over loan duration.
     *
     * @return interest                             The amount of interest due.
     */
    function getInterestAmount(uint256 principal, uint256 proratedInterestRate) public pure returns (uint256) {
        return principal * proratedInterestRate / (INTEREST_RATE_DENOMINATOR * BASIS_POINTS_DENOMINATOR);
    }
}

File 8 of 16 : FeeLookups.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

/**
 * @title FeeLookups
 * @author Non-Fungible Technologies, Inc.
 *
 * Enumerates unique identifiers for fee identifiers
 * that the lending protocol uses.
 */
abstract contract FeeLookups {
    /// @dev Origination fees: amount in bps, payable in loan token
    bytes32 public constant FL_01 = keccak256("BORROWER_ORIGINATION_FEE");
    bytes32 public constant FL_02 = keccak256("LENDER_ORIGINATION_FEE");

    /// @dev Rollover fees: amount in bps, payable in loan token
    bytes32 public constant FL_03 = keccak256("BORROWER_ROLLOVER_FEE");
    bytes32 public constant FL_04 = keccak256("LENDER_ROLLOVER_FEE");

    /// @dev Loan closure fees: amount in bps, payable in loan token
    bytes32 public constant FL_05 = keccak256("LENDER_DEFAULT_FEE");
    bytes32 public constant FL_06 = keccak256("LENDER_INTEREST_FEE");
    bytes32 public constant FL_07 = keccak256("LENDER_PRINCIPAL_FEE");
    bytes32 public constant FL_08 = keccak256("LENDER_REDEEM_FEE");
}

File 9 of 16 : LoanLibrary.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

/**
 * @title LoanLibrary
 * @author Non-Fungible Technologies, Inc.
 *
 * Contains all data types used across Arcade lending contracts.
 */
library LoanLibrary {
    /**
     * @dev Enum describing the current state of a loan.
     * State change flow:
     * Created -> Active -> Repaid
     *                   -> Defaulted
     */
    enum LoanState {
        // We need a default that is not 'Created' - this is the zero value
        DUMMY_DO_NOT_USE,
        // The loan has been initialized, funds have been delivered to the borrower and the collateral is held.
        Active,
        // The loan has been repaid, and the collateral has been returned to the borrower. This is a terminal state.
        Repaid,
        // The loan was delinquent and collateral claimed by the lender. This is a terminal state.
        Defaulted
    }

    /**
     * @dev The raw terms of a loan.
     */
    struct LoanTerms {
        // Interest expressed as a rate, unlike V1 gross value.
        // Input conversion: 0.01% = (1 * 10**18) ,  10.00% = (1000 * 10**18)
        // This represents the rate over the lifetime of the loan, not APR.
        // 0.01% is the minimum interest rate allowed by the protocol.
        uint256 proratedInterestRate;
        /// @dev Full-slot variables
        // The amount of principal in terms of the payableCurrency.
        uint256 principal;
        // The token ID of the address holding the collateral.
        /// @dev Can be an AssetVault, or the NFT contract for unbundled collateral
        address collateralAddress;
        /// @dev Packed variables
        // The number of seconds representing relative due date of the loan.
        /// @dev Max is 94,608,000, fits in 96 bits
        uint96 durationSecs;
        // The token ID of the collateral.
        uint256 collateralId;
        // The payable currency for the loan principal and interest.
        address payableCurrency;
        // Timestamp for when signature for terms expires
        uint96 deadline;
        // Affiliate code used to start the loan.
        bytes32 affiliateCode;
    }

    /**
     * @dev Modification of loan terms, used for signing only.
     *      Instead of a collateralId, a list of predicates
     *      is defined by 'bytes' in items.
     */
    struct LoanTermsWithItems {
        // Interest expressed as a rate, unlike V1 gross value.
        // Input conversion: 0.01% = (1 * 10**18) ,  10.00% = (1000 * 10**18)
        // This represents the rate over the lifetime of the loan, not APR.
        // 0.01% is the minimum interest rate allowed by the protocol.
        uint256 proratedInterestRate;
        /// @dev Full-slot variables
        // The amount of principal in terms of the payableCurrency.
        uint256 principal;
        // The tokenID of the address holding the collateral
        address collateralAddress;
        /// @dev Packed variables
        // The number of seconds representing relative due date of the loan.
        /// @dev Max is 94,608,000, fits in 96 bits
        uint96 durationSecs;
        // An encoded list of predicates, along with their verifiers.
        bytes items;
        // The payable currency for the loan principal and interest.
        address payableCurrency;
        // Timestamp for when signature for terms expires
        uint96 deadline;
        // Affiliate code used to start the loan.
        bytes32 affiliateCode;
    }

    /**
     * @dev Predicate for item-based verifications
     */
    struct Predicate {
        // The encoded predicate, to decoded and parsed by the verifier contract.
        bytes data;
        // The verifier contract.
        address verifier;
    }

    /**
     * @dev Snapshot of lending fees at the time of loan creation.
     */
    struct FeeSnapshot {
        // The fee taken when lender claims defaulted collateral.
        uint16 lenderDefaultFee;
        // The fee taken from the borrower's interest repayment.
        uint16 lenderInterestFee;
        // The fee taken from the borrower's principal repayment.
        uint16 lenderPrincipalFee;
    }

    /**
     * @dev The data of a loan. This is stored once the loan is Active
     */
    struct LoanData {
        /// @dev Packed variables
        // The current state of the loan.
        LoanState state;
        // Start date of the loan, using block.timestamp.
        uint160 startDate;
        /// @dev Full-slot variables
        // The raw terms of the loan.
        LoanTerms terms;
        // Record of lending fees at the time of loan creation.
        FeeSnapshot feeSnapshot;
    }
}

File 10 of 16 : Lending.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

import "../libraries/LoanLibrary.sol";

/**
 * @title LendingErrors
 * @author Non-Fungible Technologies, Inc.
 *
 * This file contains custom errors for the core lending protocol contracts, with errors
 * prefixed by the contract that throws them (e.g., "OC_" for OriginationController).
 * Errors located in one place to make it possible to holistically look at all
 * protocol failure cases.
 */

// ==================================== ORIGINATION CONTROLLER ======================================
/// @notice All errors prefixed with OC_, to separate from other contracts in the protocol.

/**
 * @notice Zero address passed in where not allowed.
 *
 * @param addressType                  The name of the parameter for which a zero address was provided.
 */
error OC_ZeroAddress(string addressType);

/**
 * @notice Ensure valid loan state for loan lifceycle operations.
 *
 * @param state                         Current state of a loan according to LoanState enum.
 */
error OC_InvalidState(LoanLibrary.LoanState state);

/**
 * @notice Loan duration must be greater than 1hr and less than 3yrs.
 *
 * @param durationSecs                 Total amount of time in seconds.
 */
error OC_LoanDuration(uint256 durationSecs);

/**
 * @notice Interest must be greater than 0.01% and less than 10,000%. (interestRate / 1e18 >= 1)
 *
 * @param interestRate                  InterestRate with 1e18 multiplier.
 */
error OC_InterestRate(uint256 interestRate);

/**
 * @notice One of the predicates for item verification failed.
 *
 * @param borrower                      The address of the borrower.
 * @param lender                        The address of the lender.
 * @param verifier                      The address of the verifier contract.
 * @param collateralAddress             The address of the collateral token.
 * @param collateralId                  The token ID of the collateral.
 * @param data                          The verification data (to be parsed by verifier).
 */
error OC_PredicateFailed(
    address borrower,
    address lender,
    address verifier,
    address collateralAddress,
    uint256 collateralId,
    bytes data
);

/**
 * @notice The predicates array is empty.
 */
error OC_PredicatesArrayEmpty();

/**
 * @notice A caller attempted to approve themselves.
 *
 * @param caller                        The caller of the approve function.
 */
error OC_SelfApprove(address caller);

/**
 * @notice A caller attempted to originate a loan with their own signature.
 *
 * @param caller                        The caller of the approve function, who was also the signer.
 */
error OC_ApprovedOwnLoan(address caller);

/**
 * @notice The signature could not be recovered to the counterparty or approved party.
 *
 * @param target                        The target party of the signature, which should either be the signer,
 *                                      or someone who has approved the signer.
 * @param signer                        The signer determined from ECDSA.recover.
 */
error OC_InvalidSignature(address target, address signer);

/**
 * @notice The verifier contract specified in a predicate has not been whitelisted.
 *
 * @param verifier                      The verifier the caller attempted to use.
 */
error OC_InvalidVerifier(address verifier);

/**
 * @notice The function caller was neither borrower or lender, and was not approved by either.
 *
 * @param caller                        The unapproved function caller.
 */
error OC_CallerNotParticipant(address caller);

/**
 * @notice Signer is attempting to take the wrong side of the loan.
 *
 * @param signer                       The address of the external signer.
 */
error OC_SideMismatch(address signer);

/**
 * @notice Two related parameters for batch operations did not match in length.
 */
error OC_BatchLengthMismatch();

/**
 * @notice Principal must be greater than 9999 Wei.
 *
 * @param principal                     Principal in ether.
 */
error OC_PrincipalTooLow(uint256 principal);

/**
 * @notice Signature must not be expired.
 *
 * @param deadline                      Deadline in seconds.
 */
error OC_SignatureIsExpired(uint256 deadline);

/**
 * @notice New currency does not match for a loan rollover request.
 *
 * @param oldCurrency                   The currency of the active loan.
 * @param newCurrency                   The currency of the new loan.
 */
error OC_RolloverCurrencyMismatch(address oldCurrency, address newCurrency);

/**
 * @notice New currency does not match for a loan rollover request.
 *
 * @param oldCollateralAddress          The address of the active loan's collateral.
 * @param newCollateralAddress          The token ID of the active loan's collateral.
 * @param oldCollateralId               The address of the new loan's collateral.
 * @param newCollateralId               The token ID of the new loan's collateral.
 */
error OC_RolloverCollateralMismatch(
    address oldCollateralAddress,
    uint256 oldCollateralId,
    address newCollateralAddress,
    uint256 newCollateralId
);

/**
 * @notice Provided payable currency address is not approved for lending.
 *
 * @param payableCurrency       ERC20 token address supplied in loan terms.
 */
error OC_InvalidCurrency(address payableCurrency);

/**
 * @notice Provided collateral address is not approved for lending.
 *
 * @param collateralAddress       ERC721 or ERC1155 token address supplied in loan terms.
 */
error OC_InvalidCollateral(address collateralAddress);

/**
 * @notice Provided token array does not hold any token addresses.
 */
error OC_ZeroArrayElements();

/**
 * @notice Provided token array holds more than 50 token addresses.
 */
error OC_ArrayTooManyElements();

// ==================================== ITEMS VERIFIER ======================================
/// @notice All errors prefixed with IV_, to separate from other contracts in the protocol.

/**
 * @notice The predicate payload was decoded successfully, but list of predicates is empty.
 */
error IV_NoPredicates();

/**
 * @notice Provided SignatureItem is missing an address.
 */
error IV_ItemMissingAddress();

/**
 * @notice Provided SignatureItem has an invalid collateral type.
 * @dev    Should never actually fire, since cType is defined by an enum, so will fail on decode.
 *
 * @param asset                        The NFT contract being checked.
 * @param cType                        The collateralTytpe provided.
 */
error IV_InvalidCollateralType(address asset, uint256 cType);

/**
 * @notice Provided signature item with no required amount. For single ERC721s, specify 1.
 *
 * @param asset                         The NFT contract being checked.
 * @param amount                        The amount provided (should be 0).
 */
error IV_NoAmount(address asset, uint256 amount);

/**
 * @notice Provided a wildcard for a non-ERC721.
 *
 * @param asset                         The NFT contract being checked.
 */
error IV_InvalidWildcard(address asset);

/**
 * @notice The provided token ID is out of bounds for the given collection.
 *
 * @param tokenId                       The token ID provided.
 */
error IV_InvalidTokenId(int256 tokenId);

/**
 * @notice The provided project ID does not exist on the target contract. Only
 *         used for ArtBlocks.
 *
 * @param projectId                     The project ID provided.
 * @param nextProjectId                 The contract's reported nextProjectId.
 */
error IV_InvalidProjectId(uint256 projectId, uint256 nextProjectId);

/**
 * @notice The provided collateralId converts to a vault, but
 *         the vault's address does not convert back to the provided collateralId
 *         when casted to a uint256.
 */
error IV_InvalidCollateralId(uint256 collateralId);

// ==================================== REPAYMENT CONTROLLER ======================================
/// @notice All errors prefixed with RC_, to separate from other contracts in the protocol.

/**
 * @notice Zero address passed in where not allowed.
 *
 * @param addressType                  The name of the parameter for which a zero address was provided.
 */
error RC_ZeroAddress(string addressType);

/**
 * @notice Could not dereference loan from loan ID.
 *
 * @param target                     The loanId being checked.
 */
error RC_CannotDereference(uint256 target);

/**
 * @notice Ensure valid loan state for loan lifceycle operations.
 *
 * @param state                         Current state of a loan according to LoanState enum.
 */
error RC_InvalidState(LoanLibrary.LoanState state);

/**
 * @notice Caller is not the owner of lender note.
 *
 * @param lender                     The owner of the lender note.
 * @param caller                     Msg.sender of the function call.
 */
error RC_OnlyLender(address lender, address caller);

// ==================================== Loan Core ======================================
/// @notice All errors prefixed with LC_, to separate from other contracts in the protocol.

/**
 * @notice Zero address passed in where not allowed.
 *
 * @param addressType                  The name of the parameter for which a zero address was provided.
 */
error LC_ZeroAddress(string addressType);

/// @notice Borrower address is same as lender address.
error LC_ReusedNote();

/// @notice Zero amount passed in where not allowed.
error LC_ZeroAmount();

/**
 * @notice Check collateral is not already used in a active loan.
 *
 * @param collateralAddress             Address of the collateral.
 * @param collateralId                  ID of the collateral token.
 */
error LC_CollateralInUse(address collateralAddress, uint256 collateralId);

/**
 * @notice The reported settlements are invalid, and LoanCore would lose tokens
 *         attempting to perform the requested operations.
 *
 *
 * @param payout                        Amount of tokens to be paid out.
 * @param collected                     Amount of tokens to collect - should be fewer than payout.
 */
error LC_CannotSettle(uint256 payout, uint256 collected);

/**
 * @notice User attempted to withdraw a pending balance that was in excess
 *         of what is available.
 *
 * @param amount                        Amount of tokens to be withdrawn.
 * @param available                     Amount of tokens available to withdraw.
 */
error LC_CannotWithdraw(uint256 amount, uint256 available);

/**
 * @notice Two arrays were provided that must be of matching length, but were not.
 *
 */
error LC_ArrayLengthMismatch();

/**
 * @notice A proposed affiliate split was submitted that is over the maximum.
 *
 * @param splitBps                     The proposed affiliate split.
 * @param maxSplitBps                  The maximum allowed affiliate split.
 *
 */
error LC_OverMaxSplit(uint96 splitBps, uint96 maxSplitBps);

/**
 * @notice Ensure valid loan state for loan lifceycle operations.
 *
 * @param state                         Current state of a loan according to LoanState enum.
 */
error LC_InvalidState(LoanLibrary.LoanState state);

/**
 * @notice Loan duration has not expired.
 *
 * @param dueDate                       Timestamp of the end of the loan duration.
 */
error LC_NotExpired(uint256 dueDate);

/**
 * @notice User address and the specified nonce have already been used.
 *
 * @param user                          Address of collateral owner.
 * @param nonce                         Represents the number of transactions sent by address.
 */
error LC_NonceUsed(address user, uint160 nonce);

/**
 * @notice Protocol attempted to set an affiliate code which already exists. Affiliate
 *         codes are immutable.
 *
 * @param affiliateCode                 The affiliate code being set.
 */
error LC_AffiliateCodeAlreadySet(bytes32 affiliateCode);

/**
 * @notice Specified note token ID does not have a redeemable receipt.
 *
 * @param loanId                     The loanId being checked.
 */
error LC_NoReceipt(uint256 loanId);

/**
 * @notice Only Loan Core contract can call this function.
 */
error LC_CallerNotLoanCore();

/**
 * @notice The loan core contract has been irreversibly shut down.
 */
error LC_Shutdown();

// ==================================== Promissory Note ======================================
/// @notice All errors prefixed with PN_, to separate from other contracts in the protocol.

/**
 * @notice Zero address passed in where not allowed.
 *
 * @param addressType                  The name of the parameter for which a zero address was provided.
 */
error PN_ZeroAddress(string addressType);

/**
 * @notice Caller of mint function must have the MINTER_ROLE in AccessControl.
 *
 * @param caller                        Address of the function caller.
 */
error PN_MintingRole(address caller);

/**
 * @notice Caller of burn function must have the BURNER_ROLE in AccessControl.
 *
 * @param caller                        Address of the function caller.
 */
error PN_BurningRole(address caller);

/**
 * @notice Non-existant token id provided as argument.
 *
 * @param tokenId                       The ID of the token to lookup the URI for.
 */
error PN_DoesNotExist(uint256 tokenId);

// ==================================== Fee Controller ======================================
/// @notice All errors prefixed with FC_, to separate from other contracts in the protocol.

/**
 * @notice Caller attempted to set a lending fee which is larger than the global maximum.
 */
error FC_LendingFeeOverMax(bytes32 selector, uint256 fee, uint256 maxFee);

/**
 * @notice Caller attempted to set a vault mint fee which is larger than the global maximum.
 */
error FC_VaultMintFeeOverMax(uint256 fee, uint256 maxFee);

// ==================================== ERC721 Permit ======================================
/// @notice All errors prefixed with ERC721P_, to separate from other contracts in the protocol.

/**
 * @notice Deadline for the permit has expired.
 *
 * @param deadline                      Permit deadline parameter as a timestamp.
 */
error ERC721P_DeadlineExpired(uint256 deadline);

/**
 * @notice Address of the owner to also be the owner of the tokenId.
 *
 * @param owner                        Owner parameter for the function call.
 */
error ERC721P_NotTokenOwner(address owner);

/**
 * @notice Invalid signature.
 *
 * @param signer                        Signer recovered from ECDSA sugnature hash.
 */
error ERC721P_InvalidSignature(address signer);

File 11 of 16 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @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);
}

File 12 of 16 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 13 of 16 : IERC721Enumerable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC721.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256 tokenId);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

File 14 of 16 : INFTWithDescriptor.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.18;

interface INFTWithDescriptor {
    // ============= Events ==============

    event SetDescriptor(address indexed caller, address indexed descriptor);

    // ================ Resource Metadata ================

    function tokenURI(uint256 tokenId) external view returns (string memory);

    function setDescriptor(address descriptor) external;
}

File 15 of 16 : IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;
}

File 16 of 16 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "metadata": {
    "bytecodeHash": "none"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_loanCore","type":"address"},{"internalType":"address","name":"_feeController","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"target","type":"uint256"}],"name":"RC_CannotDereference","type":"error"},{"inputs":[{"internalType":"enum LoanLibrary.LoanState","name":"state","type":"uint8"}],"name":"RC_InvalidState","type":"error"},{"inputs":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"caller","type":"address"}],"name":"RC_OnlyLender","type":"error"},{"inputs":[{"internalType":"string","name":"addressType","type":"string"}],"name":"RC_ZeroAddress","type":"error"},{"inputs":[],"name":"BASIS_POINTS_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FL_01","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FL_02","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FL_03","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FL_04","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FL_05","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FL_06","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FL_07","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FL_08","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INTEREST_RATE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"forceRepay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"proratedInterestRate","type":"uint256"}],"name":"getInterestAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"redeemNote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60e06040523480156200001157600080fd5b50604051620011cf380380620011cf83398101604081905262000034916200016b565b6001600160a01b0382166200007c5760405163302c848b60e01b81526020600482015260086024820152676c6f616e436f726560c01b60448201526064015b60405180910390fd5b6001600160a01b038116620000c55760405163302c848b60e01b815260206004820152600d60248201526c3332b2a1b7b73a3937b63632b960991b604482015260640162000073565b6001600160a01b038216608081905260408051600162010aa960e71b03198152905163ff7aab80916004808201926020929091908290030181865afa15801562000113573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001399190620001aa565b6001600160a01b0390811660a0521660c05250620001d1565b6001600160a01b03811681146200016857600080fd5b50565b600080604083850312156200017f57600080fd5b82516200018c8162000152565b60208401519092506200019f8162000152565b809150509250929050565b600060208284031215620001bd57600080fd5b8151620001ca8162000152565b9392505050565b60805160a05160c051610f9662000239600039600061091801526000818161044501526108250152600081816102f80152818161037b0152818161056901528181610611015281816106d001528181610768015281816109cb0152610a380152610f966000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c8063a7146e7111610097578063cfa498a311610066578063cfa498a31461023f578063db0a23c114610248578063ddb220ec1461026f578063ededcc411461029657600080fd5b8063a7146e71146101cf578063b8921e26146101f6578063c9498e541461021d578063cc3266e81461023057600080fd5b8063379607f5116100d3578063379607f51461016f57806359c86a11146101825780637eb094981461019557806384d2b81c146101bc57600080fd5b8063227e8f0c146100fa57806333f6b51c14610133578063371fd8e61461015a575b600080fd5b6101217f6b9fec8a90acd71b357b3fbde8e525c5e0a0ffebe7010905e79162a4fd6421bd81565b60405190815260200160405180910390f35b6101217fddfa60b1f3b0c3629357d48d7f8a1186bd1ff199faa6c6b792597e91bd705dc281565b61016d610168366004610bd7565b6102bd565b005b61016d61017d366004610bd7565b610362565b61016d610190366004610bd7565b6105d6565b6101217f4e2344e60c4b990f3c4cf2efa216c71144a011f9e4a940c6b459a8066c98e1f981565b6101216101ca366004610bf0565b610648565b6101217f41f539feb01b3a702d5e8c2e4367fa0d5a544df6b5ef24765c6836e0743db74281565b6101217f74ba47f4e32f0deada0ece4f758dd1cb5f98ba44c024c037a61f34bb066f568e81565b61016d61022b366004610c2a565b61067b565b610121670de0b6b3a764000081565b61012161271081565b6101217f6c9950464c33f914161b87af80469f5598c7ea5009d7b4464f7e3815112686a381565b6101217fc3a599955a4238a21ad67957aa12a28dc3e88efd2a54bc264ba15e23b257c35281565b6101217f4714fd9784ca8c9ee16df7000f2eb0fc7a2296e457de6968bc65d71fd287370681565b6000806102c983610a31565b6040516304f3841960e21b815260048101869052336024820152604481018390526064810182905291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906313ce1064906084015b600060405180830381600087803b15801561034557600080fd5b505af1158015610359573d6000803e3d6000fd5b50505050505050565b604051632820036560e11b8152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063504006ca906024016101a060405180830381865afa1580156103cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ef9190610d7e565b905060008151600381111561040657610406610e69565b0361042c57604051630fd8a76760e01b8152600481018390526024015b60405180910390fd5b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610494573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b89190610e7f565b90506001600160a01b03811633146104f457604051636b9e14ff60e01b81526001600160a01b0382166004820152336024820152604401610423565b60408201516020810151815160009161050c91610648565b905060008183602001516105209190610eb9565b9050600061271086606001516000015161ffff168361053f9190610ecc565b6105499190610ee3565b60405163c349026360e01b815260048101899052602481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063c349026390604401600060405180830381600087803b1580156105b557600080fd5b505af11580156105c9573d6000803e3d6000fd5b5050505050505050505050565b6000806105e283610a31565b60405163bb340b5d60e01b815260048101869052336024820152604481018390526064810182905291935091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063bb340b5d9060840161032b565b600061065e612710670de0b6b3a7640000610ecc565b6106688385610ecc565b6106729190610ee3565b90505b92915050565b6001600160a01b0381166106b75760405163302c848b60e01b8152602060048201526002602482015261746f60f01b6044820152606401610423565b604051632820036560e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063504006ca906024016101a060405180830381865afa158015610720573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107449190610d7e565b6040516385b2f18360e01b8152600481018590529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906385b2f183906024016040805180830381865afa1580156107ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d29190610f05565b915060029050825160038111156107eb576107eb610e69565b1461080c578151604051631b250a6b60e11b81526104239190600401610f33565b6040516331a9108f60e11b8152600481018590526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610874573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108989190610e7f565b90506001600160a01b03811633146108d457604051636b9e14ff60e01b81526001600160a01b0382166004820152336024820152604401610423565b60405163aee758e760e01b81527f4714fd9784ca8c9ee16df7000f2eb0fc7a2296e457de6968bc65d71fd28737066004820152600090612710906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063aee758e790602401602060405180830381865afa15801561095f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109839190610f5b565b6109919061ffff1685610ecc565b61099b9190610ee3565b60405163a443a63560e01b815260048101889052602481018290526001600160a01b0387811660448301529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a443a63590606401600060405180830381600087803b158015610a1157600080fd5b505af1158015610a25573d6000803e3d6000fd5b50505050505050505050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663504006ca856040518263ffffffff1660e01b8152600401610a8491815260200190565b6101a060405180830381865afa158015610aa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac69190610d7e565b9050600081516003811115610add57610add610e69565b03610afe57604051630fd8a76760e01b815260048101859052602401610423565b600181516003811115610b1357610b13610e69565b14610b34578051604051631b250a6b60e11b81526104239190600401610f33565b604081015160208101518151600091610b4c91610648565b9050600061271084606001516020015161ffff1683610b6b9190610ecc565b610b759190610ee3565b9050600061271085606001516040015161ffff168560200151610b989190610ecc565b610ba29190610ee3565b9050828460200151610bb49190610eb9565b965080610bc18389610f76565b610bcb9190610f76565b95505050505050915091565b600060208284031215610be957600080fd5b5035919050565b60008060408385031215610c0357600080fd5b50508035926020909101359150565b6001600160a01b0381168114610c2757600080fd5b50565b60008060408385031215610c3d57600080fd5b823591506020830135610c4f81610c12565b809150509250929050565b6040516080810167ffffffffffffffff81118282101715610c8b57634e487b7160e01b600052604160045260246000fd5b60405290565b604051610100810167ffffffffffffffff81118282101715610c8b57634e487b7160e01b600052604160045260246000fd5b8051610cce81610c12565b919050565b80516bffffffffffffffffffffffff81168114610cce57600080fd5b805161ffff81168114610cce57600080fd5b600060608284031215610d1357600080fd5b6040516060810181811067ffffffffffffffff82111715610d4457634e487b7160e01b600052604160045260246000fd5b604052905080610d5383610cef565b8152610d6160208401610cef565b6020820152610d7260408401610cef565b60408201525092915050565b60008183036101a0811215610d9257600080fd5b610d9a610c5a565b835160048110610da957600080fd5b81526020840151610db981610c12565b6020820152610100603f198301811315610dd257600080fd5b610dda610c91565b925060408501518352606085015160208401526080850151610dfb81610c12565b6040840152610e0c60a08601610cd3565b606084015260c08501516080840152610e2760e08601610cc3565b60a0840152610e37818601610cd3565b60c08401525061012084015160e0830152816040820152610e5c856101408601610d01565b6060820152949350505050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215610e9157600080fd5b8151610e9c81610c12565b9392505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561067557610675610ea3565b808202811582820484141761067557610675610ea3565b600082610f0057634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215610f1857600080fd5b8251610f2381610c12565b6020939093015192949293505050565b6020810160048310610f5557634e487b7160e01b600052602160045260246000fd5b91905290565b600060208284031215610f6d57600080fd5b61067282610cef565b8181038181111561067557610675610ea356fea164736f6c6343000812000a00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af000000000000000000000000f764442856eb3fe68a0828e07246a4b395e800fa

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100f55760003560e01c8063a7146e7111610097578063cfa498a311610066578063cfa498a31461023f578063db0a23c114610248578063ddb220ec1461026f578063ededcc411461029657600080fd5b8063a7146e71146101cf578063b8921e26146101f6578063c9498e541461021d578063cc3266e81461023057600080fd5b8063379607f5116100d3578063379607f51461016f57806359c86a11146101825780637eb094981461019557806384d2b81c146101bc57600080fd5b8063227e8f0c146100fa57806333f6b51c14610133578063371fd8e61461015a575b600080fd5b6101217f6b9fec8a90acd71b357b3fbde8e525c5e0a0ffebe7010905e79162a4fd6421bd81565b60405190815260200160405180910390f35b6101217fddfa60b1f3b0c3629357d48d7f8a1186bd1ff199faa6c6b792597e91bd705dc281565b61016d610168366004610bd7565b6102bd565b005b61016d61017d366004610bd7565b610362565b61016d610190366004610bd7565b6105d6565b6101217f4e2344e60c4b990f3c4cf2efa216c71144a011f9e4a940c6b459a8066c98e1f981565b6101216101ca366004610bf0565b610648565b6101217f41f539feb01b3a702d5e8c2e4367fa0d5a544df6b5ef24765c6836e0743db74281565b6101217f74ba47f4e32f0deada0ece4f758dd1cb5f98ba44c024c037a61f34bb066f568e81565b61016d61022b366004610c2a565b61067b565b610121670de0b6b3a764000081565b61012161271081565b6101217f6c9950464c33f914161b87af80469f5598c7ea5009d7b4464f7e3815112686a381565b6101217fc3a599955a4238a21ad67957aa12a28dc3e88efd2a54bc264ba15e23b257c35281565b6101217f4714fd9784ca8c9ee16df7000f2eb0fc7a2296e457de6968bc65d71fd287370681565b6000806102c983610a31565b6040516304f3841960e21b815260048101869052336024820152604481018390526064810182905291935091507f00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af6001600160a01b0316906313ce1064906084015b600060405180830381600087803b15801561034557600080fd5b505af1158015610359573d6000803e3d6000fd5b50505050505050565b604051632820036560e11b8152600481018290526000907f00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af6001600160a01b03169063504006ca906024016101a060405180830381865afa1580156103cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ef9190610d7e565b905060008151600381111561040657610406610e69565b0361042c57604051630fd8a76760e01b8152600481018390526024015b60405180910390fd5b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000092ed78b41537c902ad287608d8535bb6780a76186001600160a01b031690636352211e90602401602060405180830381865afa158015610494573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b89190610e7f565b90506001600160a01b03811633146104f457604051636b9e14ff60e01b81526001600160a01b0382166004820152336024820152604401610423565b60408201516020810151815160009161050c91610648565b905060008183602001516105209190610eb9565b9050600061271086606001516000015161ffff168361053f9190610ecc565b6105499190610ee3565b60405163c349026360e01b815260048101899052602481018290529091507f00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af6001600160a01b03169063c349026390604401600060405180830381600087803b1580156105b557600080fd5b505af11580156105c9573d6000803e3d6000fd5b5050505050505050505050565b6000806105e283610a31565b60405163bb340b5d60e01b815260048101869052336024820152604481018390526064810182905291935091507f00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af6001600160a01b03169063bb340b5d9060840161032b565b600061065e612710670de0b6b3a7640000610ecc565b6106688385610ecc565b6106729190610ee3565b90505b92915050565b6001600160a01b0381166106b75760405163302c848b60e01b8152602060048201526002602482015261746f60f01b6044820152606401610423565b604051632820036560e11b8152600481018390526000907f00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af6001600160a01b03169063504006ca906024016101a060405180830381865afa158015610720573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107449190610d7e565b6040516385b2f18360e01b8152600481018590529091506000906001600160a01b037f00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af16906385b2f183906024016040805180830381865afa1580156107ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107d29190610f05565b915060029050825160038111156107eb576107eb610e69565b1461080c578151604051631b250a6b60e11b81526104239190600401610f33565b6040516331a9108f60e11b8152600481018590526000907f00000000000000000000000092ed78b41537c902ad287608d8535bb6780a76186001600160a01b031690636352211e90602401602060405180830381865afa158015610874573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108989190610e7f565b90506001600160a01b03811633146108d457604051636b9e14ff60e01b81526001600160a01b0382166004820152336024820152604401610423565b60405163aee758e760e01b81527f4714fd9784ca8c9ee16df7000f2eb0fc7a2296e457de6968bc65d71fd28737066004820152600090612710906001600160a01b037f000000000000000000000000f764442856eb3fe68a0828e07246a4b395e800fa169063aee758e790602401602060405180830381865afa15801561095f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109839190610f5b565b6109919061ffff1685610ecc565b61099b9190610ee3565b60405163a443a63560e01b815260048101889052602481018290526001600160a01b0387811660448301529192507f00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af9091169063a443a63590606401600060405180830381600087803b158015610a1157600080fd5b505af1158015610a25573d6000803e3d6000fd5b50505050505050505050565b60008060007f00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af6001600160a01b031663504006ca856040518263ffffffff1660e01b8152600401610a8491815260200190565b6101a060405180830381865afa158015610aa2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac69190610d7e565b9050600081516003811115610add57610add610e69565b03610afe57604051630fd8a76760e01b815260048101859052602401610423565b600181516003811115610b1357610b13610e69565b14610b34578051604051631b250a6b60e11b81526104239190600401610f33565b604081015160208101518151600091610b4c91610648565b9050600061271084606001516020015161ffff1683610b6b9190610ecc565b610b759190610ee3565b9050600061271085606001516040015161ffff168560200151610b989190610ecc565b610ba29190610ee3565b9050828460200151610bb49190610eb9565b965080610bc18389610f76565b610bcb9190610f76565b95505050505050915091565b600060208284031215610be957600080fd5b5035919050565b60008060408385031215610c0357600080fd5b50508035926020909101359150565b6001600160a01b0381168114610c2757600080fd5b50565b60008060408385031215610c3d57600080fd5b823591506020830135610c4f81610c12565b809150509250929050565b6040516080810167ffffffffffffffff81118282101715610c8b57634e487b7160e01b600052604160045260246000fd5b60405290565b604051610100810167ffffffffffffffff81118282101715610c8b57634e487b7160e01b600052604160045260246000fd5b8051610cce81610c12565b919050565b80516bffffffffffffffffffffffff81168114610cce57600080fd5b805161ffff81168114610cce57600080fd5b600060608284031215610d1357600080fd5b6040516060810181811067ffffffffffffffff82111715610d4457634e487b7160e01b600052604160045260246000fd5b604052905080610d5383610cef565b8152610d6160208401610cef565b6020820152610d7260408401610cef565b60408201525092915050565b60008183036101a0811215610d9257600080fd5b610d9a610c5a565b835160048110610da957600080fd5b81526020840151610db981610c12565b6020820152610100603f198301811315610dd257600080fd5b610dda610c91565b925060408501518352606085015160208401526080850151610dfb81610c12565b6040840152610e0c60a08601610cd3565b606084015260c08501516080840152610e2760e08601610cc3565b60a0840152610e37818601610cd3565b60c08401525061012084015160e0830152816040820152610e5c856101408601610d01565b6060820152949350505050565b634e487b7160e01b600052602160045260246000fd5b600060208284031215610e9157600080fd5b8151610e9c81610c12565b9392505050565b634e487b7160e01b600052601160045260246000fd5b8082018082111561067557610675610ea3565b808202811582820484141761067557610675610ea3565b600082610f0057634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215610f1857600080fd5b8251610f2381610c12565b6020939093015192949293505050565b6020810160048310610f5557634e487b7160e01b600052602160045260246000fd5b91905290565b600060208284031215610f6d57600080fd5b61067282610cef565b8181038181111561067557610675610ea356fea164736f6c6343000812000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af000000000000000000000000f764442856eb3fe68a0828e07246a4b395e800fa

-----Decoded View---------------
Arg [0] : _loanCore (address): 0x89bc08BA00f135d608bc335f6B33D7a9ABCC98aF
Arg [1] : _feeController (address): 0xf764442856Eb3fe68A0828e07246a4B395e800fa

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000089bc08ba00f135d608bc335f6b33d7a9abcc98af
Arg [1] : 000000000000000000000000f764442856eb3fe68a0828e07246a4b395e800fa


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.