Description:
Decentralized Finance (DeFi) protocol contract providing Non-Fungible, Factory functionality.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// 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);
}
"
},
"@openzeppelin/contracts/token/ERC721/IERC721.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
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`.
*
* 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;
/**
* @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 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: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* 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 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 the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @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);
}
"
},
"@openzeppelin/contracts/utils/introspection/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
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);
}
"
},
"contracts/refinancing/refinancingAdapters/arcade/IArcadeLoanCore.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title IArcadeLoanCore
* @author
* @dev
*/
interface IArcadeLoanCore {
/**
* @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 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;
}
function borrowerNote() external view returns (address);
function getLoan(uint256 loanId) external view returns (LoanData memory loanData);
}
"
},
"contracts/refinancing/refinancingAdapters/arcade/InterestCalculator.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @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);
}
}
"
},
"contracts/refinancing/refinancingAdapters/arcade/IRepaymentController.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
/**
* @title IRepaymentController
* @author
* @dev
*/
interface IRepaymentController {
function repay(uint256 loanId) external;
}
"
},
"contracts/refinancing/refinancingAdapters/ArcadeRefinancingAdapter.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
import {IRefinancingAdapter} from "./IRefinancingAdapter.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IArcadeLoanCore} from "./arcade/IArcadeLoanCore.sol";
import {IRepaymentController} from "./arcade/IRepaymentController.sol";
import {InterestCalculator} from "./arcade/InterestCalculator.sol";
/**
* @title ArcadeRefinancingAdapter
* @author NFTfi
* @dev This contract is an implementation of the IRefinancingAdapter for the Arcade platform.
* It handles operations related to refinancing Arcade loans such as transferring the borrower role,
* paying off loans, and retrieving loan and collateral details.
*/
contract ArcadeRefinancingAdapter is IRefinancingAdapter, InterestCalculator {
address public constant repaymentController = 0x74241e1A9c021643289476426B9B70229Ab40D53;
error transferBorrowerRoleFailed();
/**
* @dev Gets the address of the borrower for a specific Arcade loan.
* @param _loanContract The address of the contract containing the Arcade loan.
* @param _loanIdentifier The unique identifier for the Arcade loan.
* @return The address of the borrower.
*/
function getBorrowerAddress(
address _loanContract,
uint256 _loanIdentifier,
bytes calldata
) external view override returns (address) {
return IERC721(IArcadeLoanCore(_loanContract).borrowerNote()).ownerOf(_loanIdentifier);
}
/**
* @dev Transfers the borrower role to this contract for a specific Arcade loan.
* @param _loanContract The address of the contract containing the Arcade loan.
* @param _loanIdentifier The unique identifier for the Arcade loan.
* @return A boolean value indicating whether the operation was successful.
*/
function transferBorrowerRole(
address _loanContract,
uint256 _loanIdentifier,
bytes calldata
) external override returns (bool) {
IERC721 borrowerNote = IERC721(IArcadeLoanCore(_loanContract).borrowerNote());
address borrower = borrowerNote.ownerOf(_loanIdentifier);
borrowerNote.transferFrom(borrower, address(this), _loanIdentifier);
if (borrowerNote.ownerOf(_loanIdentifier) != address(this)) revert transferBorrowerRoleFailed();
return (true);
}
/**
* @dev Pays off an Arcade loan with a specified amount of a specified token.
* @param _loanContract The address of the contract containing the Arcade loan.
* @param _loanIdentifier The unique identifier for the Arcade loan.
* @param _payBackToken The token used to pay back the Arcade loan.
* @param _payBackAmount The amount of tokens used to pay back the Arcade loan.
* @return A boolean value indicating whether the operation was successful.
*/
function payOffRefinancable(
address _loanContract,
uint256 _loanIdentifier,
address _payBackToken,
uint256 _payBackAmount,
bytes calldata
) external override returns (bool) {
IERC20(_payBackToken).approve(_loanContract, _payBackAmount);
IRepaymentController(repaymentController).repay(_loanIdentifier);
return (true);
}
/**
* @dev Gets the collateral information for a specific Arcade loan.
* @param _loanContract The address of the contract containing the Arcade loan.
* @param _loanIdentifier The unique identifier for the Arcade loan.
* @return nftCollateralContract nftCollateralId
* The address of the collateral token contract and the ID of the collateral.
*/
function getCollateral(
address _loanContract,
uint256 _loanIdentifier,
bytes calldata
) external view override returns (address, uint256) {
// get loan data
IArcadeLoanCore.LoanData memory data = IArcadeLoanCore(_loanContract).getLoan(_loanIdentifier);
return (data.terms.collateralAddress, data.terms.collateralId);
}
/**
* @dev Retrieves the loan coordinator from a specific Arcade loan contract.
* @param _loanContract The address of the contract containing the Arcade loan.
* @return The loan coordinator contract.
*/
/**
* @dev Gets the collateral information for a specific Arcade loan.
* @param _loanContract The address of the contract containing the Arcade loan.
* @param _loanIdentifier The unique identifier for the Arcade loan.
* @return loanERC20Denomination maximumRepaymentAmount
* The address of the payoff token and the required payoff amount.
*/
function getPayoffDetails(
address _loanContract,
uint256 _loanIdentifier,
bytes calldata
) external view override returns (address, uint256) {
// get loan data
IArcadeLoanCore.LoanData memory data = IArcadeLoanCore(_loanContract).getLoan(_loanIdentifier);
// get interest amount due
uint256 interestAmount = getInterestAmount(data.terms.principal, data.terms.proratedInterestRate);
uint256 payOffAmount = interestAmount + data.terms.principal;
return (data.terms.payableCurrency, payOffAmount);
}
}
"
},
"contracts/refinancing/refinancingAdapters/IRefinancingAdapter.sol": {
"content": "// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;
/**
* @title IRefinancingAdapter
* @author NFTfi
*
* @dev This is the interface for Refinancing Adapters. It provides several methods for managing and retrieving
* information about contracts that are eligible for refinancing.
*
* Adapters should implement this interface
*/
interface IRefinancingAdapter {
/**
* @dev Returns the borrower's address for a specific refinancable
*
* @param _refinanceableContract Address of the contract containing the refinanceable
* @param _refinancableIdentifier Unique identifier for the refinanceable.
*
* @return Address of the borrower.
*/
function getBorrowerAddress(
address _refinanceableContract,
uint256 _refinancableIdentifier,
bytes memory _extraData
) external returns (address);
/**
* @dev Transfers the role of borrower to refinancing contract for a specific refinanceable.
*
* @param _refinanceableContract Address of the contract containing the refinanceable
* @param _refinancableIdentifier Unique identifier for the loan.
*
* @return True if the operation was successful.
*/
function transferBorrowerRole(
address _refinanceableContract,
uint256 _refinancableIdentifier,
bytes memory _extraData
) external returns (bool);
/**
* @dev Pays off a refinanceable with a specified amount of a specified token.
*
* @param _refinanceableContract Address of the contract containing the refinanceable
* @param _refinancableIdentifier Unique identifier for the refinanceable.
* @param _payBackToken Token used to pay back the refinanceable.
* @param _payBackAmount Amount of tokens used to pay back the refinanceable.
*
* @return True if the operation was successful.
*/
function payOffRefinancable(
address _refinanceableContract,
uint256 _refinancableIdentifier,
address _payBackToken,
uint256 _payBackAmount,
bytes memory _extraData
) external returns (bool);
/**
* @dev Returns the collateral information for a specific refinancable.
*
* @param _refinanceableContract Address of the contract containing the refinanceable
* @param _refinancableIdentifier Unique identifier for the refinanceable.
*
* @return The address of the collateral token and the amount of collateral.
*/
function getCollateral(
address _refinanceableContract,
uint256 _refinancableIdentifier,
bytes memory _extraData
) external view returns (address, uint256);
/**
* @dev Returns the payoff details for a specific refinancable.
*
* @param _refinanceableContract Address of the contract containing the refinanceable
* @param _refinancableIdentifier Unique identifier for the loan.
*
* @return The address of the payoff token and the required payoff amount.
*/
function getPayoffDetails(
address _refinanceableContract,
uint256 _refinancableIdentifier,
bytes memory _extraData
) external view returns (address, uint256);
}
"
}
},
"settings": {
"metadata": {
"bytecodeHash": "none",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 900
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}
}}
Submitted on: 2025-10-03 15:02:13
Comments
Log in to comment.
No comments yet.