Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60c06040 | 18086967 | 424 days ago | IN | 0 ETH | 0.13442269 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ParticleExchange
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {IERC721} from "@openzeppelin/contracts/interfaces/IERC721.sol"; import {WETH} from "@solmate/tokens/WETH.sol"; import {IParticleExchange} from "../interfaces/IParticleExchange.sol"; import {ReentrancyGuard} from "../libraries/security/ReentrancyGuard.sol"; import {MathUtils} from "../libraries/math/MathUtils.sol"; import {Lien} from "../libraries/types/Structs.sol"; import {Errors} from "../libraries/types/Errors.sol"; contract ParticleExchange is IParticleExchange, Ownable2StepUpgradeable, UUPSUpgradeable, ReentrancyGuard { using Address for address payable; uint256 private constant _MAX_RATE = 100_000; // 1000% APR uint256 private constant _MAX_PRICE = 1_000 ether; uint256 private constant _MAX_TREASURY_RATE = 1_000; // 10% uint256 private constant _AUCTION_DURATION = 36 hours; uint256 private constant _MIN_AUCTION_DURATION = 1 hours; WETH private immutable weth; uint256 private _nextLienId; uint256 private _treasuryRate; uint256 private _treasury; mapping(uint256 lienId => bytes32 lienHash) public liens; mapping(address account => uint256 balance) public accountBalance; mapping(address marketplace => bool registered) public registeredMarketplaces; // required by openzeppelin UUPS module // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address) internal override onlyOwner {} constructor(address wethAddress) { weth = WETH(payable(wethAddress)); _disableInitializers(); } function initialize() external initializer { __UUPSUpgradeable_init(); __Ownable_init(); } /*============================================================== Supply Logic ==============================================================*/ /// @inheritdoc IParticleExchange function supplyNft( address collection, uint256 tokenId, uint256 price, uint256 rate ) external override nonReentrant returns (uint256 lienId) { lienId = _supplyNft(msg.sender, collection, tokenId, price, rate); // transfer NFT into contract /// @dev collection.setApprovalForAll should have been called by this point /// @dev receiver is this contract, no need to safeTransferFrom IERC721(collection).transferFrom(msg.sender, address(this), tokenId); return lienId; } function _supplyNft( address lender, address collection, uint256 tokenId, uint256 price, uint256 rate ) internal returns (uint256 lienId) { if (price > _MAX_PRICE || rate > _MAX_RATE) { revert Errors.InvalidParameters(); } // create a new lien Lien memory lien = Lien({ lender: lender, borrower: address(0), collection: collection, tokenId: tokenId, price: price, rate: rate, loanStartTime: 0, auctionStartTime: 0 }); /// @dev Safety: lienId unlikely to overflow by linear increment unchecked { liens[lienId = _nextLienId++] = keccak256(abi.encode(lien)); } emit SupplyNFT(lienId, lender, collection, tokenId, price, rate); } /// @inheritdoc IParticleExchange function updateLoan( Lien calldata lien, uint256 lienId, uint256 price, uint256 rate ) external override validateLien(lien, lienId) nonReentrant { if (msg.sender != lien.lender) { revert Errors.Unauthorized(); } if (lien.loanStartTime != 0) { revert Errors.LoanStarted(); } if (price > _MAX_PRICE || rate > _MAX_RATE) { revert Errors.InvalidParameters(); } liens[lienId] = keccak256( abi.encode( Lien({ lender: lien.lender, borrower: address(0), collection: lien.collection, tokenId: lien.tokenId, price: price, rate: rate, loanStartTime: 0, auctionStartTime: 0 }) ) ); emit UpdateLoan(lienId, price, rate); } /*============================================================== Withdraw Logic ==============================================================*/ /// @inheritdoc IParticleExchange function withdrawNft(Lien calldata lien, uint256 lienId) external override validateLien(lien, lienId) nonReentrant { if (msg.sender != lien.lender) { revert Errors.Unauthorized(); } if (lien.loanStartTime != 0) { /// @dev the same tokenId can be used for other lender's active loan, can't withdraw others revert Errors.LoanStarted(); } // delete lien delete liens[lienId]; // transfer NFT back to lender /// @dev can withdraw at this point means the NFT is currently in contract without active loan /// @dev the interest (if any) is already accrued to lender at NFT acquiring time /// @dev use transferFrom in case the receiver does not implement onERC721Received IERC721(lien.collection).transferFrom(address(this), msg.sender, lien.tokenId); emit WithdrawNFT(lienId); } /// @inheritdoc IParticleExchange function withdrawEth(Lien calldata lien, uint256 lienId) external override validateLien(lien, lienId) nonReentrant { if (msg.sender != lien.lender) { revert Errors.Unauthorized(); } if (lien.loanStartTime == 0) { revert Errors.InactiveLoan(); } // verify that auction is concluded (i.e., liquidation condition has met) if (lien.auctionStartTime == 0 || block.timestamp <= lien.auctionStartTime + _AUCTION_DURATION) { revert Errors.LiquidationHasNotReached(); } // delete lien delete liens[lienId]; // transfer ETH to lender, i.e., seize ETH collateral payable(lien.lender).sendValue(lien.price); emit WithdrawETH(lienId); } /*============================================================== Market Sell Logic ==============================================================*/ /// @inheritdoc IParticleExchange function sellNftToMarketPull( Lien calldata lien, uint256 lienId, uint256 amount, address marketplace, address puller, bytes calldata tradeData ) external payable override validateLien(lien, lienId) nonReentrant { _sellNftToMarketCheck(lien, amount, msg.sender, msg.value); _sellNftToMarketLienUpdate(lien, lienId, amount, msg.sender); _execSellNftToMarketPull(lien, lien.tokenId, amount, marketplace, puller, tradeData); } /// @inheritdoc IParticleExchange function sellNftToMarketPush( Lien calldata lien, uint256 lienId, uint256 amount, address marketplace, bytes calldata tradeData ) external payable override validateLien(lien, lienId) nonReentrant { _sellNftToMarketCheck(lien, amount, msg.sender, msg.value); _sellNftToMarketLienUpdate(lien, lienId, amount, msg.sender); _execSellNftToMarketPush(lien, lien.tokenId, amount, marketplace, tradeData); } /** * @dev Common pre market sell checks, for both pull and push based flow */ function _sellNftToMarketCheck(Lien calldata lien, uint256 amount, address msgSender, uint256 msgValue) internal { if (lien.loanStartTime != 0) { revert Errors.LoanStarted(); } if (lien.lender == address(0)) { revert Errors.BidNotTaken(); } /// @dev: underlying account balancing ensures balance > lien.price - (amount + msg.value) (i.e., no overspend) _balanceAccount(msgSender, lien.price, amount + msgValue); } /** * @dev Common operations prior to market sell execution, used for both market sell and bid acceptance flow */ function _sellNftToMarketBeforeExec(address marketplace) internal view returns (uint256) { if (!registeredMarketplaces[marketplace]) { revert Errors.UnregisteredMarketplace(); } // ETH + WETH balance before NFT sell execution return address(this).balance + weth.balanceOf(address(this)); } /** * @dev Pull-based sell nft to market internal execution, used for both market sell and bid acceptance flow */ function _execSellNftToMarketPull( Lien memory lien, uint256 tokenId, uint256 amount, address marketplace, address puller, bytes memory tradeData ) internal { uint256 balanceBefore = _sellNftToMarketBeforeExec(marketplace); /// @dev only approve for one tokenId, preventing bulk execute attack in raw trade /// @dev puller (e.g. Seaport Conduit) may be different from marketplace (e.g. Seaport Proxy Router) IERC721(lien.collection).approve(puller, tokenId); // execute raw order on registered marketplace // solhint-disable-next-line avoid-low-level-calls (bool success, ) = marketplace.call(tradeData); if (!success) { revert Errors.MartketplaceFailedToTrade(); } _sellNftToMarketAfterExec(lien, tokenId, amount, balanceBefore); } /** * @dev Push-based sell nft to market internal execution, used for both market sell and bid acceptance flow */ function _execSellNftToMarketPush( Lien memory lien, uint256 tokenId, uint256 amount, address marketplace, bytes memory tradeData ) internal { uint256 balanceBefore = _sellNftToMarketBeforeExec(marketplace); /// @dev directly send NFT to a marketplace router (e.g. Reservoir); based on the data, /// the router will match order and transfer back the correct amount of fund IERC721(lien.collection).safeTransferFrom(address(this), marketplace, tokenId, tradeData); _sellNftToMarketAfterExec(lien, tokenId, amount, balanceBefore); } /** * @dev Common operations after market sell execution, used for both market sell and bid acceptance flow */ function _sellNftToMarketAfterExec( Lien memory lien, uint256 tokenId, uint256 amount, uint256 balanceBefore ) internal { // transform all WETH (from this trade or otherwise collected elsewhere) to ETH uint256 wethAfter = weth.balanceOf(address(this)); if (wethAfter > 0) { weth.withdraw(wethAfter); } // verify that the NFT in lien is sold and the balance increase is correct if ( IERC721(lien.collection).ownerOf(tokenId) == address(this) || address(this).balance - balanceBefore != amount ) { revert Errors.InvalidNFTSell(); } } /** * @dev Common post market sell checks, for both pull and push based flow */ function _sellNftToMarketLienUpdate( Lien calldata lien, uint256 lienId, uint256 amount, address msgSender ) internal { // update lien liens[lienId] = keccak256( abi.encode( Lien({ lender: lien.lender, borrower: msgSender, collection: lien.collection, tokenId: lien.tokenId, price: lien.price, rate: lien.rate, loanStartTime: block.timestamp, auctionStartTime: 0 }) ) ); emit SellMarketNFT(lienId, msgSender, amount, block.timestamp); } /*============================================================== Market Buy Logic ==============================================================*/ /// @inheritdoc IParticleExchange function buyNftFromMarket( Lien calldata lien, uint256 lienId, uint256 tokenId, uint256 amount, address spender, address marketplace, bytes calldata tradeData ) external override validateLien(lien, lienId) nonReentrant { if (msg.sender != lien.borrower) { revert Errors.Unauthorized(); } if (lien.loanStartTime == 0) { revert Errors.InactiveLoan(); } uint256 accruedInterest = MathUtils.calculateCurrentInterest(lien.price, lien.rate, lien.loanStartTime); // since: lien.price = sold amount + margin // and: payback = sold amount + margin - bought amount - interest // hence: payback = lien.price - bought amount - interest /// @dev cannot overspend, i.e., will revert if payback to borrower < 0. Payback < 0 /// means the borrower loses all the margin, and still owes some interest. Notice that /// this function is not payable because rational borrower won't deposit even more cost /// to exit an already liquidated position. uint256 payback = lien.price - amount - accruedInterest; // accrue interest to lender _accrueInterest(lien.lender, accruedInterest); // payback PnL to borrower if (payback > 0) { accountBalance[lien.borrower] += payback; } // update lien (by default, the lien is open to accept new loan) liens[lienId] = keccak256( abi.encode( Lien({ lender: lien.lender, borrower: address(0), collection: lien.collection, tokenId: tokenId, price: lien.price, rate: lien.rate, loanStartTime: 0, auctionStartTime: 0 }) ) ); // route trade execution to marketplace _execBuyNftFromMarket(lien.collection, tokenId, amount, spender, marketplace, tradeData); emit BuyMarketNFT(lienId, tokenId, amount); } function _execBuyNftFromMarket( address collection, uint256 tokenId, uint256 amount, address spender, address marketplace, bytes calldata tradeData ) internal { if (!registeredMarketplaces[marketplace]) { revert Errors.UnregisteredMarketplace(); } if (IERC721(collection).ownerOf(tokenId) == address(this)) { revert Errors.InvalidNFTBuy(); } uint256 ethBalanceBefore = address(this).balance; uint256 wethBalanceBefore = weth.balanceOf(address(this)); // execute raw order on registered marketplace bool success; if (spender == address(0)) { // use ETH // solhint-disable-next-line avoid-low-level-calls (success, ) = marketplace.call{value: amount}(tradeData); } else { // use WETH weth.deposit{value: amount}(); weth.approve(spender, amount); // solhint-disable-next-line avoid-low-level-calls (success, ) = marketplace.call(tradeData); } if (!success) { revert Errors.MartketplaceFailedToTrade(); } // conert back any unspent WETH to ETH uint256 wethBalance = weth.balanceOf(address(this)); if (wethBalance > 0) { weth.withdraw(wethBalance); } // verify that the declared NFT is acquired and the balance decrease is correct if ( IERC721(collection).ownerOf(tokenId) != address(this) || ethBalanceBefore + wethBalanceBefore - address(this).balance != amount ) { revert Errors.InvalidNFTBuy(); } } /*============================================================== Swap Logic ==============================================================*/ /// @inheritdoc IParticleExchange function swapWithEth( Lien calldata lien, uint256 lienId ) external payable override validateLien(lien, lienId) nonReentrant { if (lien.loanStartTime != 0) { revert Errors.LoanStarted(); } if (lien.lender == address(0)) { revert Errors.BidNotTaken(); } /// @dev: underlying account balancing ensures balance > lien.price - msg.value (i.e., no overspend) _balanceAccount(msg.sender, lien.price, msg.value); // update lien liens[lienId] = keccak256( abi.encode( Lien({ lender: lien.lender, borrower: msg.sender, collection: lien.collection, tokenId: lien.tokenId, price: lien.price, rate: lien.rate, loanStartTime: block.timestamp, auctionStartTime: 0 }) ) ); // transfer NFT to borrower IERC721(lien.collection).safeTransferFrom(address(this), msg.sender, lien.tokenId); emit SwapWithETH(lienId, msg.sender, block.timestamp); } /// @inheritdoc IParticleExchange function repayWithNft( Lien calldata lien, uint256 lienId, uint256 tokenId ) external override validateLien(lien, lienId) nonReentrant { if (msg.sender != lien.borrower) { revert Errors.Unauthorized(); } if (lien.loanStartTime == 0) { revert Errors.InactiveLoan(); } // transfer fund to corresponding recipients _execRepayWithNft(lien, lienId, tokenId); // transfer NFT to the contract /// @dev collection.setApprovalForAll should have been called by this point /// @dev receiver is this contract, no need to safeTransferFrom IERC721(lien.collection).transferFrom(msg.sender, address(this), tokenId); } /// @dev unchecked function, make sure lien is valid, caller is borrower and collection is matched function _execRepayWithNft(Lien memory lien, uint256 lienId, uint256 tokenId) internal { // accrue interest to lender uint256 accruedInterest = MathUtils.calculateCurrentInterest(lien.price, lien.rate, lien.loanStartTime); // pay PnL to borrower // since: lien.price = sold amount + margin // and: payback = sold amount + margin - interest // hence: payback = lien.price - interest uint256 payback = lien.price - accruedInterest; if (payback > 0) { accountBalance[lien.borrower] += payback; } // accrue interest to lender _accrueInterest(lien.lender, accruedInterest); // update lien (by default, the lien is open to accept new loan) liens[lienId] = keccak256( abi.encode( Lien({ lender: lien.lender, borrower: address(0), collection: lien.collection, tokenId: tokenId, price: lien.price, rate: lien.rate, loanStartTime: 0, auctionStartTime: 0 }) ) ); emit RepayWithNFT(lienId, tokenId); } /*============================================================== Refinance Logic ==============================================================*/ /// @inheritdoc IParticleExchange function refinanceLoan( Lien calldata oldLien, uint256 oldLienId, Lien calldata newLien, uint256 newLienId ) external payable override validateLien(oldLien, oldLienId) validateLien(newLien, newLienId) nonReentrant { if (msg.sender != oldLien.borrower) { revert Errors.Unauthorized(); } if (oldLien.loanStartTime == 0) { revert Errors.InactiveLoan(); } if (newLien.loanStartTime != 0) { // cannot swap to another active loan revert Errors.LoanStarted(); } if (newLien.lender == address(0)) { revert Errors.BidNotTaken(); } if (oldLien.collection != newLien.collection) { // cannot swap to a new loan with different collection revert Errors.UnmatchedCollections(); } uint256 accruedInterest = MathUtils.calculateCurrentInterest( oldLien.price, oldLien.rate, oldLien.loanStartTime ); /// @dev old price + msg.value is available now, new price + interest is the need to spend /// @dev account balancing ensures balance > new price + interest - (old price + msg.value) (i.e., no overspend) _balanceAccount(msg.sender, newLien.price + accruedInterest, oldLien.price + msg.value); // accrue interest to the lender _accrueInterest(oldLien.lender, accruedInterest); // update old lien liens[oldLienId] = keccak256( abi.encode( Lien({ lender: oldLien.lender, borrower: address(0), collection: oldLien.collection, tokenId: newLien.tokenId, price: oldLien.price, rate: oldLien.rate, loanStartTime: 0, auctionStartTime: 0 }) ) ); // update new lien liens[newLienId] = keccak256( abi.encode( Lien({ lender: newLien.lender, borrower: oldLien.borrower, collection: newLien.collection, tokenId: newLien.tokenId, price: newLien.price, rate: newLien.rate, loanStartTime: block.timestamp, auctionStartTime: 0 }) ) ); emit Refinance(oldLienId, newLienId, block.timestamp); } /*============================================================== Bid Logic ==============================================================*/ /// @inheritdoc IParticleExchange function offerBid( address collection, uint256 margin, uint256 price, uint256 rate ) external payable override nonReentrant returns (uint256 lienId) { if (price > _MAX_PRICE || rate > _MAX_RATE) { revert Errors.InvalidParameters(); } // balance the account for the reest of the margin _balanceAccount(msg.sender, margin, msg.value); // create a new lien Lien memory lien = Lien({ lender: address(0), borrower: msg.sender, collection: collection, tokenId: margin, /// @dev: use tokenId for margin storage price: price, rate: rate, loanStartTime: 0, auctionStartTime: 0 }); /// @dev Safety: lienId unlikely to overflow by linear increment unchecked { liens[lienId = _nextLienId++] = keccak256(abi.encode(lien)); } emit OfferBid(lienId, msg.sender, collection, margin, price, rate); } /// @inheritdoc IParticleExchange function updateBid( Lien calldata lien, uint256 lienId, uint256 margin, uint256 price, uint256 rate ) external payable validateLien(lien, lienId) nonReentrant { if (msg.sender != lien.borrower) { revert Errors.Unauthorized(); } if (lien.lender != address(0)) { /// @dev: if lender exists, an NFT is supplied, regardless of loan active or not, /// bid is taken and can't be updated revert Errors.BidTaken(); } if (price > _MAX_PRICE || rate > _MAX_RATE) { revert Errors.InvalidParameters(); } /// @dev: old margin was stored in the lien.tokenId field /// @dev: old margin + msg.value is available now; surplus adds to balance, deficit takes from balance _balanceAccount(msg.sender, margin, lien.tokenId + msg.value); // update lien liens[lienId] = keccak256( abi.encode( Lien({ lender: address(0), borrower: lien.borrower, collection: lien.collection, tokenId: margin, /// @dev: use tokenId for margin storage price: price, rate: rate, loanStartTime: 0, auctionStartTime: 0 }) ) ); emit UpdateBid(lienId, margin, price, rate); } /// @inheritdoc IParticleExchange function cancelBid(Lien calldata lien, uint256 lienId) external override validateLien(lien, lienId) nonReentrant { if (msg.sender != lien.borrower) { revert Errors.Unauthorized(); } if (lien.lender != address(0)) { /// @dev: if lender exists, an NFT is supplied, regardless of loan active or not, /// bid is taken and can't be cancelled revert Errors.BidTaken(); } // return margin to borrower /// @dev: old margin was stored in the lien.tokenId field accountBalance[lien.borrower] += lien.tokenId; // delete lien delete liens[lienId]; emit CancelBid(lienId); } /// @inheritdoc IParticleExchange function acceptBidSellNftToMarketPull( Lien calldata lien, uint256 lienId, uint256 tokenId, uint256 amount, address marketplace, address puller, bytes calldata tradeData ) external override validateLien(lien, lienId) nonReentrant { _acceptBidSellNftToMarketCheck(lien, amount); _acceptBidSellNftToMarketLienUpdate(lien, lienId, tokenId, amount, msg.sender); // transfer NFT into contract /// @dev collection.setApprovalForAll should have been called by this point /// @dev receiver is this contract, no need to safeTransferFrom IERC721(lien.collection).transferFrom(msg.sender, address(this), tokenId); _execSellNftToMarketPull(lien, tokenId, amount, marketplace, puller, tradeData); } /// @inheritdoc IParticleExchange function acceptBidSellNftToMarketPush( Lien calldata lien, uint256 lienId, uint256 tokenId, uint256 amount, address marketplace, bytes calldata tradeData ) external override validateLien(lien, lienId) nonReentrant { _acceptBidSellNftToMarketCheck(lien, amount); _acceptBidSellNftToMarketLienUpdate(lien, lienId, tokenId, amount, msg.sender); // transfer NFT into contract /// @dev collection.setApprovalForAll should have been called by this point /// @dev receiver is this contract, no need to safeTransferFrom IERC721(lien.collection).transferFrom(msg.sender, address(this), tokenId); _execSellNftToMarketPush(lien, tokenId, amount, marketplace, tradeData); } function _acceptBidSellNftToMarketCheck(Lien memory lien, uint256 amount) internal { if (lien.lender != address(0)) { /// @dev: if lender exists, an NFT is supplied, regardless of loan active or not, /// bid is taken and can't be re-accepted revert Errors.BidTaken(); } // transfer the surplus to the borrower /// @dev: lien.tokenId stores the margin /// @dev: revert if margin + sold amount can't cover lien.price, i.e., no overspend accountBalance[lien.borrower] += lien.tokenId + amount - lien.price; } function _acceptBidSellNftToMarketLienUpdate( Lien memory lien, uint256 lienId, uint256 tokenId, uint256 amount, address lender ) internal { // update lien liens[lienId] = keccak256( abi.encode( Lien({ lender: lender, borrower: lien.borrower, collection: lien.collection, tokenId: tokenId, price: lien.price, rate: lien.rate, loanStartTime: block.timestamp, auctionStartTime: 0 }) ) ); emit AcceptBid(lienId, lender, tokenId, amount, block.timestamp); } /*============================================================== Auction Logic ==============================================================*/ /// @inheritdoc IParticleExchange function startLoanAuction( Lien calldata lien, uint256 lienId ) external override validateLien(lien, lienId) nonReentrant { if (msg.sender != lien.lender) { revert Errors.Unauthorized(); } if (lien.loanStartTime == 0) { revert Errors.InactiveLoan(); } if (lien.auctionStartTime != 0) { revert Errors.AuctionStarted(); } // update lien liens[lienId] = keccak256( abi.encode( Lien({ lender: lien.lender, borrower: lien.borrower, collection: lien.collection, tokenId: lien.tokenId, price: lien.price, rate: lien.rate, loanStartTime: lien.loanStartTime, auctionStartTime: block.timestamp }) ) ); emit StartAuction(lienId, block.timestamp); } /// @inheritdoc IParticleExchange function stopLoanAuction( Lien calldata lien, uint256 lienId ) external override validateLien(lien, lienId) nonReentrant { if (msg.sender != lien.lender) { revert Errors.Unauthorized(); } if (lien.auctionStartTime == 0) { revert Errors.AuctionNotStarted(); } if (block.timestamp < lien.auctionStartTime + _MIN_AUCTION_DURATION) { revert Errors.AuctionEndTooSoon(); } // update lien liens[lienId] = keccak256( abi.encode( Lien({ lender: lien.lender, borrower: lien.borrower, collection: lien.collection, tokenId: lien.tokenId, price: lien.price, rate: lien.rate, loanStartTime: lien.loanStartTime, auctionStartTime: 0 }) ) ); emit StopAuction(lienId); } /// @inheritdoc IParticleExchange function auctionSellNft( Lien calldata lien, uint256 lienId, uint256 tokenId ) external override validateLien(lien, lienId) nonReentrant { if (lien.auctionStartTime == 0) { revert Errors.AuctionNotStarted(); } // transfer fund to corresponding recipients _execAuctionSellNft(lien, lienId, tokenId, msg.sender); // transfer NFT to the contract /// @dev receiver is this contract, no need to safeTransferFrom /// @dev at this point, collection.setApprovalForAll should have been called IERC721(lien.collection).transferFrom(msg.sender, address(this), tokenId); } /// @dev unchecked function, make sure lien is validated, auction is live and collection is matched function _execAuctionSellNft(Lien memory lien, uint256 lienId, uint256 tokenId, address auctionBuyer) internal { uint256 accruedInterest = MathUtils.calculateCurrentInterest(lien.price, lien.rate, lien.loanStartTime); /// @dev: arithmetic revert if accruedInterest > lien.price, i.e., even 0 buyback cannot cover the interest uint256 currentAuctionPrice = MathUtils.calculateCurrentAuctionPrice( lien.price - accruedInterest, block.timestamp - lien.auctionStartTime, _AUCTION_DURATION ); // pay PnL to borrower uint256 payback = lien.price - currentAuctionPrice - accruedInterest; if (payback > 0) { accountBalance[lien.borrower] += payback; } // pay auction price to new NFT supplier payable(auctionBuyer).sendValue(currentAuctionPrice); // accrue interest to lender _accrueInterest(lien.lender, accruedInterest); // update lien (by default, the lien is open to accept new loan) liens[lienId] = keccak256( abi.encode( Lien({ lender: lien.lender, borrower: address(0), collection: lien.collection, tokenId: tokenId, price: lien.price, rate: lien.rate, loanStartTime: 0, auctionStartTime: 0 }) ) ); emit AuctionSellNFT(lienId, auctionBuyer, tokenId, currentAuctionPrice); } /*============================================================== Push-Based Logic ==============================================================*/ /** * @notice Receiver function upon ERC721 transfer * * @dev We modify this receiver to enable "push based" NFT supply, where one of the following is embedded in the * data bytes that are piggy backed with the SafeTransferFrom call: * (1) the price and rate (for nft supply) (64 bytes) or * (2) lien information (for NFT repay or auction buy) (288 bytes) or * (3) lien information and market sell information (accept bid to NFT market sell) (>= 384 bytes). * This way, the lender doesn't need to additionally sign the "setApprovalForAll" transaction, which saves gas and * creates a better user experience. * * @param from the address which previously owned the NFT * @param tokenId the NFT identifier which is being transferred * @param data additional data with no specified format */ function onERC721Received(address, address from, uint256 tokenId, bytes calldata data) external returns (bytes4) { /// @dev NFT transfer coming from buyNftFromMarket will be flagged as already enterred (re-entrancy status), /// where the NFT is matched with an existing lien already. If it proceeds (to supply), this NFT will be tied /// with two liens, which creates divergence. if (!isEntered()) { _pushBasedNftSupply(from, tokenId, data); } return this.onERC721Received.selector; } function _pushBasedNftSupply(address from, uint256 tokenId, bytes calldata data) internal nonReentrant { /// @dev this function is external and can be called by anyone, we need to check the NFT is indeed received /// at this point to proceed, message sender is the NFT collection in nominal function call if (IERC721(msg.sender).ownerOf(tokenId) != address(this)) { revert Errors.NFTNotReceived(); } // use data.length to branch different conditions if (data.length == 64) { // Conditon (1): NFT supply (uint256 price, uint256 rate) = abi.decode(data, (uint256, uint256)); /// @dev the msg.sender is the NFT collection (called by safeTransferFrom's _checkOnERC721Received check) _supplyNft(from, msg.sender, tokenId, price, rate); } else if (data.length == 288) { // Conditon (2): NFT repay or auction buy (Lien memory lien, uint256 lienId) = abi.decode(data, (Lien, uint256)); /// @dev equivalent to modifier validateLien, replacing calldata to memory if (liens[lienId] != keccak256(abi.encode(lien))) { revert Errors.InvalidLien(); } /// @dev msg.sender is the NFT collection address if (msg.sender != lien.collection) { revert Errors.UnmatchedCollections(); } if (from == lien.borrower) { /// @dev repayWithNft branch /// @dev notice that for borrower repayWithNft and auctionSellNft (at any price point) yield the same /// return, since repayNft's payback = auction's payback + auction price, and auction price goes to the /// same "from" (the borrower) too. Routing to repayNft is more gas efficient for one less receiver. if (lien.loanStartTime == 0) { revert Errors.InactiveLoan(); } _execRepayWithNft(lien, lienId, tokenId); } else { /// @dev auctionSellNft branch /// @dev equivalent to modifier auctionLive, replacing calldata to memory if (lien.auctionStartTime == 0) { revert Errors.AuctionNotStarted(); } /// @dev "from" (acution buyer) is the auction buyer address that calls safeTransferFrom _execAuctionSellNft(lien, lienId, tokenId, from); } } else if (data.length >= 384) { // Conditon (3): Accept bid to sell NFT to market /// @dev flexible data.length because tradeData can be of any non-zero length ( Lien memory lien, uint256 lienId, uint256 amount, address marketplace, address puller, bytes memory tradeData ) = abi.decode(data, (Lien, uint256, uint256, address, address, bytes)); /// @dev equivalent to modifier validateLien, replacing calldata to memory if (liens[lienId] != keccak256(abi.encode(lien))) { revert Errors.InvalidLien(); } /// @dev msg.sender is the NFT collection address if (msg.sender != lien.collection) { revert Errors.UnmatchedCollections(); } /// @dev "from" (nft supplier) is address that calls safeTransferFrom /// @dev zero address puller, means sell to market using push based flow if (puller == address(0)) { _acceptBidSellNftToMarketCheck(lien, amount); _acceptBidSellNftToMarketLienUpdate(lien, lienId, tokenId, amount, from); _execSellNftToMarketPush(lien, tokenId, amount, marketplace, tradeData); } else { _acceptBidSellNftToMarketCheck(lien, amount); _acceptBidSellNftToMarketLienUpdate(lien, lienId, tokenId, amount, from); _execSellNftToMarketPull(lien, tokenId, amount, marketplace, puller, tradeData); } } else { revert Errors.InvalidParameters(); } } /*============================================================== Balance Logic ==============================================================*/ /// @inheritdoc IParticleExchange function withdrawAccountBalance() external override nonReentrant { uint256 balance = accountBalance[msg.sender]; if (balance == 0) return; accountBalance[msg.sender] = 0; payable(msg.sender).sendValue(balance); emit WithdrawAccountBalance(msg.sender, balance); } function _accrueInterest(address account, uint256 amount) internal { uint256 treasuryRate = _treasuryRate; /// @dev SLOAD once to cache, saving gas if (treasuryRate > 0) { uint256 treasuryInterest = MathUtils.calculateTreasuryProportion(amount, treasuryRate); _treasury += treasuryInterest; amount -= treasuryInterest; } accountBalance[account] += amount; emit AccrueInterest(account, amount); } function _balanceAccount(address account, uint256 withdraw, uint256 deposit) internal { if (withdraw > deposit) { // use account balance to cover the deposit deficit /// @dev balance - (amount - deposit) >= 0, i.e., amount <= balance + deposit (cannot overspend) accountBalance[account] -= (withdraw - deposit); } else if (deposit > withdraw) { // top up account balance with the deposit surplus accountBalance[account] += (deposit - withdraw); } } /*============================================================== Validation Logic ==============================================================*/ modifier validateLien(Lien calldata lien, uint256 lienId) { if (liens[lienId] != keccak256(abi.encode(lien))) { revert Errors.InvalidLien(); } _; } /*============================================================== Admin Logic ==============================================================*/ /// @inheritdoc IParticleExchange function registerMarketplace(address marketplace) external override onlyOwner { registeredMarketplaces[marketplace] = true; emit RegisterMarketplace(marketplace); } /// @inheritdoc IParticleExchange function unregisterMarketplace(address marketplace) external override onlyOwner { registeredMarketplaces[marketplace] = false; emit UnregisterMarketplace(marketplace); } /// @inheritdoc IParticleExchange function setTreasuryRate(uint256 rate) external override onlyOwner { if (rate > _MAX_TREASURY_RATE) { revert Errors.InvalidParameters(); } _treasuryRate = rate; emit UpdateTreasuryRate(rate); } /// @inheritdoc IParticleExchange function withdrawTreasury(address receiver) external override onlyOwner { uint256 withdrawAmount = _treasury; if (withdrawAmount > 0) { if (receiver == address(0)) { revert Errors.InvalidParameters(); } _treasury = 0; payable(receiver).sendValue(withdrawAmount); emit WithdrawTreasury(receiver, withdrawAmount); } } /*============================================================== Miscellaneous ==============================================================*/ // receive ETH // solhint-disable-next-line no-empty-blocks receive() external payable {} // solhint-disable-next-line func-name-mixedcase function WETH_ADDRESS() external view returns (address) { return address(weth); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../ERC1967/ERC1967UpgradeUpgradeable.sol"; import "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable { function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol) pragma solidity ^0.8.0; import "./OwnableUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides 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} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable { function __Ownable2Step_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable2Step_init_unchained() internal onlyInitializing { } address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() external { address sender = _msgSender(); require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner"); _transferOwnership(sender); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://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 functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) pragma solidity ^0.8.0; import "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "./ERC20.sol"; import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; /// @notice Minimalist and modern Wrapped Ether implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/WETH.sol) /// @author Inspired by WETH9 (https://github.com/dapphub/ds-weth/blob/master/src/weth9.sol) contract WETH is ERC20("Wrapped Ether", "WETH", 18) { using SafeTransferLib for address; event Deposit(address indexed from, uint256 amount); event Withdrawal(address indexed to, uint256 amount); function deposit() public payable virtual { _mint(msg.sender, msg.value); emit Deposit(msg.sender, msg.value); } function withdraw(uint256 amount) public virtual { _burn(msg.sender, amount); emit Withdrawal(msg.sender, amount); msg.sender.safeTransferETH(amount); } receive() external payable virtual { deposit(); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {Lien} from "../libraries/types/Structs.sol"; interface IParticleExchange { event SupplyNFT(uint256 lienId, address lender, address collection, uint256 tokenId, uint256 price, uint256 rate); event UpdateLoan(uint256 lienId, uint256 price, uint256 rate); event WithdrawNFT(uint256 lienId); event WithdrawETH(uint256 lienId); event SellMarketNFT(uint256 lienId, address borrower, uint256 soldAmount, uint256 loanStartTime); event BuyMarketNFT(uint256 lienId, uint256 tokenId, uint256 paidAmount); event SwapWithETH(uint256 lienId, address borrower, uint256 loanStartTime); event RepayWithNFT(uint256 lienId, uint256 tokenId); event Refinance(uint256 oldLienId, uint256 newLienId, uint256 loanStartTime); event OfferBid(uint256 lienId, address borrower, address collection, uint256 margin, uint256 price, uint256 rate); event UpdateBid(uint256 lienId, uint256 margin, uint256 price, uint256 rate); event CancelBid(uint256 lienId); event AcceptBid(uint256 lienId, address lender, uint256 tokenId, uint256 soldAmount, uint256 loanStartTime); event StartAuction(uint256 lienId, uint256 auctionStartTime); event StopAuction(uint256 lienId); event AuctionSellNFT(uint256 lienId, address supplier, uint256 tokenId, uint256 paidAmount); event AccrueInterest(address account, uint256 amount); event WithdrawAccountBalance(address account, uint256 amount); event UpdateTreasuryRate(uint256 rate); event WithdrawTreasury(address receiver, uint256 amount); event RegisterMarketplace(address marketplace); event UnregisterMarketplace(address marketplace); /*============================================================== Supply Logic ==============================================================*/ /** * @notice Supply an NFT to contract * @param collection The address to the NFT collection * @param tokenId The ID of the NFT being supplied * @param price The supplier specified price for NFT * @param rate The supplier specified interest rate * @return lienId newly generated lienId */ function supplyNft( address collection, uint256 tokenId, uint256 price, uint256 rate ) external returns (uint256 lienId); /** * @notice Update Loan parameters * @param lien Reconstructed lien info * @param lienId The ID for the existing lien * @param price The supplier specified new price for NFT * @param rate The supplier specified new interest rate */ function updateLoan(Lien calldata lien, uint256 lienId, uint256 price, uint256 rate) external; /*============================================================== Withdraw Logic ==============================================================*/ /** * @notice Withdraw NFT from the contract * @param lien Reconstructed lien info * @param lienId The ID for the lien being cleared */ function withdrawNft(Lien calldata lien, uint256 lienId) external; /** * @notice Withdraw ETH from the contract * @param lien Reconstructed lien info * @param lienId The ID for the lien being cleared */ function withdrawEth(Lien calldata lien, uint256 lienId) external; /** * @notice Withdraw account balance of the message sender account */ function withdrawAccountBalance() external; /*============================================================== Trading Logic ==============================================================*/ /** * @notice Pull-based sell NFT to market (another contract initiates NFT transfer) * @param lien Reconstructed lien info * @param lienId The lien ID * @param amount Declared ETH amount for NFT sale * @param marketplace The contract address of the marketplace (e.g. Seaport Proxy Router) * @param puller The contract address that executes the pull operation (e.g. Seaport Conduit) * @param tradeData The trade execution bytes on the marketplace */ function sellNftToMarketPull( Lien calldata lien, uint256 lienId, uint256 amount, address marketplace, address puller, bytes calldata tradeData ) external payable; /** * @notice Push-based sell NFT to market (this contract initiates NFT transfer) * @param lien Reconstructed lien info * @param lienId The lien ID * @param amount Declared ETH amount for NFT sale * @param marketplace The contract address of the marketplace * @param tradeData The trade execution bytes to route to the marketplace */ function sellNftToMarketPush( Lien calldata lien, uint256 lienId, uint256 amount, address marketplace, bytes calldata tradeData ) external payable; /** * @notice Buy NFT from market * @param lien Reconstructed lien info * @param lienId The lien ID * @param tokenId The ID of the NFT being bought * @param amount Declared ETH amount for NFT purchase * @param spender The spender address to approve WETH spending, zero address to use ETH * @param marketplace The address of the marketplace * @param tradeData The trade execution bytes on the marketplace */ function buyNftFromMarket( Lien calldata lien, uint256 lienId, uint256 tokenId, uint256 amount, address spender, address marketplace, bytes calldata tradeData ) external; /** * @notice Swap NFT with ETH * @param lien Reconstructed lien info * @param lienId The lien ID */ function swapWithEth(Lien calldata lien, uint256 lienId) external payable; /** * @notice Repay loan with NFT * @param lien Reconstructed lien info * @param lienId The lien ID * @param tokenId The ID of the NFT being used to repay the loan */ function repayWithNft(Lien calldata lien, uint256 lienId, uint256 tokenId) external; /** * @notice Refinance an existing loan with a new one * @param oldLien Reconstructed old lien info * @param oldLienId The ID for the existing lien * @param newLien Reconstructed new lien info * @param newLienId The ID for the new lien */ function refinanceLoan( Lien calldata oldLien, uint256 oldLienId, Lien calldata newLien, uint256 newLienId ) external payable; /*============================================================== Bid Logic ==============================================================*/ /** * @notice Trader offers a bid for loan * @param collection The address to the NFT collection * @param margin Margin to use, should satisfy: margin <= msg.value + accountBalance[msg.sender] * @param price Bade desired price for NFT supplier * @param rate Bade interest rate for NFT supplier * @return lienId newly generated lienId */ function offerBid( address collection, uint256 margin, uint256 price, uint256 rate ) external payable returns (uint256 lienId); /** * @notice Trader offers a bid for loan * @param lien Reconstructed lien info * @param lienId The lien ID * @param margin Margin to use, should satisfy: margin <= msg.value + accountBalance[msg.sender] * @param price Bade desired price for NFT supplier * @param rate Bade interest rate for NFT supplier */ function updateBid( Lien calldata lien, uint256 lienId, uint256 margin, uint256 price, uint256 rate ) external payable; /** * @notice Trader cancels a opened bid (not yet accepted) * @param lien Reconstructed lien info * @param lienId The lien ID */ function cancelBid(Lien calldata lien, uint256 lienId) external; /** * @notice Supplier accepts a bid by supplying an NFT and pull-based sell to market * @param lien Reconstructed lien info * @param lienId The lien ID * @param tokenId The ID of the NFT being supplied * @param amount Declared ETH amount for NFT sale * @param marketplace The address of the marketplace (e.g. Seaport Proxy Router) * @param puller The contract address that executes the pull operation (e.g. Seaport Conduit) * @param tradeData The trade execution bytes on the marketplace */ function acceptBidSellNftToMarketPull( Lien calldata lien, uint256 lienId, uint256 tokenId, uint256 amount, address marketplace, address puller, bytes calldata tradeData ) external; /** * @notice Supplier accepts a bid by supplying an NFT and push-based sell to market * @param lien Reconstructed lien info * @param lienId The lien ID * @param tokenId The ID of the NFT being supplied * @param amount Declared ETH amount for NFT sale * @param marketplace The address of the marketplace * @param tradeData The trade execution bytes on the marketplace */ function acceptBidSellNftToMarketPush( Lien calldata lien, uint256 lienId, uint256 tokenId, uint256 amount, address marketplace, bytes calldata tradeData ) external; /*============================================================== Auction Logic ==============================================================*/ /** * @notice Start auction for a loan * @param lien Reconstructed lien info * @param lienId The lien ID */ function startLoanAuction(Lien calldata lien, uint256 lienId) external; /** * @notice Stop an auction for a loan * @param lien Reconstructed lien info * @param lienId The lien ID */ function stopLoanAuction(Lien calldata lien, uint256 lienId) external; /** * @notice Buy NFT from auction * @param lien Reconstructed lien info * @param lienId The lien ID * @param tokenId The ID of the NFT being bought */ function auctionSellNft(Lien calldata lien, uint256 lienId, uint256 tokenId) external; /*============================================================== Admin Logic ==============================================================*/ /** * @notice Register a trusted marketplace address * @param marketplace The address of the marketplace */ function registerMarketplace(address marketplace) external; /** * @notice Unregister a marketplace address * @param marketplace The address of the marketplace */ function unregisterMarketplace(address marketplace) external; /** * @notice Update treasury rate * @param rate The treasury rate in bips */ function setTreasuryRate(uint256 rate) external; /** * @notice Withdraw treasury balance * @param receiver The address to receive the treasury balance */ function withdrawTreasury(address receiver) external; }
// SPDX-License-Identifier: MIT // Adopted from OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) pragma solidity 0.8.19; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } function isEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; library MathUtils { uint256 private constant _BASIS_POINTS = 10_000; /** * @dev Calculate the current interest linearly accrued since the loan start time. * @param principal The principal amount of the loan in WEI * @param rateBips The yearly interest rate of the loan in bips * @param loanStartTime The timestamp at which this loan is opened * @return interest The current interest in WEI */ function calculateCurrentInterest( uint256 principal, uint256 rateBips, uint256 loanStartTime ) external view returns (uint256 interest) { interest = (principal * rateBips * (block.timestamp - loanStartTime)) / (_BASIS_POINTS * 365 days); } /** * @dev Calculates the current allowed auction price (increases linearly in time) * @param price The max auction buy price in WEI * @param auctionElapsed The current elapsed auction time * @param auctionDuration The block span for the auction * @return currentAuctionPrice Current allowed auction price in WEI */ function calculateCurrentAuctionPrice( uint256 price, uint256 auctionElapsed, uint256 auctionDuration ) external pure returns (uint256 currentAuctionPrice) { uint256 auctionPortion = auctionElapsed > auctionDuration ? auctionDuration : auctionElapsed; currentAuctionPrice = (price * auctionPortion) / auctionDuration; } /** * @dev Calculates the proportion that goes into treasury * @param interest total interest accrued in WEI * @param portionBips The treasury proportion in bips * @return treasuryAmount Amount goes into treasury in WEI */ function calculateTreasuryProportion( uint256 interest, uint256 portionBips ) external pure returns (uint256 treasuryAmount) { treasuryAmount = (interest * portionBips) / _BASIS_POINTS; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; struct Lien { address lender; // NFT supplier address address borrower; // NFT trade executor address address collection; // NFT collection address uint256 tokenId; /// NFT ID (@dev: at borrower bidding, this field is used to store margin) uint256 price; // NFT supplier's desired sold price uint256 rate; // APR in bips, _BASIS_POINTS defined in MathUtils.sol uint256 loanStartTime; // loan start block.timestamp uint256 auctionStartTime; // auction start block.timestamp }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; library Errors { error Unauthorized(); error UnregisteredMarketplace(); error InvalidParameters(); error InvalidLien(); error LoanStarted(); error InactiveLoan(); error LiquidationHasNotReached(); error MartketplaceFailedToTrade(); error InvalidNFTSell(); error InvalidNFTBuy(); error NFTNotReceived(); error Overspend(); error UnmatchedCollections(); error BidTaken(); error BidNotTaken(); error AuctionStarted(); error AuctionNotStarted(); error AuctionEndTooSoon(); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822ProxiableUpgradeable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.3) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeaconUpgradeable.sol"; import "../../interfaces/IERC1967Upgradeable.sol"; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/StorageSlotUpgradeable.sol"; import "../utils/Initializable.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable { function __ERC1967Upgrade_init() internal onlyInitializing { } function __ERC1967Upgrade_init_unchained() internal onlyInitializing { } // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { _functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); } } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function _functionDelegateCall(address target, bytes memory data) private returns (bytes memory) { require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed"); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; 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 proxied contracts do not make use of 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. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * 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 prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (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 { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { 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); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.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); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeaconUpgradeable { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.3) (interfaces/IERC1967.sol) pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * * _Available since v4.9._ */ interface IERC1967Upgradeable { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://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 functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlotUpgradeable { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
// 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 { } 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; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// 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); }
{ "remappings": [ "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@solmate/=lib/solmate/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": { "contracts/libraries/math/MathUtils.sol": { "MathUtils": "0x55a4dc1f67003756a438bd6626b14a536734e5c7" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"wethAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AuctionEndTooSoon","type":"error"},{"inputs":[],"name":"AuctionNotStarted","type":"error"},{"inputs":[],"name":"AuctionStarted","type":"error"},{"inputs":[],"name":"BidNotTaken","type":"error"},{"inputs":[],"name":"BidTaken","type":"error"},{"inputs":[],"name":"InactiveLoan","type":"error"},{"inputs":[],"name":"InvalidLien","type":"error"},{"inputs":[],"name":"InvalidNFTBuy","type":"error"},{"inputs":[],"name":"InvalidNFTSell","type":"error"},{"inputs":[],"name":"InvalidParameters","type":"error"},{"inputs":[],"name":"LiquidationHasNotReached","type":"error"},{"inputs":[],"name":"LoanStarted","type":"error"},{"inputs":[],"name":"MartketplaceFailedToTrade","type":"error"},{"inputs":[],"name":"NFTNotReceived","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnmatchedCollections","type":"error"},{"inputs":[],"name":"UnregisteredMarketplace","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"soldAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loanStartTime","type":"uint256"}],"name":"AcceptBid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AccrueInterest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"address","name":"supplier","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paidAmount","type":"uint256"}],"name":"AuctionSellNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paidAmount","type":"uint256"}],"name":"BuyMarketNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"CancelBid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint256","name":"margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"OfferBid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLienId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLienId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loanStartTime","type":"uint256"}],"name":"Refinance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"marketplace","type":"address"}],"name":"RegisterMarketplace","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"RepayWithNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"soldAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loanStartTime","type":"uint256"}],"name":"SellMarketNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"name":"StartAuction","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"StopAuction","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"SupplyNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"loanStartTime","type":"uint256"}],"name":"SwapWithETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"marketplace","type":"address"}],"name":"UnregisterMarketplace","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"UpdateBid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"UpdateLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"UpdateTreasuryRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawAccountBalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"WithdrawETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"WithdrawNFT","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawTreasury","type":"event"},{"inputs":[],"name":"WETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"address","name":"puller","type":"address"},{"internalType":"bytes","name":"tradeData","type":"bytes"}],"name":"acceptBidSellNftToMarketPull","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"bytes","name":"tradeData","type":"bytes"}],"name":"acceptBidSellNftToMarketPush","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accountBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"auctionSellNft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"bytes","name":"tradeData","type":"bytes"}],"name":"buyNftFromMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"cancelBid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"liens","outputs":[{"internalType":"bytes32","name":"lienHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"offerBid","outputs":[{"internalType":"uint256","name":"lienId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"oldLien","type":"tuple"},{"internalType":"uint256","name":"oldLienId","type":"uint256"},{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"newLien","type":"tuple"},{"internalType":"uint256","name":"newLienId","type":"uint256"}],"name":"refinanceLoan","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"marketplace","type":"address"}],"name":"registerMarketplace","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"marketplace","type":"address"}],"name":"registeredMarketplaces","outputs":[{"internalType":"bool","name":"registered","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"repayWithNft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"address","name":"puller","type":"address"},{"internalType":"bytes","name":"tradeData","type":"bytes"}],"name":"sellNftToMarketPull","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"bytes","name":"tradeData","type":"bytes"}],"name":"sellNftToMarketPush","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"setTreasuryRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"startLoanAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"stopLoanAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"supplyNft","outputs":[{"internalType":"uint256","name":"lienId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"swapWithEth","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"marketplace","type":"address"}],"name":"unregisterMarketplace","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"updateBid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"updateLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdrawAccountBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"withdrawEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"loanStartTime","type":"uint256"},{"internalType":"uint256","name":"auctionStartTime","type":"uint256"}],"internalType":"struct Lien","name":"lien","type":"tuple"},{"internalType":"uint256","name":"lienId","type":"uint256"}],"name":"withdrawNft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"withdrawTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60c0604052306080523480156200001557600080fd5b50604051620055733803806200557383398101604081905262000038916200011d565b600160fb556001600160a01b03811660a052620000546200005b565b506200014f565b600054610100900460ff1615620000c85760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156200011b576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200013057600080fd5b81516001600160a01b03811681146200014857600080fd5b9392505050565b60805160a0516153aa620001c96000396000818161025b01528181613bf401528181613ce301528181613d7801528181613e8201528181613f13015281816143b70152818161445201526144e3015260008181610d7a01528181610dc3015281816113150152818161135501526113e801526153aa6000f3fe60806040526004361061021e5760003560e01c806379ba509711610123578063bde938cb116100ab578063e6200dc21161006f578063e6200dc21461063d578063ea9cf4be14610652578063f2fde38b14610665578063f86c9e9a14610685578063f8887546146106a557600080fd5b8063bde938cb14610584578063c63f6052146105a4578063d0bf9c54146105d1578063d294cb0f146105f1578063e30c39781461061f57600080fd5b8063838a61f9116100f2578063838a61f9146104c5578063871ba096146104e55780638da5cb5b14610526578063a88acabd14610544578063aa3296de1461056457600080fd5b806379ba5097146104685780637f898fa01461047d5780638077ec661461049d5780638129fc1c146104b057600080fd5b80634489961a116101a6578063564d200a11610175578063564d200a146103ed5780636d8c39e414610400578063715018a61461042057806377fa66561461043557806379942ba61461044857600080fd5b80634489961a1461039257806344ef1390146103b25780634f1ef286146103c557806352d1902d146103d857600080fd5b8063335d0e13116101ed578063335d0e13146102f15780633390f7111461031f57806333b9aa231461033f5780633659cfe61461035f5780633692aae41461037f57600080fd5b806302bfb2c81461022a578063040141e51461024c578063150b7a02146102985780632a130bf2146102d157600080fd5b3661022557005b600080fd5b34801561023657600080fd5b5061024a6102453660046148cd565b6106c5565b005b34801561025857600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102a457600080fd5b506102b86102b3366004614972565b6107e4565b6040516001600160e01b0319909116815260200161028f565b3480156102dd57600080fd5b5061024a6102ec3660046149e5565b610814565b3480156102fd57600080fd5b5061031161030c366004614a70565b61097e565b60405190815260200161028f565b34801561032b57600080fd5b5061024a61033a366004614aab565b610a0c565b34801561034b57600080fd5b5061024a61035a366004614ad8565b610b88565b34801561036b57600080fd5b5061024a61037a366004614b16565b610d70565b61024a61038d366004614aab565b610e58565b34801561039e57600080fd5b5061024a6103ad366004614b16565b611085565b61024a6103c0366004614b33565b6110e6565b61024a6103d3366004614c1e565b61130b565b3480156103e457600080fd5b506103116113db565b61024a6103fb366004614c6e565b61148e565b34801561040c57600080fd5b5061024a61041b366004614cee565b61156d565b34801561042c57600080fd5b5061024a611878565b61024a610443366004614d8c565b61188c565b34801561045457600080fd5b5061024a610463366004614aab565b611cc7565b34801561047457600080fd5b5061024a611ea2565b34801561048957600080fd5b5061024a6104983660046148cd565b611f19565b61024a6104ab366004614dd6565b611ff5565b3480156104bc57600080fd5b5061024a6120c1565b3480156104d157600080fd5b5061024a6104e0366004614aab565b6121d3565b3480156104f157600080fd5b50610516610500366004614b16565b6101016020526000908152604090205460ff1681565b604051901515815260200161028f565b34801561053257600080fd5b506033546001600160a01b031661027b565b34801561055057600080fd5b5061024a61055f366004614cee565b61234a565b34801561057057600080fd5b5061024a61057f366004614aab565b6124aa565b34801561059057600080fd5b5061024a61059f366004614b16565b61260f565b3480156105b057600080fd5b506103116105bf366004614e2e565b60ff6020526000908152604090205481565b3480156105dd57600080fd5b5061024a6105ec366004614e2e565b61266c565b3480156105fd57600080fd5b5061031161060c366004614b16565b6101006020526000908152604090205481565b34801561062b57600080fd5b506065546001600160a01b031661027b565b34801561064957600080fd5b5061024a6126cc565b610311610660366004614a70565b612753565b34801561067157600080fd5b5061024a610680366004614b16565b6128a7565b34801561069157600080fd5b5061024a6106a0366004614b16565b612918565b3480156106b157600080fd5b5061024a6106c0366004614aab565b6129ae565b8282816040516020016106d89190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461071b57604051636946eab760e01b815260040160405180910390fd5b610723612b97565b8460e00135600003610748576040516301dff5d560e71b815260040160405180910390fd5b61076261075a36879003870187614f76565b858533612bf0565b6107726060860160408701614b16565b6001600160a01b03166323b872dd3330866040518463ffffffff1660e01b81526004016107a193929190614f93565b600060405180830381600087803b1580156107bb57600080fd5b505af11580156107cf573d6000803e3d6000fd5b505050506107dd600160fb55565b5050505050565b60006107f260fb5460021490565b6108025761080285858585612e9e565b50630a85bd0160e11b95945050505050565b8686816040516020016108279190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461086a57604051636946eab760e01b815260040160405180910390fd5b610872612b97565b61088a610884368b90038b018b614f76565b876131cd565b6108a561089c368b90038b018b614f76565b8989893361324c565b6108b560608a0160408b01614b16565b6001600160a01b03166323b872dd33308a6040518463ffffffff1660e01b81526004016108e493929190614f93565b600060405180830381600087803b1580156108fe57600080fd5b505af1158015610912573d6000803e3d6000fd5b505050506109698980360381019061092a9190614f76565b88888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061333f92505050565b610973600160fb55565b505050505050505050565b6000610988612b97565b61099533868686866133c0565b6040516323b872dd60e01b81529091506001600160a01b038616906323b872dd906109c890339030908990600401614f93565b600060405180830381600087803b1580156109e257600080fd5b505af11580156109f6573d6000803e3d6000fd5b50505050610a04600160fb55565b949350505050565b818181604051602001610a1f9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610a6257604051636946eab760e01b815260040160405180910390fd5b610a6a612b97565b610a776020850185614b16565b6001600160a01b0316336001600160a01b031614610aa7576040516282b42960e81b815260040160405180910390fd5b8360c00135600003610acc576040516367bec58d60e01b815260040160405180910390fd5b60e08401351580610aed5750610ae96201fa4060e0860135614fcd565b4211155b15610b0b57604051633f3db73560e21b815260040160405180910390fd5b600083815260ff60209081526040822091909155610b4490608086013590610b3590870187614b16565b6001600160a01b031690613503565b6040518381527f94effa14ea3a1ef396fa2fd829336d1597f1d76b548c26bfa2332869706638af906020015b60405180910390a1610b82600160fb55565b50505050565b838381604051602001610b9b9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610bde57604051636946eab760e01b815260040160405180910390fd5b610be6612b97565b610bf36020870187614b16565b6001600160a01b0316336001600160a01b031614610c23576040516282b42960e81b815260040160405180910390fd5b60c086013515610c465760405163577d3ffb60e01b815260040160405180910390fd5b683635c9adc5dea00000841180610c5f5750620186a083115b15610c7d57604051630e52390960e41b815260040160405180910390fd5b60408051610100810190915280610c976020890189614b16565b6001600160a01b0316815260006020820152604090810190610cbf9060608a01908a01614b16565b6001600160a01b0316815260200187606001358152602001858152602001848152602001600081526020016000815250604051602001610cff9190614fe0565b60408051808303601f190181528282528051602091820120600089815260ff835283902055878352820186905281018490527f27a96079a4426127077f0e9053dceae2d9a50ad31109773b6cbef3683af0900b9060600160405180910390a1610d68600160fb55565b505050505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610dc15760405162461bcd60e51b8152600401610db890615047565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610e0a60008051602061532e833981519152546001600160a01b031690565b6001600160a01b031614610e305760405162461bcd60e51b8152600401610db890615093565b610e3981613621565b60408051600080825260208201909252610e5591839190613629565b50565b818181604051602001610e6b9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610eae57604051636946eab760e01b815260040160405180910390fd5b610eb6612b97565b60c084013515610ed95760405163577d3ffb60e01b815260040160405180910390fd5b6000610ee86020860186614b16565b6001600160a01b031603610f0f57604051630eb2e98f60e31b815260040160405180910390fd5b610f1e33856080013534613794565b60408051610100810190915280610f386020870187614b16565b6001600160a01b03168152336020820152604090810190610f5f9060608801908801614b16565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020014281526020016000815250604051602001610fa69190614fe0565b60408051601f198184030181529181528151602092830120600086815260ff9093529181902091909155610fe09060608601908601614b16565b6001600160a01b03166342842e0e303387606001356040518463ffffffff1660e01b815260040161101393929190614f93565b600060405180830381600087803b15801561102d57600080fd5b505af1158015611041573d6000803e3d6000fd5b50506040805186815233602082015242918101919091527f7018ea7d1ccfe49000acdb52059c03871a92ffb8da722f9b785ec81866cf00b892506060019050610b70565b61108d61381f565b6001600160a01b03811660008181526101016020908152604091829020805460ff1916905590519182527fda68a0228a216daf1cfe2cbce9d172fc0d4a0181f04518aafae1cb2f8e638dee91015b60405180910390a150565b8484816040516020016110f99190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461113c57604051636946eab760e01b815260040160405180910390fd5b611144612b97565b6111546040880160208901614b16565b6001600160a01b0316336001600160a01b031614611184576040516282b42960e81b815260040160405180910390fd5b60006111936020890189614b16565b6001600160a01b0316146111ba57604051633c10be4b60e21b815260040160405180910390fd5b683635c9adc5dea000008411806111d35750620186a083115b156111f157604051630e52390960e41b815260040160405180910390fd5b61120933866112043460608c0135614fcd565b613794565b60405180610100016040528060006001600160a01b031681526020018860200160208101906112389190614b16565b6001600160a01b0316815260200161125660608a0160408b01614b16565b6001600160a01b031681526020018681526020018581526020018481526020016000815260200160008152506040516020016112929190614fe0565b60408051808303601f19018152828252805160209182012060008a815260ff83528390205588835282018790528101859052606081018490527f699d32d6654f5041063117eee3b5e6d16b2af3e2c78347aabf2a48f0db5df84f9060800160405180910390a1611302600160fb55565b50505050505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036113535760405162461bcd60e51b8152600401610db890615047565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031661139c60008051602061532e833981519152546001600160a01b031690565b6001600160a01b0316146113c25760405162461bcd60e51b8152600401610db890615093565b6113cb82613621565b6113d782826001613629565b5050565b6000306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461147b5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610db8565b5060008051602061532e83398151915290565b8585816040516020016114a19190614e47565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146114e457604051636946eab760e01b815260040160405180910390fd5b6114ec612b97565b6114f888873334613879565b611504888888336138e5565b611559611516368a90038a018a614f76565b8960600135888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061333f92505050565b611563600160fb55565b5050505050505050565b8787816040516020016115809190614e47565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146115c357604051636946eab760e01b815260040160405180910390fd5b6115cb612b97565b6115db60408b0160208c01614b16565b6001600160a01b0316336001600160a01b03161461160b576040516282b42960e81b815260040160405180910390fd5b8960c00135600003611630576040516367bec58d60e01b815260040160405180910390fd5b6040516316147d4d60e31b815260808b0135600482015260a08b0135602482015260c08b013560448201526000907355a4dc1f67003756a438bd6626b14a536734e5c79063b0a3ea6890606401602060405180830381865af415801561169a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116be91906150df565b90506000816116d18a60808f01356150f8565b6116db91906150f8565b90506116f36116ed60208e018e614b16565b836139ea565b8015611747578061010060008e60200160208101906117129190614b16565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546117419190614fcd565b90915550505b6040805161010081019091528061176160208f018f614b16565b6001600160a01b0316815260200160006001600160a01b031681526020018d60400160208101906117929190614b16565b6001600160a01b031681526020018b81526020018d6080013581526020018d60a0013581526020016000815260200160008152506040516020016117d69190614fe0565b60408051601f19818403018152918152815160209283012060008e815260ff909352918190209190915561181f906118149060608f01908f01614b16565b8b8b8b8b8b8b613b0e565b604080518c8152602081018c90529081018a90527fac76107e19044e50d0526f5983962056aff4f8d4a4bb07a3730e609dc3cf9d129060600160405180910390a1505061186c600160fb55565b50505050505050505050565b61188061381f565b61188a6000614038565b565b83838160405160200161189f9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146118e257604051636946eab760e01b815260040160405180910390fd5b8383816040516020016118f59190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461193857604051636946eab760e01b815260040160405180910390fd5b611940612b97565b6119506040890160208a01614b16565b6001600160a01b0316336001600160a01b031614611980576040516282b42960e81b815260040160405180910390fd5b8760c001356000036119a5576040516367bec58d60e01b815260040160405180910390fd5b60c0860135156119c85760405163577d3ffb60e01b815260040160405180910390fd5b60006119d76020880188614b16565b6001600160a01b0316036119fe57604051630eb2e98f60e31b815260040160405180910390fd5b611a0e6060870160408801614b16565b6001600160a01b0316611a2760608a0160408b01614b16565b6001600160a01b031614611a4e576040516352bbeac560e01b815260040160405180910390fd5b6040516316147d4d60e31b81526080890135600482015260a0890135602482015260c089013560448201526000907355a4dc1f67003756a438bd6626b14a536734e5c79063b0a3ea6890606401602060405180830381865af4158015611ab8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adc91906150df565b9050611afe33611af08360808b0135614fcd565b6112043460808e0135614fcd565b611b14611b0e60208b018b614b16565b826139ea565b60408051610100810190915280611b2e60208c018c614b16565b6001600160a01b0316815260006020820152604090810190611b569060608d01908d01614b16565b6001600160a01b03168152602001886060013581526020018a6080013581526020018a60a001358152602001600081526020016000815250604051602001611b9e9190614fe0565b60408051601f19818403018152828252805160209182012060008c815260ff83528390205561010083019091528190611bd9908a018a614b16565b6001600160a01b031681526020018a6020016020810190611bfa9190614b16565b6001600160a01b03168152602001611c1860608a0160408b01614b16565b6001600160a01b0316815260200188606001358152602001886080013581526020018860a0013581526020014281526020016000815250604051602001611c5f9190614fe0565b60408051601f19818403018152828252805160209182012060008a815260ff8352839020558a835282018890524282820152517fabdbeebdc0a5c123625afdabd45e1c7cb5193d257ae81f27aa8f9865e0b867fc9181900360600190a150611563600160fb55565b818181604051602001611cda9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414611d1d57604051636946eab760e01b815260040160405180910390fd5b611d25612b97565b611d326020850185614b16565b6001600160a01b0316336001600160a01b031614611d62576040516282b42960e81b815260040160405180910390fd5b8360c00135600003611d87576040516367bec58d60e01b815260040160405180910390fd5b60e084013515611daa5760405163647ccdcd60e11b815260040160405180910390fd5b60408051610100810190915280611dc46020870187614b16565b6001600160a01b03168152602001856020016020810190611de59190614b16565b6001600160a01b03168152602001611e036060870160408801614b16565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020018560c00135815260200142815250604051602001611e4d9190614fe0565b60408051808303601f190181528282528051602091820120600087815260ff83528390205585835242908301527f8b31d3b4bc191b98ddfb3298ea923ba81c7121b9d7169f47a2cf1079c7010acf9101610b70565b60655433906001600160a01b03168114611f105760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610db8565b610e5581614038565b828281604051602001611f2c9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414611f6f57604051636946eab760e01b815260040160405180910390fd5b611f77612b97565b611f876040860160208701614b16565b6001600160a01b0316336001600160a01b031614611fb7576040516282b42960e81b815260040160405180910390fd5b8460c00135600003611fdc576040516367bec58d60e01b815260040160405180910390fd5b610762611fee36879003870187614f76565b8585614051565b8686816040516020016120089190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461204b57604051636946eab760e01b815260040160405180910390fd5b612053612b97565b61205f89883334613879565b61206b898989336138e5565b61096961207d368b90038b018b614f76565b8a6060013589898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061421392505050565b600054610100900460ff16158080156120e15750600054600160ff909116105b806120fb5750303b1580156120fb575060005460ff166001145b61215e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610db8565b6000805460ff191660011790558015612181576000805461ff0019166101001790555b612189614312565b612191614339565b8015610e55576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016110db565b8181816040516020016121e69190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461222957604051636946eab760e01b815260040160405180910390fd5b612231612b97565b61223e6020850185614b16565b6001600160a01b0316336001600160a01b03161461226e576040516282b42960e81b815260040160405180910390fd5b60c0840135156122915760405163577d3ffb60e01b815260040160405180910390fd5b600083815260ff6020526040808220919091556122b49060608601908601614b16565b6001600160a01b03166323b872dd303387606001356040518463ffffffff1660e01b81526004016122e793929190614f93565b600060405180830381600087803b15801561230157600080fd5b505af1158015612315573d6000803e3d6000fd5b505050507fd18ab7eec3067b4a8e15f1c1f5299c77c05218c5718857eae55ac13c190f287583604051610b7091815260200190565b87878160405160200161235d9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146123a057604051636946eab760e01b815260040160405180910390fd5b6123a8612b97565b6123c06123ba368c90038c018c614f76565b886131cd565b6123db6123d2368c90038c018c614f76565b8a8a8a3361324c565b6123eb60608b0160408c01614b16565b6001600160a01b03166323b872dd33308b6040518463ffffffff1660e01b815260040161241a93929190614f93565b600060405180830381600087803b15801561243457600080fd5b505af1158015612448573d6000803e3d6000fd5b505050506124a08a8036038101906124609190614f76565b8989898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061421392505050565b61186c600160fb55565b8181816040516020016124bd9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461250057604051636946eab760e01b815260040160405180910390fd5b612508612b97565b6125186040850160208601614b16565b6001600160a01b0316336001600160a01b031614612548576040516282b42960e81b815260040160405180910390fd5b60006125576020860186614b16565b6001600160a01b03161461257e57604051633c10be4b60e21b815260040160405180910390fd5b606084013561010060006125986040880160208901614b16565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546125c79190614fcd565b9091555050600083815260ff602052604080822091909155517f7687efe94566d20f7ebb8eff43bb57b2c014749dfd9ad179089e58c338ecdfa790610b709085815260200190565b61261761381f565b6001600160a01b03811660008181526101016020908152604091829020805460ff1916600117905590519182527f9d26696f1250d555e1136fcc68cc61c008bfdbc4edc53223e9e87ee94c530df591016110db565b61267461381f565b6103e881111561269757604051630e52390960e41b815260040160405180910390fd5b60fd8190556040518181527f2f1e1f4c9db00c1f5b9f1fb7b358f5beb59f9d4f72b9ba22a03240abf2344946906020016110db565b6126d4612b97565b3360009081526101006020526040812054908190036126f35750612749565b336000818152610100602052604081205561270e9082613503565b60408051338152602081018390527f3efd984b5a13f92c04233a1e4a17098601b9effd13622786eab024424b9a4b02910160405180910390a1505b61188a600160fb55565b600061275d612b97565b683635c9adc5dea000008311806127765750620186a082115b1561279457604051630e52390960e41b815260040160405180910390fd5b61279f338534613794565b600060405180610100016040528060006001600160a01b03168152602001336001600160a01b03168152602001876001600160a01b0316815260200186815260200185815260200184815260200160008152602001600081525090508060405160200161280c9190614fe0565b60408051601f19818403018152828252805160209182012060fc805460018101909155600081815260ff84528490209190915580845233918401919091526001600160a01b03891683830152606083018890526080830187905260a0830186905290519093507f6386159f9aeea426c15aaec24295e5deef70a311ffe87a52fe8c875acc9941519181900360c00190a150610a04600160fb55565b6128af61381f565b606580546001600160a01b0383166001600160a01b031990911681179091556128e06033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b61292061381f565b60fe5480156113d7576001600160a01b03821661295057604051630e52390960e41b815260040160405180910390fd5b600060fe556129686001600160a01b03831682613503565b604080516001600160a01b0384168152602081018390527f905d2a9b2639a94f09720cfd7b061c3b7a9e27921a009e954d67c8aff6e73667910160405180910390a15050565b8181816040516020016129c19190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414612a0457604051636946eab760e01b815260040160405180910390fd5b612a0c612b97565b612a196020850185614b16565b6001600160a01b0316336001600160a01b031614612a49576040516282b42960e81b815260040160405180910390fd5b8360e00135600003612a6e576040516301dff5d560e71b815260040160405180910390fd5b612a7e610e1060e0860135614fcd565b421015612a9e5760405163b882dff360e01b815260040160405180910390fd5b60408051610100810190915280612ab86020870187614b16565b6001600160a01b03168152602001856020016020810190612ad99190614b16565b6001600160a01b03168152602001612af76060870160408801614b16565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020018560c0013581526020016000815250604051602001612b429190614fe0565b60408051601f198184030181528282528051602091820120600087815260ff909252919020557f35dd1796423ce8f6a16296e4b6f10f75f26bc954cbb4014ae929416d0476abac90610b709085815260200190565b600260fb5403612be95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610db8565b600260fb55565b608084015160a085015160c08601516040516316147d4d60e31b81526000937355a4dc1f67003756a438bd6626b14a536734e5c79363b0a3ea6893612c48936004019283526020830191909152604082015260600190565b602060405180830381865af4158015612c65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8991906150df565b905060007355a4dc1f67003756a438bd6626b14a536734e5c763b87a5ded838860800151612cb791906150f8565b60e0890151612cc690426150f8565b6040516001600160e01b031960e085901b168152600481019290925260248201526201fa406044820152606401602060405180830381865af4158015612d10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d3491906150df565b9050600082828860800151612d4991906150f8565b612d5391906150f8565b90508015612d8f576020808801516001600160a01b03166000908152610100909152604081208054839290612d89908490614fcd565b90915550505b612da26001600160a01b03851683613503565b8651612dae90846139ea565b60405180610100016040528088600001516001600160a01b0316815260200160006001600160a01b0316815260200188604001516001600160a01b03168152602001868152602001886080015181526020018860a001518152602001600081526020016000815250604051602001612e269190614fe0565b60408051808303601f19018152828252805160209182012060008a815260ff8352839020558883526001600160a01b038716908301528101869052606081018390527fdd79deab13d35b6c83e88ee7f630110a06d72c9b0d6532310060518dce8946169060800160405180910390a150505050505050565b612ea6612b97565b6040516331a9108f60e11b81526004810184905230903390636352211e90602401602060405180830381865afa158015612ee4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f08919061510b565b6001600160a01b031614612f2f57604051634f95e6e560e01b815260040160405180910390fd5b6040819003612f6057600080612f4783850185615128565b91509150612f5886338785856133c0565b5050506131c3565b61012081900361309157600080612f798385018561514a565b9150915081604051602001612f8e9190614fe0565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414612fd157604051636946eab760e01b815260040160405180910390fd5b81604001516001600160a01b0316336001600160a01b031614613007576040516352bbeac560e01b815260040160405180910390fd5b81602001516001600160a01b0316866001600160a01b031603613059578160c00151600003613049576040516367bec58d60e01b815260040160405180910390fd5b613054828287614051565b61308a565b8160e0015160000361307e576040516301dff5d560e71b815260040160405180910390fd5b61308a82828789612bf0565b50506131c3565b61018081106131aa57600080808080806130ad87890189615168565b955095509550955095509550856040516020016130ca9190614fe0565b60408051601f198184030181529181528151602092830120600088815260ff9093529120541461310d57604051636946eab760e01b815260040160405180910390fd5b85604001516001600160a01b0316336001600160a01b031614613143576040516352bbeac560e01b815260040160405180910390fd5b6001600160a01b03821661317a5761315b86856131cd565b61316886868b878e61324c565b613175868a86868561333f565b61319f565b61318486856131cd565b61319186868b878e61324c565b61319f868a86868686614213565b5050505050506131c3565b604051630e52390960e41b815260040160405180910390fd5b610b82600160fb55565b81516001600160a01b0316156131f657604051633c10be4b60e21b815260040160405180910390fd5b816080015181836060015161320b9190614fcd565b61321591906150f8565b6020808401516001600160a01b03166000908152610100909152604081208054909190613243908490614fcd565b90915550505050565b604051806101000160405280826001600160a01b0316815260200186602001516001600160a01b0316815260200186604001516001600160a01b03168152602001848152602001866080015181526020018660a00151815260200142815260200160008152506040516020016132c29190614fe0565b60408051808303601f190181528282528051602091820120600088815260ff8352839020558683526001600160a01b038416908301528101849052606081018390524260808201527fa4797a6bc9b727c487bf6fc5d5e062bd2ba98a9e7777d09b10f8ebee56b9bcd59060a0015b60405180910390a15050505050565b600061334a83614368565b905085604001516001600160a01b031663b88d4fde308588866040518563ffffffff1660e01b81526004016133829493929190615244565b600060405180830381600087803b15801561339c57600080fd5b505af11580156133b0573d6000803e3d6000fd5b50505050610d688686868461443a565b6000683635c9adc5dea000008311806133db5750620186a082115b156133f957604051630e52390960e41b815260040160405180910390fd5b6000604051806101000160405280886001600160a01b0316815260200160006001600160a01b03168152602001876001600160a01b031681526020018681526020018581526020018481526020016000815260200160008152509050806040516020016134669190614fe0565b60408051601f19818403018152828252805160209182012060fc805460018101909155600081815260ff8452849020919091558084526001600160a01b038b81169285019290925290891683830152606083018890526080830187905260a0830186905290519093507f1d0c2455e7d4e618f457a481b4202c8e4837d7f73b41c7e136fa59e353f7bbaf9181900360c00190a15095945050505050565b804710156135535760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610db8565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146135a0576040519150601f19603f3d011682016040523d82523d6000602084013e6135a5565b606091505b505090508061361c5760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610db8565b505050565b610e5561381f565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561365c5761361c836145f3565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156136b6575060408051601f3d908101601f191682019092526136b3918101906150df565b60015b6137195760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610db8565b60008051602061532e83398151915281146137885760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610db8565b5061361c83838361468f565b808211156137da576137a681836150f8565b6001600160a01b03841660009081526101006020526040812080549091906137cf9084906150f8565b9091555061361c9050565b8181111561361c576137ec82826150f8565b6001600160a01b0384166000908152610100602052604081208054909190613815908490614fcd565b9091555050505050565b6033546001600160a01b0316331461188a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610db8565b60c08401351561389c5760405163577d3ffb60e01b815260040160405180910390fd5b60006138ab6020860186614b16565b6001600160a01b0316036138d257604051630eb2e98f60e31b815260040160405180910390fd5b610b828260808601356112048487614fcd565b604080516101008101909152806138ff6020870187614b16565b6001600160a01b03168152602001826001600160a01b0316815260200185604001602081019061392f9190614b16565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a00135815260200142815260200160008152506040516020016139769190614fe0565b60408051808303601f190181528282528051602091820120600087815260ff8352839020558583526001600160a01b0384169083015281018390524260608201527f2a3d416f574ebbd2ff065eb2dcaa051e8193b2f928088debd9b826b5535d7bad9060800160405180910390a150505050565b60fd548015613a99576040516311fbaf5560e31b815260048101839052602481018290526000907355a4dc1f67003756a438bd6626b14a536734e5c790638fdd7aa890604401602060405180830381865af4158015613a4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a7191906150df565b90508060fe6000828254613a859190614fcd565b90915550613a95905081846150f8565b9250505b6001600160a01b0383166000908152610100602052604081208054849290613ac2908490614fcd565b9091555050604080516001600160a01b0385168152602081018490527fdcf38454e4a88aabad69fa0440c623dba63d38fb63c4813ddb034e2fece02648910160405180910390a1505050565b6001600160a01b0383166000908152610101602052604090205460ff16613b4857604051635998d66f60e01b815260040160405180910390fd5b6040516331a9108f60e11b81526004810187905230906001600160a01b03891690636352211e90602401602060405180830381865afa158015613b8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bb3919061510b565b6001600160a01b031603613bda576040516362251d0d60e11b815260040160405180910390fd5b6040516370a0823160e01b815230600482015247906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015613c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c6791906150df565b905060006001600160a01b038716613ce157856001600160a01b0316888686604051613c94929190615281565b60006040518083038185875af1925050503d8060008114613cd1576040519150601f19603f3d011682016040523d82523d6000602084013e613cd6565b606091505b505080915050613e4c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0896040518263ffffffff1660e01b81526004016000604051808303818588803b158015613d3c57600080fd5b505af1158015613d50573d6000803e3d6000fd5b505060405163095ea7b360e01b81526001600160a01b038b81166004830152602482018d90527f000000000000000000000000000000000000000000000000000000000000000016935063095ea7b3925060440190506020604051808303816000875af1158015613dc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613de99190615291565b50856001600160a01b03168585604051613e04929190615281565b6000604051808303816000865af19150503d8060008114613e41576040519150601f19603f3d011682016040523d82523d6000602084013e613e46565b606091505b50909150505b80613e6a57604051635917920d60e11b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015613ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ef591906150df565b90508015613f7857604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015613f5f57600080fd5b505af1158015613f73573d6000803e3d6000fd5b505050505b6040516331a9108f60e11b8152600481018b905230906001600160a01b038d1690636352211e90602401602060405180830381865afa158015613fbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe3919061510b565b6001600160a01b031614158061400d575088476140008587614fcd565b61400a91906150f8565b14155b1561402b576040516362251d0d60e11b815260040160405180910390fd5b5050505050505050505050565b606580546001600160a01b0319169055610e55816146b4565b608083015160a084015160c08501516040516316147d4d60e31b81526000937355a4dc1f67003756a438bd6626b14a536734e5c79363b0a3ea68936140a9936004019283526020830191909152604082015260600190565b602060405180830381865af41580156140c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ea91906150df565b905060008185608001516140fe91906150f8565b9050801561413a576020808601516001600160a01b03166000908152610100909152604081208054839290614134908490614fcd565b90915550505b845161414690836139ea565b60405180610100016040528086600001516001600160a01b0316815260200160006001600160a01b0316815260200186604001516001600160a01b03168152602001848152602001866080015181526020018660a0015181526020016000815260200160008152506040516020016141be9190614fe0565b60408051808303601f190181528282528051602091820120600088815260ff83528390205586835282018590527f7d7be60a03206cce6542b753ae6252f45891ec167a68dee14ed0a0439d2059df9101613330565b600061421e84614368565b604080890151905163095ea7b360e01b81526001600160a01b038681166004830152602482018a905292935091169063095ea7b390604401600060405180830381600087803b15801561427057600080fd5b505af1158015614284573d6000803e3d6000fd5b505050506000846001600160a01b0316836040516142a291906152b3565b6000604051808303816000865af19150503d80600081146142df576040519150601f19603f3d011682016040523d82523d6000602084013e6142e4565b606091505b505090508061430657604051635917920d60e11b815260040160405180910390fd5b6115638888888561443a565b600054610100900460ff1661188a5760405162461bcd60e51b8152600401610db8906152cf565b600054610100900460ff166143605760405162461bcd60e51b8152600401610db8906152cf565b61188a614706565b6001600160a01b0381166000908152610101602052604081205460ff166143a257604051635998d66f60e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015614406573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061442a91906150df565b6144349047614fcd565b92915050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156144a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144c591906150df565b9050801561454857604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561452f57600080fd5b505af1158015614543573d6000803e3d6000fd5b505050505b60408581015190516331a9108f60e11b81526004810186905230916001600160a01b031690636352211e90602401602060405180830381865afa158015614593573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145b7919061510b565b6001600160a01b031614806145d55750826145d283476150f8565b14155b156107dd5760405163afe9b87960e01b815260040160405180910390fd5b6001600160a01b0381163b6146605760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610db8565b60008051602061532e83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61469883614736565b6000825111806146a55750805b1561361c57610b828383614776565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff1661472d5760405162461bcd60e51b8152600401610db8906152cf565b61188a33614038565b61473f816145f3565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b6147de5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610db8565b600080846001600160a01b0316846040516147f991906152b3565b600060405180830381855af49150503d8060008114614834576040519150601f19603f3d011682016040523d82523d6000602084013e614839565b606091505b5091509150614861828260405180606001604052806027815260200161534e6027913961486a565b95945050505050565b60608315614879575081614883565b614883838361488a565b9392505050565b81511561489a5781518083602001fd5b8060405162461bcd60e51b8152600401610db8919061531a565b600061010082840312156148c757600080fd5b50919050565b600080600061014084860312156148e357600080fd5b6148ed85856148b4565b956101008501359550610120909401359392505050565b6001600160a01b0381168114610e5557600080fd5b803561492481614904565b919050565b60008083601f84011261493b57600080fd5b50813567ffffffffffffffff81111561495357600080fd5b60208301915083602082850101111561496b57600080fd5b9250929050565b60008060008060006080868803121561498a57600080fd5b853561499581614904565b945060208601356149a581614904565b935060408601359250606086013567ffffffffffffffff8111156149c857600080fd5b6149d488828901614929565b969995985093965092949392505050565b60008060008060008060006101a0888a031215614a0157600080fd5b614a0b89896148b4565b9650610100880135955061012088013594506101408801359350610160880135614a3481614904565b925061018088013567ffffffffffffffff811115614a5157600080fd5b614a5d8a828b01614929565b989b979a50959850939692959293505050565b60008060008060808587031215614a8657600080fd5b8435614a9181614904565b966020860135965060408601359560600135945092505050565b6000806101208385031215614abf57600080fd5b614ac984846148b4565b94610100939093013593505050565b6000806000806101608587031215614aef57600080fd5b614af986866148b4565b966101008601359650610120860135956101400135945092505050565b600060208284031215614b2857600080fd5b813561488381614904565b60008060008060006101808688031215614b4c57600080fd5b614b5687876148b4565b9761010087013597506101208701359661014081013596506101600135945092505050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112614ba257600080fd5b813567ffffffffffffffff80821115614bbd57614bbd614b7b565b604051601f8301601f19908116603f01168101908282118183101715614be557614be5614b7b565b81604052838152866020858801011115614bfe57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215614c3157600080fd5b8235614c3c81614904565b9150602083013567ffffffffffffffff811115614c5857600080fd5b614c6485828601614b91565b9150509250929050565b6000806000806000806101808789031215614c8857600080fd5b614c9288886148b4565b955061010087013594506101208701359350610140870135614cb381614904565b925061016087013567ffffffffffffffff811115614cd057600080fd5b614cdc89828a01614929565b979a9699509497509295939492505050565b6000806000806000806000806101c0898b031215614d0b57600080fd5b614d158a8a6148b4565b9750610100890135965061012089013595506101408901359450610160890135614d3e81614904565b9350610180890135614d4f81614904565b92506101a089013567ffffffffffffffff811115614d6c57600080fd5b614d788b828c01614929565b999c989b5096995094979396929594505050565b6000806000806102408587031215614da357600080fd5b614dad86866148b4565b93506101008501359250614dc58661012087016148b4565b939692955092936102200135925050565b60008060008060008060006101a0888a031215614df257600080fd5b614dfc89896148b4565b965061010088013595506101208801359450610140880135614e1d81614904565b9350610160880135614a3481614904565b600060208284031215614e4057600080fd5b5035919050565b61010081018235614e5781614904565b6001600160a01b039081168352602084013590614e7382614904565b9081166020840152604084013590614e8a82614904565b80821660408501525050606083013560608301526080830135608083015260a083013560a083015260c083013560c083015260e083013560e083015292915050565b6000610100808385031215614ee057600080fd5b6040519081019067ffffffffffffffff82118183101715614f0357614f03614b7b565b8160405280925083359150614f1782614904565b818152614f2660208501614919565b6020820152614f3760408501614919565b6040820152606084013560608201526080840135608082015260a084013560a082015260c084013560c082015260e084013560e0820152505092915050565b60006101008284031215614f8957600080fd5b6148838383614ecc565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561443457614434614fb7565b60006101008201905060018060a01b0380845116835280602085015116602084015280604085015116604084015250606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015292915050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6000602082840312156150f157600080fd5b5051919050565b8181038181111561443457614434614fb7565b60006020828403121561511d57600080fd5b815161488381614904565b6000806040838503121561513b57600080fd5b50508035926020909101359150565b600080610120838503121561515e57600080fd5b614ac98484614ecc565b6000806000806000806101a0878903121561518257600080fd5b61518c8888614ecc565b9550610100870135945061012087013593506101408701356151ad81614904565b92506101608701356151be81614904565b915061018087013567ffffffffffffffff8111156151db57600080fd5b6151e789828a01614b91565b9150509295509295509295565b60005b8381101561520f5781810151838201526020016151f7565b50506000910152565b600081518084526152308160208601602086016151f4565b601f01601f19169290920160200192915050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061527790830184615218565b9695505050505050565b8183823760009101908152919050565b6000602082840312156152a357600080fd5b8151801515811461488357600080fd5b600082516152c58184602087016151f4565b9190910192915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b602081526000614883602083018461521856fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122061118da3ef7a3e9d46eb7d093c11014d90f4e27f4afb8f0304f51a660115420864736f6c63430008130033000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Deployed Bytecode
0x60806040526004361061021e5760003560e01c806379ba509711610123578063bde938cb116100ab578063e6200dc21161006f578063e6200dc21461063d578063ea9cf4be14610652578063f2fde38b14610665578063f86c9e9a14610685578063f8887546146106a557600080fd5b8063bde938cb14610584578063c63f6052146105a4578063d0bf9c54146105d1578063d294cb0f146105f1578063e30c39781461061f57600080fd5b8063838a61f9116100f2578063838a61f9146104c5578063871ba096146104e55780638da5cb5b14610526578063a88acabd14610544578063aa3296de1461056457600080fd5b806379ba5097146104685780637f898fa01461047d5780638077ec661461049d5780638129fc1c146104b057600080fd5b80634489961a116101a6578063564d200a11610175578063564d200a146103ed5780636d8c39e414610400578063715018a61461042057806377fa66561461043557806379942ba61461044857600080fd5b80634489961a1461039257806344ef1390146103b25780634f1ef286146103c557806352d1902d146103d857600080fd5b8063335d0e13116101ed578063335d0e13146102f15780633390f7111461031f57806333b9aa231461033f5780633659cfe61461035f5780633692aae41461037f57600080fd5b806302bfb2c81461022a578063040141e51461024c578063150b7a02146102985780632a130bf2146102d157600080fd5b3661022557005b600080fd5b34801561023657600080fd5b5061024a6102453660046148cd565b6106c5565b005b34801561025857600080fd5b507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102a457600080fd5b506102b86102b3366004614972565b6107e4565b6040516001600160e01b0319909116815260200161028f565b3480156102dd57600080fd5b5061024a6102ec3660046149e5565b610814565b3480156102fd57600080fd5b5061031161030c366004614a70565b61097e565b60405190815260200161028f565b34801561032b57600080fd5b5061024a61033a366004614aab565b610a0c565b34801561034b57600080fd5b5061024a61035a366004614ad8565b610b88565b34801561036b57600080fd5b5061024a61037a366004614b16565b610d70565b61024a61038d366004614aab565b610e58565b34801561039e57600080fd5b5061024a6103ad366004614b16565b611085565b61024a6103c0366004614b33565b6110e6565b61024a6103d3366004614c1e565b61130b565b3480156103e457600080fd5b506103116113db565b61024a6103fb366004614c6e565b61148e565b34801561040c57600080fd5b5061024a61041b366004614cee565b61156d565b34801561042c57600080fd5b5061024a611878565b61024a610443366004614d8c565b61188c565b34801561045457600080fd5b5061024a610463366004614aab565b611cc7565b34801561047457600080fd5b5061024a611ea2565b34801561048957600080fd5b5061024a6104983660046148cd565b611f19565b61024a6104ab366004614dd6565b611ff5565b3480156104bc57600080fd5b5061024a6120c1565b3480156104d157600080fd5b5061024a6104e0366004614aab565b6121d3565b3480156104f157600080fd5b50610516610500366004614b16565b6101016020526000908152604090205460ff1681565b604051901515815260200161028f565b34801561053257600080fd5b506033546001600160a01b031661027b565b34801561055057600080fd5b5061024a61055f366004614cee565b61234a565b34801561057057600080fd5b5061024a61057f366004614aab565b6124aa565b34801561059057600080fd5b5061024a61059f366004614b16565b61260f565b3480156105b057600080fd5b506103116105bf366004614e2e565b60ff6020526000908152604090205481565b3480156105dd57600080fd5b5061024a6105ec366004614e2e565b61266c565b3480156105fd57600080fd5b5061031161060c366004614b16565b6101006020526000908152604090205481565b34801561062b57600080fd5b506065546001600160a01b031661027b565b34801561064957600080fd5b5061024a6126cc565b610311610660366004614a70565b612753565b34801561067157600080fd5b5061024a610680366004614b16565b6128a7565b34801561069157600080fd5b5061024a6106a0366004614b16565b612918565b3480156106b157600080fd5b5061024a6106c0366004614aab565b6129ae565b8282816040516020016106d89190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461071b57604051636946eab760e01b815260040160405180910390fd5b610723612b97565b8460e00135600003610748576040516301dff5d560e71b815260040160405180910390fd5b61076261075a36879003870187614f76565b858533612bf0565b6107726060860160408701614b16565b6001600160a01b03166323b872dd3330866040518463ffffffff1660e01b81526004016107a193929190614f93565b600060405180830381600087803b1580156107bb57600080fd5b505af11580156107cf573d6000803e3d6000fd5b505050506107dd600160fb55565b5050505050565b60006107f260fb5460021490565b6108025761080285858585612e9e565b50630a85bd0160e11b95945050505050565b8686816040516020016108279190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461086a57604051636946eab760e01b815260040160405180910390fd5b610872612b97565b61088a610884368b90038b018b614f76565b876131cd565b6108a561089c368b90038b018b614f76565b8989893361324c565b6108b560608a0160408b01614b16565b6001600160a01b03166323b872dd33308a6040518463ffffffff1660e01b81526004016108e493929190614f93565b600060405180830381600087803b1580156108fe57600080fd5b505af1158015610912573d6000803e3d6000fd5b505050506109698980360381019061092a9190614f76565b88888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061333f92505050565b610973600160fb55565b505050505050505050565b6000610988612b97565b61099533868686866133c0565b6040516323b872dd60e01b81529091506001600160a01b038616906323b872dd906109c890339030908990600401614f93565b600060405180830381600087803b1580156109e257600080fd5b505af11580156109f6573d6000803e3d6000fd5b50505050610a04600160fb55565b949350505050565b818181604051602001610a1f9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610a6257604051636946eab760e01b815260040160405180910390fd5b610a6a612b97565b610a776020850185614b16565b6001600160a01b0316336001600160a01b031614610aa7576040516282b42960e81b815260040160405180910390fd5b8360c00135600003610acc576040516367bec58d60e01b815260040160405180910390fd5b60e08401351580610aed5750610ae96201fa4060e0860135614fcd565b4211155b15610b0b57604051633f3db73560e21b815260040160405180910390fd5b600083815260ff60209081526040822091909155610b4490608086013590610b3590870187614b16565b6001600160a01b031690613503565b6040518381527f94effa14ea3a1ef396fa2fd829336d1597f1d76b548c26bfa2332869706638af906020015b60405180910390a1610b82600160fb55565b50505050565b838381604051602001610b9b9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610bde57604051636946eab760e01b815260040160405180910390fd5b610be6612b97565b610bf36020870187614b16565b6001600160a01b0316336001600160a01b031614610c23576040516282b42960e81b815260040160405180910390fd5b60c086013515610c465760405163577d3ffb60e01b815260040160405180910390fd5b683635c9adc5dea00000841180610c5f5750620186a083115b15610c7d57604051630e52390960e41b815260040160405180910390fd5b60408051610100810190915280610c976020890189614b16565b6001600160a01b0316815260006020820152604090810190610cbf9060608a01908a01614b16565b6001600160a01b0316815260200187606001358152602001858152602001848152602001600081526020016000815250604051602001610cff9190614fe0565b60408051808303601f190181528282528051602091820120600089815260ff835283902055878352820186905281018490527f27a96079a4426127077f0e9053dceae2d9a50ad31109773b6cbef3683af0900b9060600160405180910390a1610d68600160fb55565b505050505050565b6001600160a01b037f000000000000000000000000674ac9250fc4a5e54b129206a8ed817d22ffe2c6163003610dc15760405162461bcd60e51b8152600401610db890615047565b60405180910390fd5b7f000000000000000000000000674ac9250fc4a5e54b129206a8ed817d22ffe2c66001600160a01b0316610e0a60008051602061532e833981519152546001600160a01b031690565b6001600160a01b031614610e305760405162461bcd60e51b8152600401610db890615093565b610e3981613621565b60408051600080825260208201909252610e5591839190613629565b50565b818181604051602001610e6b9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610eae57604051636946eab760e01b815260040160405180910390fd5b610eb6612b97565b60c084013515610ed95760405163577d3ffb60e01b815260040160405180910390fd5b6000610ee86020860186614b16565b6001600160a01b031603610f0f57604051630eb2e98f60e31b815260040160405180910390fd5b610f1e33856080013534613794565b60408051610100810190915280610f386020870187614b16565b6001600160a01b03168152336020820152604090810190610f5f9060608801908801614b16565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020014281526020016000815250604051602001610fa69190614fe0565b60408051601f198184030181529181528151602092830120600086815260ff9093529181902091909155610fe09060608601908601614b16565b6001600160a01b03166342842e0e303387606001356040518463ffffffff1660e01b815260040161101393929190614f93565b600060405180830381600087803b15801561102d57600080fd5b505af1158015611041573d6000803e3d6000fd5b50506040805186815233602082015242918101919091527f7018ea7d1ccfe49000acdb52059c03871a92ffb8da722f9b785ec81866cf00b892506060019050610b70565b61108d61381f565b6001600160a01b03811660008181526101016020908152604091829020805460ff1916905590519182527fda68a0228a216daf1cfe2cbce9d172fc0d4a0181f04518aafae1cb2f8e638dee91015b60405180910390a150565b8484816040516020016110f99190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461113c57604051636946eab760e01b815260040160405180910390fd5b611144612b97565b6111546040880160208901614b16565b6001600160a01b0316336001600160a01b031614611184576040516282b42960e81b815260040160405180910390fd5b60006111936020890189614b16565b6001600160a01b0316146111ba57604051633c10be4b60e21b815260040160405180910390fd5b683635c9adc5dea000008411806111d35750620186a083115b156111f157604051630e52390960e41b815260040160405180910390fd5b61120933866112043460608c0135614fcd565b613794565b60405180610100016040528060006001600160a01b031681526020018860200160208101906112389190614b16565b6001600160a01b0316815260200161125660608a0160408b01614b16565b6001600160a01b031681526020018681526020018581526020018481526020016000815260200160008152506040516020016112929190614fe0565b60408051808303601f19018152828252805160209182012060008a815260ff83528390205588835282018790528101859052606081018490527f699d32d6654f5041063117eee3b5e6d16b2af3e2c78347aabf2a48f0db5df84f9060800160405180910390a1611302600160fb55565b50505050505050565b6001600160a01b037f000000000000000000000000674ac9250fc4a5e54b129206a8ed817d22ffe2c61630036113535760405162461bcd60e51b8152600401610db890615047565b7f000000000000000000000000674ac9250fc4a5e54b129206a8ed817d22ffe2c66001600160a01b031661139c60008051602061532e833981519152546001600160a01b031690565b6001600160a01b0316146113c25760405162461bcd60e51b8152600401610db890615093565b6113cb82613621565b6113d782826001613629565b5050565b6000306001600160a01b037f000000000000000000000000674ac9250fc4a5e54b129206a8ed817d22ffe2c6161461147b5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610db8565b5060008051602061532e83398151915290565b8585816040516020016114a19190614e47565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146114e457604051636946eab760e01b815260040160405180910390fd5b6114ec612b97565b6114f888873334613879565b611504888888336138e5565b611559611516368a90038a018a614f76565b8960600135888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061333f92505050565b611563600160fb55565b5050505050505050565b8787816040516020016115809190614e47565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146115c357604051636946eab760e01b815260040160405180910390fd5b6115cb612b97565b6115db60408b0160208c01614b16565b6001600160a01b0316336001600160a01b03161461160b576040516282b42960e81b815260040160405180910390fd5b8960c00135600003611630576040516367bec58d60e01b815260040160405180910390fd5b6040516316147d4d60e31b815260808b0135600482015260a08b0135602482015260c08b013560448201526000907355a4dc1f67003756a438bd6626b14a536734e5c79063b0a3ea6890606401602060405180830381865af415801561169a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116be91906150df565b90506000816116d18a60808f01356150f8565b6116db91906150f8565b90506116f36116ed60208e018e614b16565b836139ea565b8015611747578061010060008e60200160208101906117129190614b16565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546117419190614fcd565b90915550505b6040805161010081019091528061176160208f018f614b16565b6001600160a01b0316815260200160006001600160a01b031681526020018d60400160208101906117929190614b16565b6001600160a01b031681526020018b81526020018d6080013581526020018d60a0013581526020016000815260200160008152506040516020016117d69190614fe0565b60408051601f19818403018152918152815160209283012060008e815260ff909352918190209190915561181f906118149060608f01908f01614b16565b8b8b8b8b8b8b613b0e565b604080518c8152602081018c90529081018a90527fac76107e19044e50d0526f5983962056aff4f8d4a4bb07a3730e609dc3cf9d129060600160405180910390a1505061186c600160fb55565b50505050505050505050565b61188061381f565b61188a6000614038565b565b83838160405160200161189f9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146118e257604051636946eab760e01b815260040160405180910390fd5b8383816040516020016118f59190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461193857604051636946eab760e01b815260040160405180910390fd5b611940612b97565b6119506040890160208a01614b16565b6001600160a01b0316336001600160a01b031614611980576040516282b42960e81b815260040160405180910390fd5b8760c001356000036119a5576040516367bec58d60e01b815260040160405180910390fd5b60c0860135156119c85760405163577d3ffb60e01b815260040160405180910390fd5b60006119d76020880188614b16565b6001600160a01b0316036119fe57604051630eb2e98f60e31b815260040160405180910390fd5b611a0e6060870160408801614b16565b6001600160a01b0316611a2760608a0160408b01614b16565b6001600160a01b031614611a4e576040516352bbeac560e01b815260040160405180910390fd5b6040516316147d4d60e31b81526080890135600482015260a0890135602482015260c089013560448201526000907355a4dc1f67003756a438bd6626b14a536734e5c79063b0a3ea6890606401602060405180830381865af4158015611ab8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adc91906150df565b9050611afe33611af08360808b0135614fcd565b6112043460808e0135614fcd565b611b14611b0e60208b018b614b16565b826139ea565b60408051610100810190915280611b2e60208c018c614b16565b6001600160a01b0316815260006020820152604090810190611b569060608d01908d01614b16565b6001600160a01b03168152602001886060013581526020018a6080013581526020018a60a001358152602001600081526020016000815250604051602001611b9e9190614fe0565b60408051601f19818403018152828252805160209182012060008c815260ff83528390205561010083019091528190611bd9908a018a614b16565b6001600160a01b031681526020018a6020016020810190611bfa9190614b16565b6001600160a01b03168152602001611c1860608a0160408b01614b16565b6001600160a01b0316815260200188606001358152602001886080013581526020018860a0013581526020014281526020016000815250604051602001611c5f9190614fe0565b60408051601f19818403018152828252805160209182012060008a815260ff8352839020558a835282018890524282820152517fabdbeebdc0a5c123625afdabd45e1c7cb5193d257ae81f27aa8f9865e0b867fc9181900360600190a150611563600160fb55565b818181604051602001611cda9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414611d1d57604051636946eab760e01b815260040160405180910390fd5b611d25612b97565b611d326020850185614b16565b6001600160a01b0316336001600160a01b031614611d62576040516282b42960e81b815260040160405180910390fd5b8360c00135600003611d87576040516367bec58d60e01b815260040160405180910390fd5b60e084013515611daa5760405163647ccdcd60e11b815260040160405180910390fd5b60408051610100810190915280611dc46020870187614b16565b6001600160a01b03168152602001856020016020810190611de59190614b16565b6001600160a01b03168152602001611e036060870160408801614b16565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020018560c00135815260200142815250604051602001611e4d9190614fe0565b60408051808303601f190181528282528051602091820120600087815260ff83528390205585835242908301527f8b31d3b4bc191b98ddfb3298ea923ba81c7121b9d7169f47a2cf1079c7010acf9101610b70565b60655433906001600160a01b03168114611f105760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610db8565b610e5581614038565b828281604051602001611f2c9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414611f6f57604051636946eab760e01b815260040160405180910390fd5b611f77612b97565b611f876040860160208701614b16565b6001600160a01b0316336001600160a01b031614611fb7576040516282b42960e81b815260040160405180910390fd5b8460c00135600003611fdc576040516367bec58d60e01b815260040160405180910390fd5b610762611fee36879003870187614f76565b8585614051565b8686816040516020016120089190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461204b57604051636946eab760e01b815260040160405180910390fd5b612053612b97565b61205f89883334613879565b61206b898989336138e5565b61096961207d368b90038b018b614f76565b8a6060013589898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061421392505050565b600054610100900460ff16158080156120e15750600054600160ff909116105b806120fb5750303b1580156120fb575060005460ff166001145b61215e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610db8565b6000805460ff191660011790558015612181576000805461ff0019166101001790555b612189614312565b612191614339565b8015610e55576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016110db565b8181816040516020016121e69190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461222957604051636946eab760e01b815260040160405180910390fd5b612231612b97565b61223e6020850185614b16565b6001600160a01b0316336001600160a01b03161461226e576040516282b42960e81b815260040160405180910390fd5b60c0840135156122915760405163577d3ffb60e01b815260040160405180910390fd5b600083815260ff6020526040808220919091556122b49060608601908601614b16565b6001600160a01b03166323b872dd303387606001356040518463ffffffff1660e01b81526004016122e793929190614f93565b600060405180830381600087803b15801561230157600080fd5b505af1158015612315573d6000803e3d6000fd5b505050507fd18ab7eec3067b4a8e15f1c1f5299c77c05218c5718857eae55ac13c190f287583604051610b7091815260200190565b87878160405160200161235d9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146123a057604051636946eab760e01b815260040160405180910390fd5b6123a8612b97565b6123c06123ba368c90038c018c614f76565b886131cd565b6123db6123d2368c90038c018c614f76565b8a8a8a3361324c565b6123eb60608b0160408c01614b16565b6001600160a01b03166323b872dd33308b6040518463ffffffff1660e01b815260040161241a93929190614f93565b600060405180830381600087803b15801561243457600080fd5b505af1158015612448573d6000803e3d6000fd5b505050506124a08a8036038101906124609190614f76565b8989898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061421392505050565b61186c600160fb55565b8181816040516020016124bd9190614e47565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461250057604051636946eab760e01b815260040160405180910390fd5b612508612b97565b6125186040850160208601614b16565b6001600160a01b0316336001600160a01b031614612548576040516282b42960e81b815260040160405180910390fd5b60006125576020860186614b16565b6001600160a01b03161461257e57604051633c10be4b60e21b815260040160405180910390fd5b606084013561010060006125986040880160208901614b16565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546125c79190614fcd565b9091555050600083815260ff602052604080822091909155517f7687efe94566d20f7ebb8eff43bb57b2c014749dfd9ad179089e58c338ecdfa790610b709085815260200190565b61261761381f565b6001600160a01b03811660008181526101016020908152604091829020805460ff1916600117905590519182527f9d26696f1250d555e1136fcc68cc61c008bfdbc4edc53223e9e87ee94c530df591016110db565b61267461381f565b6103e881111561269757604051630e52390960e41b815260040160405180910390fd5b60fd8190556040518181527f2f1e1f4c9db00c1f5b9f1fb7b358f5beb59f9d4f72b9ba22a03240abf2344946906020016110db565b6126d4612b97565b3360009081526101006020526040812054908190036126f35750612749565b336000818152610100602052604081205561270e9082613503565b60408051338152602081018390527f3efd984b5a13f92c04233a1e4a17098601b9effd13622786eab024424b9a4b02910160405180910390a1505b61188a600160fb55565b600061275d612b97565b683635c9adc5dea000008311806127765750620186a082115b1561279457604051630e52390960e41b815260040160405180910390fd5b61279f338534613794565b600060405180610100016040528060006001600160a01b03168152602001336001600160a01b03168152602001876001600160a01b0316815260200186815260200185815260200184815260200160008152602001600081525090508060405160200161280c9190614fe0565b60408051601f19818403018152828252805160209182012060fc805460018101909155600081815260ff84528490209190915580845233918401919091526001600160a01b03891683830152606083018890526080830187905260a0830186905290519093507f6386159f9aeea426c15aaec24295e5deef70a311ffe87a52fe8c875acc9941519181900360c00190a150610a04600160fb55565b6128af61381f565b606580546001600160a01b0383166001600160a01b031990911681179091556128e06033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b61292061381f565b60fe5480156113d7576001600160a01b03821661295057604051630e52390960e41b815260040160405180910390fd5b600060fe556129686001600160a01b03831682613503565b604080516001600160a01b0384168152602081018390527f905d2a9b2639a94f09720cfd7b061c3b7a9e27921a009e954d67c8aff6e73667910160405180910390a15050565b8181816040516020016129c19190614e47565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414612a0457604051636946eab760e01b815260040160405180910390fd5b612a0c612b97565b612a196020850185614b16565b6001600160a01b0316336001600160a01b031614612a49576040516282b42960e81b815260040160405180910390fd5b8360e00135600003612a6e576040516301dff5d560e71b815260040160405180910390fd5b612a7e610e1060e0860135614fcd565b421015612a9e5760405163b882dff360e01b815260040160405180910390fd5b60408051610100810190915280612ab86020870187614b16565b6001600160a01b03168152602001856020016020810190612ad99190614b16565b6001600160a01b03168152602001612af76060870160408801614b16565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020018560c0013581526020016000815250604051602001612b429190614fe0565b60408051601f198184030181528282528051602091820120600087815260ff909252919020557f35dd1796423ce8f6a16296e4b6f10f75f26bc954cbb4014ae929416d0476abac90610b709085815260200190565b600260fb5403612be95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610db8565b600260fb55565b608084015160a085015160c08601516040516316147d4d60e31b81526000937355a4dc1f67003756a438bd6626b14a536734e5c79363b0a3ea6893612c48936004019283526020830191909152604082015260600190565b602060405180830381865af4158015612c65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c8991906150df565b905060007355a4dc1f67003756a438bd6626b14a536734e5c763b87a5ded838860800151612cb791906150f8565b60e0890151612cc690426150f8565b6040516001600160e01b031960e085901b168152600481019290925260248201526201fa406044820152606401602060405180830381865af4158015612d10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d3491906150df565b9050600082828860800151612d4991906150f8565b612d5391906150f8565b90508015612d8f576020808801516001600160a01b03166000908152610100909152604081208054839290612d89908490614fcd565b90915550505b612da26001600160a01b03851683613503565b8651612dae90846139ea565b60405180610100016040528088600001516001600160a01b0316815260200160006001600160a01b0316815260200188604001516001600160a01b03168152602001868152602001886080015181526020018860a001518152602001600081526020016000815250604051602001612e269190614fe0565b60408051808303601f19018152828252805160209182012060008a815260ff8352839020558883526001600160a01b038716908301528101869052606081018390527fdd79deab13d35b6c83e88ee7f630110a06d72c9b0d6532310060518dce8946169060800160405180910390a150505050505050565b612ea6612b97565b6040516331a9108f60e11b81526004810184905230903390636352211e90602401602060405180830381865afa158015612ee4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f08919061510b565b6001600160a01b031614612f2f57604051634f95e6e560e01b815260040160405180910390fd5b6040819003612f6057600080612f4783850185615128565b91509150612f5886338785856133c0565b5050506131c3565b61012081900361309157600080612f798385018561514a565b9150915081604051602001612f8e9190614fe0565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414612fd157604051636946eab760e01b815260040160405180910390fd5b81604001516001600160a01b0316336001600160a01b031614613007576040516352bbeac560e01b815260040160405180910390fd5b81602001516001600160a01b0316866001600160a01b031603613059578160c00151600003613049576040516367bec58d60e01b815260040160405180910390fd5b613054828287614051565b61308a565b8160e0015160000361307e576040516301dff5d560e71b815260040160405180910390fd5b61308a82828789612bf0565b50506131c3565b61018081106131aa57600080808080806130ad87890189615168565b955095509550955095509550856040516020016130ca9190614fe0565b60408051601f198184030181529181528151602092830120600088815260ff9093529120541461310d57604051636946eab760e01b815260040160405180910390fd5b85604001516001600160a01b0316336001600160a01b031614613143576040516352bbeac560e01b815260040160405180910390fd5b6001600160a01b03821661317a5761315b86856131cd565b61316886868b878e61324c565b613175868a86868561333f565b61319f565b61318486856131cd565b61319186868b878e61324c565b61319f868a86868686614213565b5050505050506131c3565b604051630e52390960e41b815260040160405180910390fd5b610b82600160fb55565b81516001600160a01b0316156131f657604051633c10be4b60e21b815260040160405180910390fd5b816080015181836060015161320b9190614fcd565b61321591906150f8565b6020808401516001600160a01b03166000908152610100909152604081208054909190613243908490614fcd565b90915550505050565b604051806101000160405280826001600160a01b0316815260200186602001516001600160a01b0316815260200186604001516001600160a01b03168152602001848152602001866080015181526020018660a00151815260200142815260200160008152506040516020016132c29190614fe0565b60408051808303601f190181528282528051602091820120600088815260ff8352839020558683526001600160a01b038416908301528101849052606081018390524260808201527fa4797a6bc9b727c487bf6fc5d5e062bd2ba98a9e7777d09b10f8ebee56b9bcd59060a0015b60405180910390a15050505050565b600061334a83614368565b905085604001516001600160a01b031663b88d4fde308588866040518563ffffffff1660e01b81526004016133829493929190615244565b600060405180830381600087803b15801561339c57600080fd5b505af11580156133b0573d6000803e3d6000fd5b50505050610d688686868461443a565b6000683635c9adc5dea000008311806133db5750620186a082115b156133f957604051630e52390960e41b815260040160405180910390fd5b6000604051806101000160405280886001600160a01b0316815260200160006001600160a01b03168152602001876001600160a01b031681526020018681526020018581526020018481526020016000815260200160008152509050806040516020016134669190614fe0565b60408051601f19818403018152828252805160209182012060fc805460018101909155600081815260ff8452849020919091558084526001600160a01b038b81169285019290925290891683830152606083018890526080830187905260a0830186905290519093507f1d0c2455e7d4e618f457a481b4202c8e4837d7f73b41c7e136fa59e353f7bbaf9181900360c00190a15095945050505050565b804710156135535760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610db8565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146135a0576040519150601f19603f3d011682016040523d82523d6000602084013e6135a5565b606091505b505090508061361c5760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610db8565b505050565b610e5561381f565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561365c5761361c836145f3565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156136b6575060408051601f3d908101601f191682019092526136b3918101906150df565b60015b6137195760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610db8565b60008051602061532e83398151915281146137885760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610db8565b5061361c83838361468f565b808211156137da576137a681836150f8565b6001600160a01b03841660009081526101006020526040812080549091906137cf9084906150f8565b9091555061361c9050565b8181111561361c576137ec82826150f8565b6001600160a01b0384166000908152610100602052604081208054909190613815908490614fcd565b9091555050505050565b6033546001600160a01b0316331461188a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610db8565b60c08401351561389c5760405163577d3ffb60e01b815260040160405180910390fd5b60006138ab6020860186614b16565b6001600160a01b0316036138d257604051630eb2e98f60e31b815260040160405180910390fd5b610b828260808601356112048487614fcd565b604080516101008101909152806138ff6020870187614b16565b6001600160a01b03168152602001826001600160a01b0316815260200185604001602081019061392f9190614b16565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a00135815260200142815260200160008152506040516020016139769190614fe0565b60408051808303601f190181528282528051602091820120600087815260ff8352839020558583526001600160a01b0384169083015281018390524260608201527f2a3d416f574ebbd2ff065eb2dcaa051e8193b2f928088debd9b826b5535d7bad9060800160405180910390a150505050565b60fd548015613a99576040516311fbaf5560e31b815260048101839052602481018290526000907355a4dc1f67003756a438bd6626b14a536734e5c790638fdd7aa890604401602060405180830381865af4158015613a4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a7191906150df565b90508060fe6000828254613a859190614fcd565b90915550613a95905081846150f8565b9250505b6001600160a01b0383166000908152610100602052604081208054849290613ac2908490614fcd565b9091555050604080516001600160a01b0385168152602081018490527fdcf38454e4a88aabad69fa0440c623dba63d38fb63c4813ddb034e2fece02648910160405180910390a1505050565b6001600160a01b0383166000908152610101602052604090205460ff16613b4857604051635998d66f60e01b815260040160405180910390fd5b6040516331a9108f60e11b81526004810187905230906001600160a01b03891690636352211e90602401602060405180830381865afa158015613b8f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bb3919061510b565b6001600160a01b031603613bda576040516362251d0d60e11b815260040160405180910390fd5b6040516370a0823160e01b815230600482015247906000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa158015613c43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c6791906150df565b905060006001600160a01b038716613ce157856001600160a01b0316888686604051613c94929190615281565b60006040518083038185875af1925050503d8060008114613cd1576040519150601f19603f3d011682016040523d82523d6000602084013e613cd6565b606091505b505080915050613e4c565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0896040518263ffffffff1660e01b81526004016000604051808303818588803b158015613d3c57600080fd5b505af1158015613d50573d6000803e3d6000fd5b505060405163095ea7b360e01b81526001600160a01b038b81166004830152602482018d90527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216935063095ea7b3925060440190506020604051808303816000875af1158015613dc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613de99190615291565b50856001600160a01b03168585604051613e04929190615281565b6000604051808303816000865af19150503d8060008114613e41576040519150601f19603f3d011682016040523d82523d6000602084013e613e46565b606091505b50909150505b80613e6a57604051635917920d60e11b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa158015613ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ef591906150df565b90508015613f7857604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015613f5f57600080fd5b505af1158015613f73573d6000803e3d6000fd5b505050505b6040516331a9108f60e11b8152600481018b905230906001600160a01b038d1690636352211e90602401602060405180830381865afa158015613fbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe3919061510b565b6001600160a01b031614158061400d575088476140008587614fcd565b61400a91906150f8565b14155b1561402b576040516362251d0d60e11b815260040160405180910390fd5b5050505050505050505050565b606580546001600160a01b0319169055610e55816146b4565b608083015160a084015160c08501516040516316147d4d60e31b81526000937355a4dc1f67003756a438bd6626b14a536734e5c79363b0a3ea68936140a9936004019283526020830191909152604082015260600190565b602060405180830381865af41580156140c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ea91906150df565b905060008185608001516140fe91906150f8565b9050801561413a576020808601516001600160a01b03166000908152610100909152604081208054839290614134908490614fcd565b90915550505b845161414690836139ea565b60405180610100016040528086600001516001600160a01b0316815260200160006001600160a01b0316815260200186604001516001600160a01b03168152602001848152602001866080015181526020018660a0015181526020016000815260200160008152506040516020016141be9190614fe0565b60408051808303601f190181528282528051602091820120600088815260ff83528390205586835282018590527f7d7be60a03206cce6542b753ae6252f45891ec167a68dee14ed0a0439d2059df9101613330565b600061421e84614368565b604080890151905163095ea7b360e01b81526001600160a01b038681166004830152602482018a905292935091169063095ea7b390604401600060405180830381600087803b15801561427057600080fd5b505af1158015614284573d6000803e3d6000fd5b505050506000846001600160a01b0316836040516142a291906152b3565b6000604051808303816000865af19150503d80600081146142df576040519150601f19603f3d011682016040523d82523d6000602084013e6142e4565b606091505b505090508061430657604051635917920d60e11b815260040160405180910390fd5b6115638888888561443a565b600054610100900460ff1661188a5760405162461bcd60e51b8152600401610db8906152cf565b600054610100900460ff166143605760405162461bcd60e51b8152600401610db8906152cf565b61188a614706565b6001600160a01b0381166000908152610101602052604081205460ff166143a257604051635998d66f60e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa158015614406573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061442a91906150df565b6144349047614fcd565b92915050565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa1580156144a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144c591906150df565b9050801561454857604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561452f57600080fd5b505af1158015614543573d6000803e3d6000fd5b505050505b60408581015190516331a9108f60e11b81526004810186905230916001600160a01b031690636352211e90602401602060405180830381865afa158015614593573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145b7919061510b565b6001600160a01b031614806145d55750826145d283476150f8565b14155b156107dd5760405163afe9b87960e01b815260040160405180910390fd5b6001600160a01b0381163b6146605760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610db8565b60008051602061532e83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b61469883614736565b6000825111806146a55750805b1561361c57610b828383614776565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff1661472d5760405162461bcd60e51b8152600401610db8906152cf565b61188a33614038565b61473f816145f3565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b6147de5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610db8565b600080846001600160a01b0316846040516147f991906152b3565b600060405180830381855af49150503d8060008114614834576040519150601f19603f3d011682016040523d82523d6000602084013e614839565b606091505b5091509150614861828260405180606001604052806027815260200161534e6027913961486a565b95945050505050565b60608315614879575081614883565b614883838361488a565b9392505050565b81511561489a5781518083602001fd5b8060405162461bcd60e51b8152600401610db8919061531a565b600061010082840312156148c757600080fd5b50919050565b600080600061014084860312156148e357600080fd5b6148ed85856148b4565b956101008501359550610120909401359392505050565b6001600160a01b0381168114610e5557600080fd5b803561492481614904565b919050565b60008083601f84011261493b57600080fd5b50813567ffffffffffffffff81111561495357600080fd5b60208301915083602082850101111561496b57600080fd5b9250929050565b60008060008060006080868803121561498a57600080fd5b853561499581614904565b945060208601356149a581614904565b935060408601359250606086013567ffffffffffffffff8111156149c857600080fd5b6149d488828901614929565b969995985093965092949392505050565b60008060008060008060006101a0888a031215614a0157600080fd5b614a0b89896148b4565b9650610100880135955061012088013594506101408801359350610160880135614a3481614904565b925061018088013567ffffffffffffffff811115614a5157600080fd5b614a5d8a828b01614929565b989b979a50959850939692959293505050565b60008060008060808587031215614a8657600080fd5b8435614a9181614904565b966020860135965060408601359560600135945092505050565b6000806101208385031215614abf57600080fd5b614ac984846148b4565b94610100939093013593505050565b6000806000806101608587031215614aef57600080fd5b614af986866148b4565b966101008601359650610120860135956101400135945092505050565b600060208284031215614b2857600080fd5b813561488381614904565b60008060008060006101808688031215614b4c57600080fd5b614b5687876148b4565b9761010087013597506101208701359661014081013596506101600135945092505050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112614ba257600080fd5b813567ffffffffffffffff80821115614bbd57614bbd614b7b565b604051601f8301601f19908116603f01168101908282118183101715614be557614be5614b7b565b81604052838152866020858801011115614bfe57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215614c3157600080fd5b8235614c3c81614904565b9150602083013567ffffffffffffffff811115614c5857600080fd5b614c6485828601614b91565b9150509250929050565b6000806000806000806101808789031215614c8857600080fd5b614c9288886148b4565b955061010087013594506101208701359350610140870135614cb381614904565b925061016087013567ffffffffffffffff811115614cd057600080fd5b614cdc89828a01614929565b979a9699509497509295939492505050565b6000806000806000806000806101c0898b031215614d0b57600080fd5b614d158a8a6148b4565b9750610100890135965061012089013595506101408901359450610160890135614d3e81614904565b9350610180890135614d4f81614904565b92506101a089013567ffffffffffffffff811115614d6c57600080fd5b614d788b828c01614929565b999c989b5096995094979396929594505050565b6000806000806102408587031215614da357600080fd5b614dad86866148b4565b93506101008501359250614dc58661012087016148b4565b939692955092936102200135925050565b60008060008060008060006101a0888a031215614df257600080fd5b614dfc89896148b4565b965061010088013595506101208801359450610140880135614e1d81614904565b9350610160880135614a3481614904565b600060208284031215614e4057600080fd5b5035919050565b61010081018235614e5781614904565b6001600160a01b039081168352602084013590614e7382614904565b9081166020840152604084013590614e8a82614904565b80821660408501525050606083013560608301526080830135608083015260a083013560a083015260c083013560c083015260e083013560e083015292915050565b6000610100808385031215614ee057600080fd5b6040519081019067ffffffffffffffff82118183101715614f0357614f03614b7b565b8160405280925083359150614f1782614904565b818152614f2660208501614919565b6020820152614f3760408501614919565b6040820152606084013560608201526080840135608082015260a084013560a082015260c084013560c082015260e084013560e0820152505092915050565b60006101008284031215614f8957600080fd5b6148838383614ecc565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561443457614434614fb7565b60006101008201905060018060a01b0380845116835280602085015116602084015280604085015116604084015250606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015292915050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b6000602082840312156150f157600080fd5b5051919050565b8181038181111561443457614434614fb7565b60006020828403121561511d57600080fd5b815161488381614904565b6000806040838503121561513b57600080fd5b50508035926020909101359150565b600080610120838503121561515e57600080fd5b614ac98484614ecc565b6000806000806000806101a0878903121561518257600080fd5b61518c8888614ecc565b9550610100870135945061012087013593506101408701356151ad81614904565b92506101608701356151be81614904565b915061018087013567ffffffffffffffff8111156151db57600080fd5b6151e789828a01614b91565b9150509295509295509295565b60005b8381101561520f5781810151838201526020016151f7565b50506000910152565b600081518084526152308160208601602086016151f4565b601f01601f19169290920160200192915050565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061527790830184615218565b9695505050505050565b8183823760009101908152919050565b6000602082840312156152a357600080fd5b8151801515811461488357600080fd5b600082516152c58184602087016151f4565b9190910192915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b602081526000614883602083018461521856fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122061118da3ef7a3e9d46eb7d093c11014d90f4e27f4afb8f0304f51a660115420864736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
-----Decoded View---------------
Arg [0] : wethAddress (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.