Contract Name:
PunkGateway
Contract Source Code:
<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {ERC721HolderUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol";
import {ILendPool} from "../interfaces/ILendPool.sol";
import {ILendPoolLoan} from "../interfaces/ILendPoolLoan.sol";
import {ILendPoolAddressesProvider} from "../interfaces/ILendPoolAddressesProvider.sol";
import {IPunks} from "../interfaces/IPunks.sol";
import {IWrappedPunks} from "../interfaces/IWrappedPunks.sol";
import {IPunkGateway} from "../interfaces/IPunkGateway.sol";
import {DataTypes} from "../libraries/types/DataTypes.sol";
import {IWETHGateway} from "../interfaces/IWETHGateway.sol";
import {EmergencyTokenRecoveryUpgradeable} from "./EmergencyTokenRecoveryUpgradeable.sol";
contract PunkGateway is IPunkGateway, ERC721HolderUpgradeable, EmergencyTokenRecoveryUpgradeable {
using SafeERC20Upgradeable for IERC20Upgradeable;
ILendPoolAddressesProvider internal _addressProvider;
IWETHGateway internal _wethGateway;
IPunks public punks;
IWrappedPunks public wrappedPunks;
address public proxy;
function initialize(
address addressProvider,
address wethGateway,
address _punks,
address _wrappedPunks
) public initializer {
__ERC721Holder_init();
__EmergencyTokenRecovery_init();
_addressProvider = ILendPoolAddressesProvider(addressProvider);
_wethGateway = IWETHGateway(wethGateway);
punks = IPunks(_punks);
wrappedPunks = IWrappedPunks(_wrappedPunks);
wrappedPunks.registerProxy();
proxy = wrappedPunks.proxyInfo(address(this));
IERC721Upgradeable(address(wrappedPunks)).setApprovalForAll(address(_getLendPool()), true);
IERC721Upgradeable(address(wrappedPunks)).setApprovalForAll(address(_wethGateway), true);
}
function _getLendPool() internal view returns (ILendPool) {
return ILendPool(_addressProvider.getLendPool());
}
function _getLendPoolLoan() internal view returns (ILendPoolLoan) {
return ILendPoolLoan(_addressProvider.getLendPoolLoan());
}
function authorizeLendPoolERC20(address[] calldata tokens) external onlyOwner {
for (uint256 i = 0; i < tokens.length; i++) {
IERC20Upgradeable(tokens[i]).approve(address(_getLendPool()), type(uint256).max);
}
}
function _depositPunk(uint256 punkIndex) internal {
ILendPoolLoan cachedPoolLoan = _getLendPoolLoan();
uint256 loanId = cachedPoolLoan.getCollateralLoanId(address(wrappedPunks), punkIndex);
if (loanId != 0) {
return;
}
address owner = punks.punkIndexToAddress(punkIndex);
require(owner == _msgSender(), "PunkGateway: not owner of punkIndex");
punks.buyPunk(punkIndex);
punks.transferPunk(proxy, punkIndex);
wrappedPunks.mint(punkIndex);
}
function borrow(
address reserveAsset,
uint256 amount,
uint256 punkIndex,
address onBehalfOf,
uint16 referralCode
) external override {
ILendPool cachedPool = _getLendPool();
_depositPunk(punkIndex);
cachedPool.borrow(reserveAsset, amount, address(wrappedPunks), punkIndex, onBehalfOf, referralCode);
IERC20Upgradeable(reserveAsset).transfer(onBehalfOf, amount);
}
function _withdrawPunk(uint256 punkIndex, address onBehalfOf) internal {
address owner = wrappedPunks.ownerOf(punkIndex);
require(owner == _msgSender(), "PunkGateway: caller is not owner");
require(owner == onBehalfOf, "PunkGateway: onBehalfOf is not owner");
wrappedPunks.safeTransferFrom(onBehalfOf, address(this), punkIndex);
wrappedPunks.burn(punkIndex);
punks.transferPunk(onBehalfOf, punkIndex);
}
function repay(uint256 punkIndex, uint256 amount) external override returns (uint256, bool) {
ILendPool cachedPool = _getLendPool();
ILendPoolLoan cachedPoolLoan = _getLendPoolLoan();
uint256 loanId = cachedPoolLoan.getCollateralLoanId(address(wrappedPunks), punkIndex);
require(loanId != 0, "PunkGateway: no loan with such punkIndex");
(, , address reserve, ) = cachedPoolLoan.getLoanCollateralAndReserve(loanId);
(, uint256 debt) = cachedPoolLoan.getLoanReserveBorrowAmount(loanId);
address borrower = cachedPoolLoan.borrowerOf(loanId);
if (amount > debt) {
amount = debt;
}
IERC20Upgradeable(reserve).transferFrom(msg.sender, address(this), amount);
(uint256 paybackAmount, bool burn) = cachedPool.repay(address(wrappedPunks), punkIndex, amount);
if (burn) {
require(borrower == _msgSender(), "PunkGateway: caller is not borrower");
_withdrawPunk(punkIndex, borrower);
}
return (paybackAmount, burn);
}
function auction(
uint256 punkIndex,
uint256 bidPrice,
address onBehalfOf
) external override {
ILendPool cachedPool = _getLendPool();
ILendPoolLoan cachedPoolLoan = _getLendPoolLoan();
uint256 loanId = cachedPoolLoan.getCollateralLoanId(address(wrappedPunks), punkIndex);
require(loanId != 0, "PunkGateway: no loan with such punkIndex");
(, , address reserve, ) = cachedPoolLoan.getLoanCollateralAndReserve(loanId);
IERC20Upgradeable(reserve).transferFrom(msg.sender, address(this), bidPrice);
cachedPool.auction(address(wrappedPunks), punkIndex, bidPrice, onBehalfOf);
}
function redeem(uint256 punkIndex, uint256 amount) external override returns (uint256) {
ILendPool cachedPool = _getLendPool();
ILendPoolLoan cachedPoolLoan = _getLendPoolLoan();
uint256 loanId = cachedPoolLoan.getCollateralLoanId(address(wrappedPunks), punkIndex);
require(loanId != 0, "PunkGateway: no loan with such punkIndex");
DataTypes.LoanData memory loan = cachedPoolLoan.getLoan(loanId);
IERC20Upgradeable(loan.reserveAsset).transferFrom(msg.sender, address(this), amount);
uint256 paybackAmount = cachedPool.redeem(address(wrappedPunks), punkIndex, amount);
if (amount > paybackAmount) {
IERC20Upgradeable(loan.reserveAsset).safeTransfer(msg.sender, (amount - paybackAmount));
}
return paybackAmount;
}
function liquidate(uint256 punkIndex, uint256 amount) external override returns (uint256) {
ILendPool cachedPool = _getLendPool();
ILendPoolLoan cachedPoolLoan = _getLendPoolLoan();
uint256 loanId = cachedPoolLoan.getCollateralLoanId(address(wrappedPunks), punkIndex);
require(loanId != 0, "PunkGateway: no loan with such punkIndex");
DataTypes.LoanData memory loan = cachedPoolLoan.getLoan(loanId);
require(loan.bidderAddress == _msgSender(), "PunkGateway: caller is not bidder");
if (amount > 0) {
IERC20Upgradeable(loan.reserveAsset).transferFrom(msg.sender, address(this), amount);
}
uint256 extraRetAmount = cachedPool.liquidate(address(wrappedPunks), punkIndex, amount);
_withdrawPunk(punkIndex, loan.bidderAddress);
if (amount > extraRetAmount) {
IERC20Upgradeable(loan.reserveAsset).safeTransfer(msg.sender, (amount - extraRetAmount));
}
return (extraRetAmount);
}
function borrowETH(
uint256 amount,
uint256 punkIndex,
address onBehalfOf,
uint16 referralCode
) external override {
_depositPunk(punkIndex);
_wethGateway.borrowETH(amount, address(wrappedPunks), punkIndex, onBehalfOf, referralCode);
}
function repayETH(uint256 punkIndex, uint256 amount) external payable override returns (uint256, bool) {
ILendPoolLoan cachedPoolLoan = _getLendPoolLoan();
uint256 loanId = cachedPoolLoan.getCollateralLoanId(address(wrappedPunks), punkIndex);
require(loanId != 0, "PunkGateway: no loan with such punkIndex");
address borrower = cachedPoolLoan.borrowerOf(loanId);
(uint256 paybackAmount, bool burn) = _wethGateway.repayETH{value: msg.value}(
address(wrappedPunks),
punkIndex,
amount
);
if (burn) {
require(borrower == _msgSender(), "PunkGateway: caller is not borrower");
_withdrawPunk(punkIndex, borrower);
}
// refund remaining dust eth
if (msg.value > paybackAmount) {
_safeTransferETH(msg.sender, msg.value - paybackAmount);
}
return (paybackAmount, burn);
}
function auctionETH(uint256 punkIndex, address onBehalfOf) external payable override {
_wethGateway.auctionETH{value: msg.value}(address(wrappedPunks), punkIndex, onBehalfOf);
}
function redeemETH(uint256 punkIndex, uint256 amount) external payable override returns (uint256) {
ILendPoolLoan cachedPoolLoan = _getLendPoolLoan();
uint256 loanId = cachedPoolLoan.getCollateralLoanId(address(wrappedPunks), punkIndex);
require(loanId != 0, "PunkGateway: no loan with such punkIndex");
//DataTypes.LoanData memory loan = cachedPoolLoan.getLoan(loanId);
uint256 paybackAmount = _wethGateway.redeemETH{value: msg.value}(address(wrappedPunks), punkIndex, amount);
// refund remaining dust eth
if (msg.value > paybackAmount) {
_safeTransferETH(msg.sender, msg.value - paybackAmount);
}
return paybackAmount;
}
function liquidateETH(uint256 punkIndex) external payable override returns (uint256) {
ILendPoolLoan cachedPoolLoan = _getLendPoolLoan();
uint256 loanId = cachedPoolLoan.getCollateralLoanId(address(wrappedPunks), punkIndex);
require(loanId != 0, "PunkGateway: no loan with such punkIndex");
DataTypes.LoanData memory loan = cachedPoolLoan.getLoan(loanId);
require(loan.bidderAddress == _msgSender(), "PunkGateway: caller is not bidder");
uint256 extraAmount = _wethGateway.liquidateETH{value: msg.value}(address(wrappedPunks), punkIndex);
_withdrawPunk(punkIndex, loan.bidderAddress);
// refund remaining dust eth
if (msg.value > extraAmount) {
_safeTransferETH(msg.sender, msg.value - extraAmount);
}
return extraAmount;
}
/**
* @dev transfer ETH to an address, revert if it fails.
* @param to recipient of the transfer
* @param value the amount to send
*/
function _safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, "ETH_TRANSFER_FAILED");
}
/**
* @dev
*/
receive() external payable {}
/**
* @dev Revert fallback calls
*/
fallback() external payable {
revert("Fallback not allowed");
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Context_init_unchained();
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
uint256[49] private __gap;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165Upgradeable.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721Upgradeable is IERC165Upgradeable {
/**
* @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;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @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);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
import "../../../utils/AddressUpgradeable.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 SafeERC20Upgradeable {
using AddressUpgradeable for address;
function safeTransfer(
IERC20Upgradeable token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20Upgradeable 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(
IERC20Upgradeable 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(
IERC20Upgradeable 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(
IERC20Upgradeable 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(IERC20Upgradeable 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");
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol)
pragma solidity ^0.8.0;
import "../IERC721ReceiverUpgradeable.sol";
import "../../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
*/
contract ERC721HolderUpgradeable is Initializable, IERC721ReceiverUpgradeable {
function __ERC721Holder_init() internal onlyInitializing {
__ERC721Holder_init_unchained();
}
function __ERC721Holder_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address,
address,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
uint256[50] private __gap;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
import {ILendPoolAddressesProvider} from "./ILendPoolAddressesProvider.sol";
import {DataTypes} from "../libraries/types/DataTypes.sol";
interface ILendPool {
/**
* @dev Emitted on deposit()
* @param user The address initiating the deposit
* @param amount The amount deposited
* @param reserve The address of the underlying asset of the reserve
* @param onBehalfOf The beneficiary of the deposit, receiving the bTokens
* @param referral The referral code used
**/
event Deposit(
address user,
address indexed reserve,
uint256 amount,
address indexed onBehalfOf,
uint16 indexed referral
);
/**
* @dev Emitted on withdraw()
* @param user The address initiating the withdrawal, owner of bTokens
* @param reserve The address of the underlyng asset being withdrawn
* @param amount The amount to be withdrawn
* @param to Address that will receive the underlying
**/
event Withdraw(address indexed user, address indexed reserve, uint256 amount, address indexed to);
/**
* @dev Emitted on borrow() when loan needs to be opened
* @param user The address of the user initiating the borrow(), receiving the funds
* @param reserve The address of the underlying asset being borrowed
* @param amount The amount borrowed out
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token id of the underlying NFT used as collateral
* @param onBehalfOf The address that will be getting the loan
* @param referral The referral code used
**/
event Borrow(
address user,
address indexed reserve,
uint256 amount,
address nftAsset,
uint256 nftTokenId,
address indexed onBehalfOf,
uint256 borrowRate,
uint256 loanId,
uint16 indexed referral
);
/**
* @dev Emitted on repay()
* @param user The address of the user initiating the repay(), providing the funds
* @param reserve The address of the underlying asset of the reserve
* @param amount The amount repaid
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token id of the underlying NFT used as collateral
* @param borrower The beneficiary of the repayment, getting his debt reduced
* @param loanId The loan ID of the NFT loans
**/
event Repay(
address user,
address indexed reserve,
uint256 amount,
address indexed nftAsset,
uint256 nftTokenId,
address indexed borrower,
uint256 loanId
);
/**
* @dev Emitted when a borrower's loan is auctioned.
* @param user The address of the user initiating the auction
* @param reserve The address of the underlying asset of the reserve
* @param bidPrice The price of the underlying reserve given by the bidder
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token id of the underlying NFT used as collateral
* @param onBehalfOf The address that will be getting the NFT
* @param loanId The loan ID of the NFT loans
**/
event Auction(
address user,
address indexed reserve,
uint256 bidPrice,
address indexed nftAsset,
uint256 nftTokenId,
address onBehalfOf,
address indexed borrower,
uint256 loanId
);
/**
* @dev Emitted on redeem()
* @param user The address of the user initiating the redeem(), providing the funds
* @param reserve The address of the underlying asset of the reserve
* @param borrowAmount The borrow amount repaid
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token id of the underlying NFT used as collateral
* @param loanId The loan ID of the NFT loans
**/
event Redeem(
address user,
address indexed reserve,
uint256 borrowAmount,
uint256 fineAmount,
address indexed nftAsset,
uint256 nftTokenId,
address indexed borrower,
uint256 loanId
);
/**
* @dev Emitted when a borrower's loan is liquidated.
* @param user The address of the user initiating the auction
* @param reserve The address of the underlying asset of the reserve
* @param repayAmount The amount of reserve repaid by the liquidator
* @param remainAmount The amount of reserve received by the borrower
* @param loanId The loan ID of the NFT loans
**/
event Liquidate(
address user,
address indexed reserve,
uint256 repayAmount,
uint256 remainAmount,
address indexed nftAsset,
uint256 nftTokenId,
address indexed borrower,
uint256 loanId
);
/**
* @dev Emitted when the pause is triggered.
*/
event Paused();
/**
* @dev Emitted when the pause is lifted.
*/
event Unpaused();
/**
* @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared
* in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal,
* the event will actually be fired by the LendPool contract. The event is therefore replicated here so it
* gets added to the LendPool ABI
* @param reserve The address of the underlying asset of the reserve
* @param liquidityRate The new liquidity rate
* @param variableBorrowRate The new variable borrow rate
* @param liquidityIndex The new liquidity index
* @param variableBorrowIndex The new variable borrow index
**/
event ReserveDataUpdated(
address indexed reserve,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
/**
* @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying bTokens.
* - E.g. User deposits 100 USDC and gets in return 100 bUSDC
* @param reserve The address of the underlying asset to deposit
* @param amount The amount to be deposited
* @param onBehalfOf The address that will receive the bTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of bTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function deposit(
address reserve,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent bTokens owned
* E.g. User has 100 bUSDC, calls withdraw() and receives 100 USDC, burning the 100 bUSDC
* @param reserve The address of the underlying asset to withdraw
* @param amount The underlying amount to be withdrawn
* - Send the value type(uint256).max in order to withdraw the whole bToken balance
* @param to Address that will receive the underlying, same as msg.sender if the user
* wants to receive it on his own wallet, or a different address if the beneficiary is a
* different wallet
* @return The final amount withdrawn
**/
function withdraw(
address reserve,
uint256 amount,
address to
) external returns (uint256);
/**
* @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
* already deposited enough collateral
* - E.g. User borrows 100 USDC, receiving the 100 USDC in his wallet
* and lock collateral asset in contract
* @param reserveAsset The address of the underlying asset to borrow
* @param amount The amount to be borrowed
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token ID of the underlying NFT used as collateral
* @param onBehalfOf Address of the user who will receive the loan. Should be the address of the borrower itself
* calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
* if he has been given credit delegation allowance
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function borrow(
address reserveAsset,
uint256 amount,
address nftAsset,
uint256 nftTokenId,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent loan owned
* - E.g. User repays 100 USDC, burning loan and receives collateral asset
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token ID of the underlying NFT used as collateral
* @param amount The amount to repay
* @return The final amount repaid, loan is burned or not
**/
function repay(
address nftAsset,
uint256 nftTokenId,
uint256 amount
) external returns (uint256, bool);
/**
* @dev Function to auction a non-healthy position collateral-wise
* - The caller (liquidator) want to buy collateral asset of the user getting liquidated
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token ID of the underlying NFT used as collateral
* @param bidPrice The bid price of the liquidator want to buy the underlying NFT
* @param onBehalfOf Address of the user who will get the underlying NFT, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of NFT
* is a different wallet
**/
function auction(
address nftAsset,
uint256 nftTokenId,
uint256 bidPrice,
address onBehalfOf
) external;
/**
* @notice Redeem a NFT loan which state is in Auction
* - E.g. User repays 100 USDC, burning loan and receives collateral asset
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token ID of the underlying NFT used as collateral
* @param amount The amount to repay the debt and bid fine
**/
function redeem(
address nftAsset,
uint256 nftTokenId,
uint256 amount
) external returns (uint256);
/**
* @dev Function to liquidate a non-healthy position collateral-wise
* - The caller (liquidator) buy collateral asset of the user getting liquidated, and receives
* the collateral asset
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token ID of the underlying NFT used as collateral
**/
function liquidate(
address nftAsset,
uint256 nftTokenId,
uint256 amount
) external returns (uint256);
/**
* @dev Validates and finalizes an bToken transfer
* - Only callable by the overlying bToken of the `asset`
* @param asset The address of the underlying asset of the bToken
* @param from The user from which the bTokens are transferred
* @param to The user receiving the bTokens
* @param amount The amount being transferred/withdrawn
* @param balanceFromBefore The bToken balance of the `from` user before the transfer
* @param balanceToBefore The bToken balance of the `to` user before the transfer
*/
function finalizeTransfer(
address asset,
address from,
address to,
uint256 amount,
uint256 balanceFromBefore,
uint256 balanceToBefore
) external view;
function getReserveConfiguration(address asset) external view returns (DataTypes.ReserveConfigurationMap memory);
function getNftConfiguration(address asset) external view returns (DataTypes.NftConfigurationMap memory);
/**
* @dev Returns the normalized income normalized income of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The reserve's normalized income
*/
function getReserveNormalizedIncome(address asset) external view returns (uint256);
/**
* @dev Returns the normalized variable debt per unit of asset
* @param asset The address of the underlying asset of the reserve
* @return The reserve normalized variable debt
*/
function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);
/**
* @dev Returns the state and configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The state of the reserve
**/
function getReserveData(address asset) external view returns (DataTypes.ReserveData memory);
function getReservesList() external view returns (address[] memory);
function getNftData(address asset) external view returns (DataTypes.NftData memory);
/**
* @dev Returns the loan data of the NFT
* @param nftAsset The address of the NFT
* @param reserveAsset The address of the Reserve
* @return totalCollateralInETH the total collateral in ETH of the NFT
* @return totalCollateralInReserve the total collateral in Reserve of the NFT
* @return availableBorrowsInETH the borrowing power in ETH of the NFT
* @return availableBorrowsInReserve the borrowing power in Reserve of the NFT
* @return ltv the loan to value of the user
* @return liquidationThreshold the liquidation threshold of the NFT
* @return liquidationBonus the liquidation bonus of the NFT
**/
function getNftCollateralData(address nftAsset, address reserveAsset)
external
view
returns (
uint256 totalCollateralInETH,
uint256 totalCollateralInReserve,
uint256 availableBorrowsInETH,
uint256 availableBorrowsInReserve,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus
);
/**
* @dev Returns the debt data of the NFT
* @param nftAsset The address of the NFT
* @param nftTokenId The token id of the NFT
* @return loanId the loan id of the NFT
* @return reserveAsset the address of the Reserve
* @return totalCollateral the total power of the NFT
* @return totalDebt the total debt of the NFT
* @return availableBorrows the borrowing power left of the NFT
* @return healthFactor the current health factor of the NFT
**/
function getNftDebtData(address nftAsset, uint256 nftTokenId)
external
view
returns (
uint256 loanId,
address reserveAsset,
uint256 totalCollateral,
uint256 totalDebt,
uint256 availableBorrows,
uint256 healthFactor
);
/**
* @dev Returns the auction data of the NFT
* @param nftAsset The address of the NFT
* @param nftTokenId The token id of the NFT
* @return loanId the loan id of the NFT
* @return bidderAddress the highest bidder address of the loan
* @return bidPrice the highest bid price in Reserve of the loan
* @return bidBorrowAmount the borrow amount in Reserve of the loan
* @return bidFine the penalty fine of the loan
**/
function getNftAuctionData(address nftAsset, uint256 nftTokenId)
external
view
returns (
uint256 loanId,
address bidderAddress,
uint256 bidPrice,
uint256 bidBorrowAmount,
uint256 bidFine
);
function getNftLiquidatePrice(address nftAsset, uint256 nftTokenId)
external
view
returns (uint256 liquidatePrice, uint256 paybackAmount);
function getNftsList() external view returns (address[] memory);
/**
* @dev Set the _pause state of a reserve
* - Only callable by the LendPool contract
* @param val `true` to pause the reserve, `false` to un-pause it
*/
function setPause(bool val) external;
/**
* @dev Returns if the LendPool is paused
*/
function paused() external view returns (bool);
function getAddressesProvider() external view returns (ILendPoolAddressesProvider);
function initReserve(
address asset,
address bTokenAddress,
address debtTokenAddress,
address interestRateAddress
) external;
function initNft(address asset, address bNftAddress) external;
function setReserveInterestRateAddress(address asset, address rateAddress) external;
function setReserveConfiguration(address asset, uint256 configuration) external;
function setNftConfiguration(address asset, uint256 configuration) external;
function setMaxNumberOfReserves(uint256 val) external;
function setMaxNumberOfNfts(uint256 val) external;
function getMaxNumberOfReserves() external view returns (uint256);
function getMaxNumberOfNfts() external view returns (uint256);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
import {DataTypes} from "../libraries/types/DataTypes.sol";
interface ILendPoolLoan {
/**
* @dev Emitted on initialization to share location of dependent notes
* @param pool The address of the associated lend pool
*/
event Initialized(address indexed pool);
/**
* @dev Emitted when a loan is created
* @param user The address initiating the action
*/
event LoanCreated(
address indexed user,
address indexed onBehalfOf,
uint256 indexed loanId,
address nftAsset,
uint256 nftTokenId,
address reserveAsset,
uint256 amount,
uint256 borrowIndex
);
/**
* @dev Emitted when a loan is updated
* @param user The address initiating the action
*/
event LoanUpdated(
address indexed user,
uint256 indexed loanId,
address nftAsset,
uint256 nftTokenId,
address reserveAsset,
uint256 amountAdded,
uint256 amountTaken,
uint256 borrowIndex
);
/**
* @dev Emitted when a loan is repaid by the borrower
* @param user The address initiating the action
*/
event LoanRepaid(
address indexed user,
uint256 indexed loanId,
address nftAsset,
uint256 nftTokenId,
address reserveAsset,
uint256 amount,
uint256 borrowIndex
);
/**
* @dev Emitted when a loan is auction by the liquidator
* @param user The address initiating the action
*/
event LoanAuctioned(
address indexed user,
uint256 indexed loanId,
address nftAsset,
uint256 nftTokenId,
uint256 amount,
uint256 borrowIndex,
address bidder,
uint256 price,
address previousBidder,
uint256 previousPrice
);
/**
* @dev Emitted when a loan is redeemed
* @param user The address initiating the action
*/
event LoanRedeemed(
address indexed user,
uint256 indexed loanId,
address nftAsset,
uint256 nftTokenId,
address reserveAsset,
uint256 amountTaken,
uint256 borrowIndex
);
/**
* @dev Emitted when a loan is liquidate by the liquidator
* @param user The address initiating the action
*/
event LoanLiquidated(
address indexed user,
uint256 indexed loanId,
address nftAsset,
uint256 nftTokenId,
address reserveAsset,
uint256 amount,
uint256 borrowIndex
);
function initNft(address nftAsset, address bNftAddress) external;
/**
* @dev Create store a loan object with some params
* @param initiator The address of the user initiating the borrow
* @param onBehalfOf The address receiving the loan
*/
function createLoan(
address initiator,
address onBehalfOf,
address nftAsset,
uint256 nftTokenId,
address bNftAddress,
address reserveAsset,
uint256 amount,
uint256 borrowIndex
) external returns (uint256);
/**
* @dev Update the given loan with some params
*
* Requirements:
* - The caller must be a holder of the loan
* - The loan must be in state Active
* @param initiator The address of the user initiating the borrow
*/
function updateLoan(
address initiator,
uint256 loanId,
uint256 amountAdded,
uint256 amountTaken,
uint256 borrowIndex
) external;
/**
* @dev Repay the given loan
*
* Requirements:
* - The caller must be a holder of the loan
* - The caller must send in principal + interest
* - The loan must be in state Active
*
* @param initiator The address of the user initiating the repay
* @param loanId The loan getting burned
* @param bNftAddress The address of bNFT
*/
function repayLoan(
address initiator,
uint256 loanId,
address bNftAddress,
uint256 amount,
uint256 borrowIndex
) external;
/**
* @dev Auction the given loan
*
* Requirements:
* - The price must be greater than current highest price
* - The loan must be in state Active or Auction
*
* @param initiator The address of the user initiating the auction
* @param loanId The loan getting auctioned
* @param bidPrice The bid price of this auction
*/
function auctionLoan(
address initiator,
uint256 loanId,
address onBehalfOf,
uint256 bidPrice,
uint256 borrowAmount,
uint256 borrowIndex
) external;
/**
* @dev Redeem the given loan with some params
*
* Requirements:
* - The caller must be a holder of the loan
* - The loan must be in state Auction
* @param initiator The address of the user initiating the borrow
*/
function redeemLoan(
address initiator,
uint256 loanId,
uint256 amountTaken,
uint256 borrowIndex
) external;
/**
* @dev Liquidate the given loan
*
* Requirements:
* - The caller must send in principal + interest
* - The loan must be in state Active
*
* @param initiator The address of the user initiating the auction
* @param loanId The loan getting burned
* @param bNftAddress The address of bNFT
*/
function liquidateLoan(
address initiator,
uint256 loanId,
address bNftAddress,
uint256 borrowAmount,
uint256 borrowIndex
) external;
function borrowerOf(uint256 loanId) external view returns (address);
function getCollateralLoanId(address nftAsset, uint256 nftTokenId) external view returns (uint256);
function getLoan(uint256 loanId) external view returns (DataTypes.LoanData memory loanData);
function getLoanCollateralAndReserve(uint256 loanId)
external
view
returns (
address nftAsset,
uint256 nftTokenId,
address reserveAsset,
uint256 scaledAmount
);
function getLoanReserveBorrowScaledAmount(uint256 loanId) external view returns (address, uint256);
function getLoanReserveBorrowAmount(uint256 loanId) external view returns (address, uint256);
function getLoanHighestBid(uint256 loanId) external view returns (address, uint256);
function getNftCollateralAmount(address nftAsset) external view returns (uint256);
function getUserNftCollateralAmount(address user, address nftAsset) external view returns (uint256);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
/**
* @title LendPoolAddressesProvider contract
* @dev Main registry of addresses part of or connected to the protocol, including permissioned roles
* - Acting also as factory of proxies and admin of those, so with right to change its implementations
* - Owned by the Bend Governance
* @author Bend
**/
interface ILendPoolAddressesProvider {
event MarketIdSet(string newMarketId);
event LendPoolUpdated(address indexed newAddress, bytes encodedCallData);
event ConfigurationAdminUpdated(address indexed newAddress);
event EmergencyAdminUpdated(address indexed newAddress);
event LendPoolConfiguratorUpdated(address indexed newAddress, bytes encodedCallData);
event ReserveOracleUpdated(address indexed newAddress);
event NftOracleUpdated(address indexed newAddress);
event LendPoolLoanUpdated(address indexed newAddress, bytes encodedCallData);
event ProxyCreated(bytes32 id, address indexed newAddress);
event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy, bytes encodedCallData);
event BNFTRegistryUpdated(address indexed newAddress);
event LendPoolLiquidatorUpdated(address indexed newAddress);
event IncentivesControllerUpdated(address indexed newAddress);
event UIDataProviderUpdated(address indexed newAddress);
event BendDataProviderUpdated(address indexed newAddress);
event WalletBalanceProviderUpdated(address indexed newAddress);
function getMarketId() external view returns (string memory);
function setMarketId(string calldata marketId) external;
function setAddress(bytes32 id, address newAddress) external;
function setAddressAsProxy(
bytes32 id,
address impl,
bytes memory encodedCallData
) external;
function getAddress(bytes32 id) external view returns (address);
function getLendPool() external view returns (address);
function setLendPoolImpl(address pool, bytes memory encodedCallData) external;
function getLendPoolConfigurator() external view returns (address);
function setLendPoolConfiguratorImpl(address configurator, bytes memory encodedCallData) external;
function getPoolAdmin() external view returns (address);
function setPoolAdmin(address admin) external;
function getEmergencyAdmin() external view returns (address);
function setEmergencyAdmin(address admin) external;
function getReserveOracle() external view returns (address);
function setReserveOracle(address reserveOracle) external;
function getNFTOracle() external view returns (address);
function setNFTOracle(address nftOracle) external;
function getLendPoolLoan() external view returns (address);
function setLendPoolLoanImpl(address loan, bytes memory encodedCallData) external;
function getBNFTRegistry() external view returns (address);
function setBNFTRegistry(address factory) external;
function getLendPoolLiquidator() external view returns (address);
function setLendPoolLiquidator(address liquidator) external;
function getIncentivesController() external view returns (address);
function setIncentivesController(address controller) external;
function getUIDataProvider() external view returns (address);
function setUIDataProvider(address provider) external;
function getBendDataProvider() external view returns (address);
function setBendDataProvider(address provider) external;
function getWalletBalanceProvider() external view returns (address);
function setWalletBalanceProvider(address provider) external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
/**
* @dev Interface for a permittable ERC721 contract
* See https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC72 allowance (see {IERC721-allowance}) by
* presenting a message signed by the account. By not relying on {IERC721-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IPunks {
function balanceOf(address account) external view returns (uint256);
function punkIndexToAddress(uint256 punkIndex) external view returns (address owner);
function buyPunk(uint256 punkIndex) external;
function transferPunk(address to, uint256 punkIndex) external;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
/**
* @dev Interface for a permittable ERC721 contract
* See https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC72 allowance (see {IERC721-allowance}) by
* presenting a message signed by the account. By not relying on {IERC721-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IWrappedPunks is IERC721 {
function punkContract() external view returns (address);
function mint(uint256 punkIndex) external;
function burn(uint256 punkIndex) external;
function registerProxy() external;
function proxyInfo(address user) external returns (address proxy);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
interface IPunkGateway {
/**
* @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
* already deposited enough collateral
* - E.g. User borrows 100 USDC, receiving the 100 USDC in his wallet
* and lock collateral asset in contract
* @param reserveAsset The address of the underlying asset to borrow
* @param amount The amount to be borrowed
* @param punkIndex The index of the CryptoPunk used as collteral
* @param onBehalfOf Address of the user who will receive the loan. Should be the address of the borrower itself
* calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
* if he has been given credit delegation allowance
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function borrow(
address reserveAsset,
uint256 amount,
uint256 punkIndex,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @notice Repays a borrowed `amount` on a specific punk, burning the equivalent loan owned
* - E.g. User repays 100 USDC, burning loan and receives collateral asset
* @param punkIndex The index of the CryptoPunk used as collteral
* @param amount The amount to repay
* @return The final amount repaid, loan is burned or not
**/
function repay(uint256 punkIndex, uint256 amount) external returns (uint256, bool);
/**
* @notice auction a unhealth punk loan with ERC20 reserve
* @param punkIndex The index of the CryptoPunk used as collteral
* @param bidPrice The bid price
**/
function auction(
uint256 punkIndex,
uint256 bidPrice,
address onBehalfOf
) external;
/**
* @notice redeem a unhealth punk loan with ERC20 reserve
* @param punkIndex The index of the CryptoPunk used as collteral
* @param amount The amount to repay the debt and bid fine
**/
function redeem(uint256 punkIndex, uint256 amount) external returns (uint256);
/**
* @notice liquidate a unhealth punk loan with ERC20 reserve
* @param punkIndex The index of the CryptoPunk used as collteral
**/
function liquidate(uint256 punkIndex, uint256 amount) external returns (uint256);
/**
* @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
* already deposited enough collateral
* - E.g. User borrows 100 ETH, receiving the 100 ETH in his wallet
* and lock collateral asset in contract
* @param amount The amount to be borrowed
* @param punkIndex The index of the CryptoPunk to deposit
* @param onBehalfOf Address of the user who will receive the loan. Should be the address of the borrower itself
* calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
* if he has been given credit delegation allowance
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function borrowETH(
uint256 amount,
uint256 punkIndex,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @notice Repays a borrowed `amount` on a specific punk with native ETH
* - E.g. User repays 100 ETH, burning loan and receives collateral asset
* @param punkIndex The index of the CryptoPunk to repay
* @param amount The amount to repay
* @return The final amount repaid, loan is burned or not
**/
function repayETH(uint256 punkIndex, uint256 amount) external payable returns (uint256, bool);
/**
* @notice auction a unhealth punk loan with native ETH
* @param punkIndex The index of the CryptoPunk to repay
* @param onBehalfOf Address of the user who will receive the CryptoPunk. Should be the address of the user itself
* calling the function if he wants to get collateral
**/
function auctionETH(uint256 punkIndex, address onBehalfOf) external payable;
/**
* @notice liquidate a unhealth punk loan with native ETH
* @param punkIndex The index of the CryptoPunk to repay
* @param amount The amount to repay the debt and bid fine
**/
function redeemETH(uint256 punkIndex, uint256 amount) external payable returns (uint256);
/**
* @notice liquidate a unhealth punk loan with native ETH
* @param punkIndex The index of the CryptoPunk to repay
**/
function liquidateETH(uint256 punkIndex) external payable returns (uint256);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
library DataTypes {
struct ReserveData {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
uint40 lastUpdateTimestamp;
//tokens addresses
address bTokenAddress;
address debtTokenAddress;
//address of the interest rate strategy
address interestRateAddress;
//the id of the reserve. Represents the position in the list of the active reserves
uint8 id;
}
struct NftData {
//stores the nft configuration
NftConfigurationMap configuration;
//address of the bNFT contract
address bNftAddress;
//the id of the nft. Represents the position in the list of the active nfts
uint8 id;
}
struct ReserveConfigurationMap {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 48-55: Decimals
//bit 56: Reserve is active
//bit 57: reserve is frozen
//bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled
//bit 60-63: reserved
//bit 64-79: reserve factor
uint256 data;
}
struct NftConfigurationMap {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 56: NFT is active
//bit 57: NFT is frozen
uint256 data;
}
/**
* @dev Enum describing the current state of a loan
* State change flow:
* Created -> Active -> Repaid
* -> Auction -> Defaulted
*/
enum LoanState {
// We need a default that is not 'Created' - this is the zero value
None,
// The loan data is stored, but not initiated yet.
Created,
// The loan has been initialized, funds have been delivered to the borrower and the collateral is held.
Active,
// The loan is in auction, higest price liquidator will got chance to claim it.
Auction,
// 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 liquidator. This is a terminal state.
Defaulted
}
struct LoanData {
//the id of the nft loan
uint256 loanId;
//the current state of the loan
LoanState state;
//address of borrower
address borrower;
//address of nft asset token
address nftAsset;
//the id of nft token
uint256 nftTokenId;
//address of reserve asset token
address reserveAsset;
//scaled borrow amount. Expressed in ray
uint256 scaledAmount;
//start time of first bid time
uint256 bidStartTimestamp;
//bidder address of higest bid
address bidderAddress;
//price of higest bid
uint256 bidPrice;
//borrow amount of loan
uint256 bidBorrowAmount;
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
interface IWETHGateway {
/**
* @dev deposits WETH into the reserve, using native ETH. A corresponding amount of the overlying asset (bTokens)
* is minted.
* @param onBehalfOf address of the user who will receive the bTokens representing the deposit
* @param referralCode integrators are assigned a referral code and can potentially receive rewards.
**/
function depositETH(address onBehalfOf, uint16 referralCode) external payable;
/**
* @dev withdraws the WETH _reserves of msg.sender.
* @param amount amount of bWETH to withdraw and receive native ETH
* @param to address of the user who will receive native ETH
*/
function withdrawETH(uint256 amount, address to) external;
/**
* @dev borrow WETH, unwraps to ETH and send both the ETH and DebtTokens to msg.sender, via `approveDelegation` and onBehalf argument in `LendPool.borrow`.
* @param amount the amount of ETH to borrow
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token ID of the underlying NFT used as collateral
* @param onBehalfOf Address of the user who will receive the loan. Should be the address of the borrower itself
* calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
* if he has been given credit delegation allowance
* @param referralCode integrators are assigned a referral code and can potentially receive rewards
*/
function borrowETH(
uint256 amount,
address nftAsset,
uint256 nftTokenId,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @dev repays a borrow on the WETH reserve, for the specified amount (or for the whole amount, if uint256(-1) is specified).
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token ID of the underlying NFT used as collateral
* @param amount the amount to repay, or uint256(-1) if the user wants to repay everything
*/
function repayETH(
address nftAsset,
uint256 nftTokenId,
uint256 amount
) external payable returns (uint256, bool);
/**
* @dev auction a borrow on the WETH reserve
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token ID of the underlying NFT used as collateral
* @param onBehalfOf Address of the user who will receive the underlying NFT used as collateral.
* Should be the address of the borrower itself calling the function if he wants to borrow against his own collateral.
*/
function auctionETH(
address nftAsset,
uint256 nftTokenId,
address onBehalfOf
) external payable;
/**
* @dev redeems a borrow on the WETH reserve
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token ID of the underlying NFT used as collateral
* @param amount The amount to repay the debt and bid fine
*/
function redeemETH(
address nftAsset,
uint256 nftTokenId,
uint256 amount
) external payable returns (uint256);
/**
* @dev liquidates a borrow on the WETH reserve
* @param nftAsset The address of the underlying NFT used as collateral
* @param nftTokenId The token ID of the underlying NFT used as collateral
*/
function liquidateETH(address nftAsset, uint256 nftTokenId) external payable returns (uint256);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.4;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import {IPunks} from "../interfaces/IPunks.sol";
/**
* @title EmergencyTokenRecovery
* @notice Add Emergency Recovery Logic to contract implementation
* @author Bend
**/
abstract contract EmergencyTokenRecoveryUpgradeable is OwnableUpgradeable {
event EmergencyEtherTransfer(address indexed to, uint256 amount);
function __EmergencyTokenRecovery_init() internal onlyInitializing {
__Ownable_init();
}
/**
* @dev transfer ERC20 from the utility contract, for ERC20 recovery in case of stuck tokens due
* direct transfers to the contract address.
* @param token token to transfer
* @param to recipient of the transfer
* @param amount amount to send
*/
function emergencyERC20Transfer(
address token,
address to,
uint256 amount
) external onlyOwner {
IERC20Upgradeable(token).transfer(to, amount);
}
/**
* @dev transfer ERC721 from the utility contract, for ERC721 recovery in case of stuck tokens due
* direct transfers to the contract address.
* @param token token to transfer
* @param to recipient of the transfer
* @param id token id to send
*/
function emergencyERC721Transfer(
address token,
address to,
uint256 id
) external onlyOwner {
IERC721Upgradeable(token).safeTransferFrom(address(this), to, id);
}
/**
* @dev transfer CryptoPunks from the utility contract, for punks recovery in case of stuck punks
* due direct transfers to the contract address.
* @param to recipient of the transfer
* @param index punk index to send
*/
function emergencyPunksTransfer(
address punks,
address to,
uint256 index
) external onlyOwner {
IPunks(punks).transferPunk(to, index);
}
/**
* @dev transfer native Ether from the utility contract, for native Ether recovery in case of stuck Ether
* due selfdestructs or transfer ether to pre-computated contract address before deployment.
* @param to recipient of the transfer
* @param amount amount to send
*/
function emergencyEtherTransfer(address to, uint256 amount) external onlyOwner {
(bool success, ) = to.call{value: amount}(new bytes(0));
require(success, "ETH_TRANSFER_FAILED");
emit EmergencyEtherTransfer(to, amount);
}
uint256[50] private __gap;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
__Context_init_unchained();
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
uint256[50] private __gap;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/utils/Initializable.sol)
pragma solidity ^0.8.0;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
* initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() initializer {}
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
// contract may have been reentered.
require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} modifier, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
function _isConstructor() private view returns (bool) {
return !AddressUpgradeable.isContract(address(this));
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @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 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);
}
}
}
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// 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 IERC165Upgradeable {
/**
* @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);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721ReceiverUpgradeable {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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`, 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;
} <i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>
// 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);
}