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 | 18266280 | 399 days ago | IN | 0 ETH | 0.05679622 |
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:
paris 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 {Multicall} from "@openzeppelin/contracts/utils/Multicall.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, Multicall { 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: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol) pragma solidity ^0.8.0; import "./Address.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. * * _Available since v4.1._ */ abstract contract Multicall { /** * @dev Receives and executes a batch of function calls on this contract. */ function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { results[i] = Address.functionDelegateCall(address(this), data[i]); } return results; } }
// 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": [ "forge-std/=lib/forge-std/src/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@solmate/=lib/solmate/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": { "contracts/libraries/math/MathUtils.sol": { "MathUtils": "0xd04eb5594b4e6b50c27d1062e2d22d5c10a299bf" } } }
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":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","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
60c0604052306080523480156200001557600080fd5b50604051620058f0380380620058f083398101604081905262000038916200011d565b600160fb556001600160a01b03811660a052620000546200005b565b506200014f565b600054610100900460ff1615620000c85760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156200011b576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200013057600080fd5b81516001600160a01b03811681146200014857600080fd5b9392505050565b60805160a051615727620001c96000396000818161026601528181613d2201528181613e1101528181613ea601528181613fb00152818161404101528181614511015281816145a60152614637015260008181610db201528181610dfb0152818161134d0152818161138d015261142001526157276000f3fe6080604052600436106102295760003560e01c80637f898fa011610123578063bde938cb116100ab578063e6200dc21161006f578063e6200dc214610675578063ea9cf4be1461068a578063f2fde38b1461069d578063f86c9e9a146106bd578063f8887546146106dd57600080fd5b8063bde938cb146105bc578063c63f6052146105dc578063d0bf9c5414610609578063d294cb0f14610629578063e30c39781461065757600080fd5b8063871ba096116100f2578063871ba096146104f05780638da5cb5b14610531578063a88acabd1461054f578063aa3296de1461056f578063ac9650d81461058f57600080fd5b80637f898fa0146104885780638077ec66146104a85780638129fc1c146104bb578063838a61f9146104d057600080fd5b80634489961a116101b15780636d8c39e4116101755780636d8c39e41461040b578063715018a61461042b57806377fa66561461044057806379942ba61461045357806379ba50971461047357600080fd5b80634489961a1461039d57806344ef1390146103bd5780634f1ef286146103d057806352d1902d146103e3578063564d200a146103f857600080fd5b8063335d0e13116101f8578063335d0e13146102fc5780633390f7111461032a57806333b9aa231461034a5780633659cfe61461036a5780633692aae41461038a57600080fd5b806302bfb2c814610235578063040141e514610257578063150b7a02146102a35780632a130bf2146102dc57600080fd5b3661023057005b600080fd5b34801561024157600080fd5b50610255610250366004614b07565b6106fd565b005b34801561026357600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102af57600080fd5b506102c36102be366004614bac565b61081c565b6040516001600160e01b0319909116815260200161029a565b3480156102e857600080fd5b506102556102f7366004614c1f565b61084c565b34801561030857600080fd5b5061031c610317366004614caa565b6109b6565b60405190815260200161029a565b34801561033657600080fd5b50610255610345366004614ce5565b610a44565b34801561035657600080fd5b50610255610365366004614d12565b610bc0565b34801561037657600080fd5b50610255610385366004614d50565b610da8565b610255610398366004614ce5565b610e90565b3480156103a957600080fd5b506102556103b8366004614d50565b6110bd565b6102556103cb366004614d6d565b61111e565b6102556103de366004614e58565b611343565b3480156103ef57600080fd5b5061031c611413565b610255610406366004614ea8565b6114c6565b34801561041757600080fd5b50610255610426366004614f28565b6115a5565b34801561043757600080fd5b506102556118b0565b61025561044e366004614fc6565b6118c4565b34801561045f57600080fd5b5061025561046e366004614ce5565b611cff565b34801561047f57600080fd5b50610255611eda565b34801561049457600080fd5b506102556104a3366004614b07565b611f51565b6102556104b6366004615010565b61202d565b3480156104c757600080fd5b506102556120f9565b3480156104dc57600080fd5b506102556104eb366004614ce5565b61220b565b3480156104fc57600080fd5b5061052161050b366004614d50565b6101016020526000908152604090205460ff1681565b604051901515815260200161029a565b34801561053d57600080fd5b506033546001600160a01b0316610286565b34801561055b57600080fd5b5061025561056a366004614f28565b612382565b34801561057b57600080fd5b5061025561058a366004614ce5565b6124e2565b34801561059b57600080fd5b506105af6105aa366004615068565b612647565b60405161029a919061512d565b3480156105c857600080fd5b506102556105d7366004614d50565b61273d565b3480156105e857600080fd5b5061031c6105f736600461518f565b60ff6020526000908152604090205481565b34801561061557600080fd5b5061025561062436600461518f565b61279a565b34801561063557600080fd5b5061031c610644366004614d50565b6101006020526000908152604090205481565b34801561066357600080fd5b506065546001600160a01b0316610286565b34801561068157600080fd5b506102556127fa565b61031c610698366004614caa565b612881565b3480156106a957600080fd5b506102556106b8366004614d50565b6129d5565b3480156106c957600080fd5b506102556106d8366004614d50565b612a46565b3480156106e957600080fd5b506102556106f8366004614ce5565b612adc565b82828160405160200161071091906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461075357604051636946eab760e01b815260040160405180910390fd5b61075b612cc5565b8460e00135600003610780576040516301dff5d560e71b815260040160405180910390fd5b61079a610792368790038701876152d7565b858533612d1e565b6107aa6060860160408701614d50565b6001600160a01b03166323b872dd3330866040518463ffffffff1660e01b81526004016107d9939291906152f4565b600060405180830381600087803b1580156107f357600080fd5b505af1158015610807573d6000803e3d6000fd5b50505050610815600160fb55565b5050505050565b600061082a60fb5460021490565b61083a5761083a85858585612fcc565b50630a85bd0160e11b95945050505050565b86868160405160200161085f91906151a8565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146108a257604051636946eab760e01b815260040160405180910390fd5b6108aa612cc5565b6108c26108bc368b90038b018b6152d7565b876132fb565b6108dd6108d4368b90038b018b6152d7565b8989893361337a565b6108ed60608a0160408b01614d50565b6001600160a01b03166323b872dd33308a6040518463ffffffff1660e01b815260040161091c939291906152f4565b600060405180830381600087803b15801561093657600080fd5b505af115801561094a573d6000803e3d6000fd5b505050506109a18980360381019061096291906152d7565b88888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061346d92505050565b6109ab600160fb55565b505050505050505050565b60006109c0612cc5565b6109cd33868686866134ee565b6040516323b872dd60e01b81529091506001600160a01b038616906323b872dd90610a00903390309089906004016152f4565b600060405180830381600087803b158015610a1a57600080fd5b505af1158015610a2e573d6000803e3d6000fd5b50505050610a3c600160fb55565b949350505050565b818181604051602001610a5791906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610a9a57604051636946eab760e01b815260040160405180910390fd5b610aa2612cc5565b610aaf6020850185614d50565b6001600160a01b0316336001600160a01b031614610adf576040516282b42960e81b815260040160405180910390fd5b8360c00135600003610b04576040516367bec58d60e01b815260040160405180910390fd5b60e08401351580610b255750610b216201fa4060e086013561532e565b4211155b15610b4357604051633f3db73560e21b815260040160405180910390fd5b600083815260ff60209081526040822091909155610b7c90608086013590610b6d90870187614d50565b6001600160a01b031690613631565b6040518381527f94effa14ea3a1ef396fa2fd829336d1597f1d76b548c26bfa2332869706638af906020015b60405180910390a1610bba600160fb55565b50505050565b838381604051602001610bd391906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610c1657604051636946eab760e01b815260040160405180910390fd5b610c1e612cc5565b610c2b6020870187614d50565b6001600160a01b0316336001600160a01b031614610c5b576040516282b42960e81b815260040160405180910390fd5b60c086013515610c7e5760405163577d3ffb60e01b815260040160405180910390fd5b683635c9adc5dea00000841180610c975750620186a083115b15610cb557604051630e52390960e41b815260040160405180910390fd5b60408051610100810190915280610ccf6020890189614d50565b6001600160a01b0316815260006020820152604090810190610cf79060608a01908a01614d50565b6001600160a01b0316815260200187606001358152602001858152602001848152602001600081526020016000815250604051602001610d379190615341565b60408051808303601f190181528282528051602091820120600089815260ff835283902055878352820186905281018490527f27a96079a4426127077f0e9053dceae2d9a50ad31109773b6cbef3683af0900b9060600160405180910390a1610da0600160fb55565b505050505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610df95760405162461bcd60e51b8152600401610df0906153a8565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610e426000805160206156ab833981519152546001600160a01b031690565b6001600160a01b031614610e685760405162461bcd60e51b8152600401610df0906153f4565b610e718161374f565b60408051600080825260208201909252610e8d91839190613757565b50565b818181604051602001610ea391906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610ee657604051636946eab760e01b815260040160405180910390fd5b610eee612cc5565b60c084013515610f115760405163577d3ffb60e01b815260040160405180910390fd5b6000610f206020860186614d50565b6001600160a01b031603610f4757604051630eb2e98f60e31b815260040160405180910390fd5b610f56338560800135346138c2565b60408051610100810190915280610f706020870187614d50565b6001600160a01b03168152336020820152604090810190610f979060608801908801614d50565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020014281526020016000815250604051602001610fde9190615341565b60408051601f198184030181529181528151602092830120600086815260ff90935291819020919091556110189060608601908601614d50565b6001600160a01b03166342842e0e303387606001356040518463ffffffff1660e01b815260040161104b939291906152f4565b600060405180830381600087803b15801561106557600080fd5b505af1158015611079573d6000803e3d6000fd5b50506040805186815233602082015242918101919091527f7018ea7d1ccfe49000acdb52059c03871a92ffb8da722f9b785ec81866cf00b892506060019050610ba8565b6110c561394d565b6001600160a01b03811660008181526101016020908152604091829020805460ff1916905590519182527fda68a0228a216daf1cfe2cbce9d172fc0d4a0181f04518aafae1cb2f8e638dee91015b60405180910390a150565b84848160405160200161113191906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461117457604051636946eab760e01b815260040160405180910390fd5b61117c612cc5565b61118c6040880160208901614d50565b6001600160a01b0316336001600160a01b0316146111bc576040516282b42960e81b815260040160405180910390fd5b60006111cb6020890189614d50565b6001600160a01b0316146111f257604051633c10be4b60e21b815260040160405180910390fd5b683635c9adc5dea0000084118061120b5750620186a083115b1561122957604051630e52390960e41b815260040160405180910390fd5b611241338661123c3460608c013561532e565b6138c2565b60405180610100016040528060006001600160a01b031681526020018860200160208101906112709190614d50565b6001600160a01b0316815260200161128e60608a0160408b01614d50565b6001600160a01b031681526020018681526020018581526020018481526020016000815260200160008152506040516020016112ca9190615341565b60408051808303601f19018152828252805160209182012060008a815260ff83528390205588835282018790528101859052606081018490527f699d32d6654f5041063117eee3b5e6d16b2af3e2c78347aabf2a48f0db5df84f9060800160405180910390a161133a600160fb55565b50505050505050565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361138b5760405162461bcd60e51b8152600401610df0906153a8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166113d46000805160206156ab833981519152546001600160a01b031690565b6001600160a01b0316146113fa5760405162461bcd60e51b8152600401610df0906153f4565b6114038261374f565b61140f82826001613757565b5050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146114b35760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610df0565b506000805160206156ab83398151915290565b8585816040516020016114d991906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461151c57604051636946eab760e01b815260040160405180910390fd5b611524612cc5565b611530888733346139a7565b61153c88888833613a13565b61159161154e368a90038a018a6152d7565b8960600135888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061346d92505050565b61159b600160fb55565b5050505050505050565b8787816040516020016115b891906151a8565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146115fb57604051636946eab760e01b815260040160405180910390fd5b611603612cc5565b61161360408b0160208c01614d50565b6001600160a01b0316336001600160a01b031614611643576040516282b42960e81b815260040160405180910390fd5b8960c00135600003611668576040516367bec58d60e01b815260040160405180910390fd5b6040516316147d4d60e31b815260808b0135600482015260a08b0135602482015260c08b0135604482015260009073d04eb5594b4e6b50c27d1062e2d22d5c10a299bf9063b0a3ea6890606401602060405180830381865af41580156116d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f69190615440565b90506000816117098a60808f0135615459565b6117139190615459565b905061172b61172560208e018e614d50565b83613b18565b801561177f578061010060008e602001602081019061174a9190614d50565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254611779919061532e565b90915550505b6040805161010081019091528061179960208f018f614d50565b6001600160a01b0316815260200160006001600160a01b031681526020018d60400160208101906117ca9190614d50565b6001600160a01b031681526020018b81526020018d6080013581526020018d60a00135815260200160008152602001600081525060405160200161180e9190615341565b60408051601f19818403018152918152815160209283012060008e815260ff90935291819020919091556118579061184c9060608f01908f01614d50565b8b8b8b8b8b8b613c3c565b604080518c8152602081018c90529081018a90527fac76107e19044e50d0526f5983962056aff4f8d4a4bb07a3730e609dc3cf9d129060600160405180910390a150506118a4600160fb55565b50505050505050505050565b6118b861394d565b6118c26000614166565b565b8383816040516020016118d791906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461191a57604051636946eab760e01b815260040160405180910390fd5b83838160405160200161192d91906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461197057604051636946eab760e01b815260040160405180910390fd5b611978612cc5565b6119886040890160208a01614d50565b6001600160a01b0316336001600160a01b0316146119b8576040516282b42960e81b815260040160405180910390fd5b8760c001356000036119dd576040516367bec58d60e01b815260040160405180910390fd5b60c086013515611a005760405163577d3ffb60e01b815260040160405180910390fd5b6000611a0f6020880188614d50565b6001600160a01b031603611a3657604051630eb2e98f60e31b815260040160405180910390fd5b611a466060870160408801614d50565b6001600160a01b0316611a5f60608a0160408b01614d50565b6001600160a01b031614611a86576040516352bbeac560e01b815260040160405180910390fd5b6040516316147d4d60e31b81526080890135600482015260a0890135602482015260c0890135604482015260009073d04eb5594b4e6b50c27d1062e2d22d5c10a299bf9063b0a3ea6890606401602060405180830381865af4158015611af0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b149190615440565b9050611b3633611b288360808b013561532e565b61123c3460808e013561532e565b611b4c611b4660208b018b614d50565b82613b18565b60408051610100810190915280611b6660208c018c614d50565b6001600160a01b0316815260006020820152604090810190611b8e9060608d01908d01614d50565b6001600160a01b03168152602001886060013581526020018a6080013581526020018a60a001358152602001600081526020016000815250604051602001611bd69190615341565b60408051601f19818403018152828252805160209182012060008c815260ff83528390205561010083019091528190611c11908a018a614d50565b6001600160a01b031681526020018a6020016020810190611c329190614d50565b6001600160a01b03168152602001611c5060608a0160408b01614d50565b6001600160a01b0316815260200188606001358152602001886080013581526020018860a0013581526020014281526020016000815250604051602001611c979190615341565b60408051601f19818403018152828252805160209182012060008a815260ff8352839020558a835282018890524282820152517fabdbeebdc0a5c123625afdabd45e1c7cb5193d257ae81f27aa8f9865e0b867fc9181900360600190a15061159b600160fb55565b818181604051602001611d1291906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414611d5557604051636946eab760e01b815260040160405180910390fd5b611d5d612cc5565b611d6a6020850185614d50565b6001600160a01b0316336001600160a01b031614611d9a576040516282b42960e81b815260040160405180910390fd5b8360c00135600003611dbf576040516367bec58d60e01b815260040160405180910390fd5b60e084013515611de25760405163647ccdcd60e11b815260040160405180910390fd5b60408051610100810190915280611dfc6020870187614d50565b6001600160a01b03168152602001856020016020810190611e1d9190614d50565b6001600160a01b03168152602001611e3b6060870160408801614d50565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020018560c00135815260200142815250604051602001611e859190615341565b60408051808303601f190181528282528051602091820120600087815260ff83528390205585835242908301527f8b31d3b4bc191b98ddfb3298ea923ba81c7121b9d7169f47a2cf1079c7010acf9101610ba8565b60655433906001600160a01b03168114611f485760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610df0565b610e8d81614166565b828281604051602001611f6491906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414611fa757604051636946eab760e01b815260040160405180910390fd5b611faf612cc5565b611fbf6040860160208701614d50565b6001600160a01b0316336001600160a01b031614611fef576040516282b42960e81b815260040160405180910390fd5b8460c00135600003612014576040516367bec58d60e01b815260040160405180910390fd5b61079a612026368790038701876152d7565b858561417f565b86868160405160200161204091906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461208357604051636946eab760e01b815260040160405180910390fd5b61208b612cc5565b612097898833346139a7565b6120a389898933613a13565b6109a16120b5368b90038b018b6152d7565b8a6060013589898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061434192505050565b600054610100900460ff16158080156121195750600054600160ff909116105b806121335750303b158015612133575060005460ff166001145b6121965760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610df0565b6000805460ff1916600117905580156121b9576000805461ff0019166101001790555b6121c1614440565b6121c9614467565b8015610e8d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611113565b81818160405160200161221e91906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461226157604051636946eab760e01b815260040160405180910390fd5b612269612cc5565b6122766020850185614d50565b6001600160a01b0316336001600160a01b0316146122a6576040516282b42960e81b815260040160405180910390fd5b60c0840135156122c95760405163577d3ffb60e01b815260040160405180910390fd5b600083815260ff6020526040808220919091556122ec9060608601908601614d50565b6001600160a01b03166323b872dd303387606001356040518463ffffffff1660e01b815260040161231f939291906152f4565b600060405180830381600087803b15801561233957600080fd5b505af115801561234d573d6000803e3d6000fd5b505050507fd18ab7eec3067b4a8e15f1c1f5299c77c05218c5718857eae55ac13c190f287583604051610ba891815260200190565b87878160405160200161239591906151a8565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146123d857604051636946eab760e01b815260040160405180910390fd5b6123e0612cc5565b6123f86123f2368c90038c018c6152d7565b886132fb565b61241361240a368c90038c018c6152d7565b8a8a8a3361337a565b61242360608b0160408c01614d50565b6001600160a01b03166323b872dd33308b6040518463ffffffff1660e01b8152600401612452939291906152f4565b600060405180830381600087803b15801561246c57600080fd5b505af1158015612480573d6000803e3d6000fd5b505050506124d88a80360381019061249891906152d7565b8989898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061434192505050565b6118a4600160fb55565b8181816040516020016124f591906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461253857604051636946eab760e01b815260040160405180910390fd5b612540612cc5565b6125506040850160208601614d50565b6001600160a01b0316336001600160a01b031614612580576040516282b42960e81b815260040160405180910390fd5b600061258f6020860186614d50565b6001600160a01b0316146125b657604051633c10be4b60e21b815260040160405180910390fd5b606084013561010060006125d06040880160208901614d50565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546125ff919061532e565b9091555050600083815260ff602052604080822091909155517f7687efe94566d20f7ebb8eff43bb57b2c014749dfd9ad179089e58c338ecdfa790610ba89085815260200190565b60608167ffffffffffffffff81111561266257612662614db5565b60405190808252806020026020018201604052801561269557816020015b60608152602001906001900390816126805790505b50905060005b8281101561273557612705308585848181106126b9576126b961546c565b90506020028101906126cb9190615482565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061449692505050565b8282815181106127175761271761546c565b6020026020010181905250808061272d906154c9565b91505061269b565b505b92915050565b61274561394d565b6001600160a01b03811660008181526101016020908152604091829020805460ff1916600117905590519182527f9d26696f1250d555e1136fcc68cc61c008bfdbc4edc53223e9e87ee94c530df59101611113565b6127a261394d565b6103e88111156127c557604051630e52390960e41b815260040160405180910390fd5b60fd8190556040518181527f2f1e1f4c9db00c1f5b9f1fb7b358f5beb59f9d4f72b9ba22a03240abf234494690602001611113565b612802612cc5565b3360009081526101006020526040812054908190036128215750612877565b336000818152610100602052604081205561283c9082613631565b60408051338152602081018390527f3efd984b5a13f92c04233a1e4a17098601b9effd13622786eab024424b9a4b02910160405180910390a1505b6118c2600160fb55565b600061288b612cc5565b683635c9adc5dea000008311806128a45750620186a082115b156128c257604051630e52390960e41b815260040160405180910390fd5b6128cd3385346138c2565b600060405180610100016040528060006001600160a01b03168152602001336001600160a01b03168152602001876001600160a01b0316815260200186815260200185815260200184815260200160008152602001600081525090508060405160200161293a9190615341565b60408051601f19818403018152828252805160209182012060fc805460018101909155600081815260ff84528490209190915580845233918401919091526001600160a01b03891683830152606083018890526080830187905260a0830186905290519093507f6386159f9aeea426c15aaec24295e5deef70a311ffe87a52fe8c875acc9941519181900360c00190a150610a3c600160fb55565b6129dd61394d565b606580546001600160a01b0383166001600160a01b03199091168117909155612a0e6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b612a4e61394d565b60fe54801561140f576001600160a01b038216612a7e57604051630e52390960e41b815260040160405180910390fd5b600060fe55612a966001600160a01b03831682613631565b604080516001600160a01b0384168152602081018390527f905d2a9b2639a94f09720cfd7b061c3b7a9e27921a009e954d67c8aff6e73667910160405180910390a15050565b818181604051602001612aef91906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414612b3257604051636946eab760e01b815260040160405180910390fd5b612b3a612cc5565b612b476020850185614d50565b6001600160a01b0316336001600160a01b031614612b77576040516282b42960e81b815260040160405180910390fd5b8360e00135600003612b9c576040516301dff5d560e71b815260040160405180910390fd5b612bac610e1060e086013561532e565b421015612bcc5760405163b882dff360e01b815260040160405180910390fd5b60408051610100810190915280612be66020870187614d50565b6001600160a01b03168152602001856020016020810190612c079190614d50565b6001600160a01b03168152602001612c256060870160408801614d50565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020018560c0013581526020016000815250604051602001612c709190615341565b60408051601f198184030181528282528051602091820120600087815260ff909252919020557f35dd1796423ce8f6a16296e4b6f10f75f26bc954cbb4014ae929416d0476abac90610ba89085815260200190565b600260fb5403612d175760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b600260fb55565b608084015160a085015160c08601516040516316147d4d60e31b815260009373d04eb5594b4e6b50c27d1062e2d22d5c10a299bf9363b0a3ea6893612d76936004019283526020830191909152604082015260600190565b602060405180830381865af4158015612d93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db79190615440565b9050600073d04eb5594b4e6b50c27d1062e2d22d5c10a299bf63b87a5ded838860800151612de59190615459565b60e0890151612df49042615459565b6040516001600160e01b031960e085901b168152600481019290925260248201526201fa406044820152606401602060405180830381865af4158015612e3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e629190615440565b9050600082828860800151612e779190615459565b612e819190615459565b90508015612ebd576020808801516001600160a01b03166000908152610100909152604081208054839290612eb790849061532e565b90915550505b612ed06001600160a01b03851683613631565b8651612edc9084613b18565b60405180610100016040528088600001516001600160a01b0316815260200160006001600160a01b0316815260200188604001516001600160a01b03168152602001868152602001886080015181526020018860a001518152602001600081526020016000815250604051602001612f549190615341565b60408051808303601f19018152828252805160209182012060008a815260ff8352839020558883526001600160a01b038716908301528101869052606081018390527fdd79deab13d35b6c83e88ee7f630110a06d72c9b0d6532310060518dce8946169060800160405180910390a150505050505050565b612fd4612cc5565b6040516331a9108f60e11b81526004810184905230903390636352211e90602401602060405180830381865afa158015613012573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303691906154e2565b6001600160a01b03161461305d57604051634f95e6e560e01b815260040160405180910390fd5b604081900361308e57600080613075838501856154ff565b9150915061308686338785856134ee565b5050506132f1565b6101208190036131bf576000806130a783850185615521565b91509150816040516020016130bc9190615341565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146130ff57604051636946eab760e01b815260040160405180910390fd5b81604001516001600160a01b0316336001600160a01b031614613135576040516352bbeac560e01b815260040160405180910390fd5b81602001516001600160a01b0316866001600160a01b031603613187578160c00151600003613177576040516367bec58d60e01b815260040160405180910390fd5b61318282828761417f565b6131b8565b8160e001516000036131ac576040516301dff5d560e71b815260040160405180910390fd5b6131b882828789612d1e565b50506132f1565b61018081106132d857600080808080806131db8789018961553f565b955095509550955095509550856040516020016131f89190615341565b60408051601f198184030181529181528151602092830120600088815260ff9093529120541461323b57604051636946eab760e01b815260040160405180910390fd5b85604001516001600160a01b0316336001600160a01b031614613271576040516352bbeac560e01b815260040160405180910390fd5b6001600160a01b0382166132a85761328986856132fb565b61329686868b878e61337a565b6132a3868a86868561346d565b6132cd565b6132b286856132fb565b6132bf86868b878e61337a565b6132cd868a86868686614341565b5050505050506132f1565b604051630e52390960e41b815260040160405180910390fd5b610bba600160fb55565b81516001600160a01b03161561332457604051633c10be4b60e21b815260040160405180910390fd5b8160800151818360600151613339919061532e565b6133439190615459565b6020808401516001600160a01b0316600090815261010090915260408120805490919061337190849061532e565b90915550505050565b604051806101000160405280826001600160a01b0316815260200186602001516001600160a01b0316815260200186604001516001600160a01b03168152602001848152602001866080015181526020018660a00151815260200142815260200160008152506040516020016133f09190615341565b60408051808303601f190181528282528051602091820120600088815260ff8352839020558683526001600160a01b038416908301528101849052606081018390524260808201527fa4797a6bc9b727c487bf6fc5d5e062bd2ba98a9e7777d09b10f8ebee56b9bcd59060a0015b60405180910390a15050505050565b6000613478836144c2565b905085604001516001600160a01b031663b88d4fde308588866040518563ffffffff1660e01b81526004016134b094939291906155cb565b600060405180830381600087803b1580156134ca57600080fd5b505af11580156134de573d6000803e3d6000fd5b50505050610da08686868461458e565b6000683635c9adc5dea000008311806135095750620186a082115b1561352757604051630e52390960e41b815260040160405180910390fd5b6000604051806101000160405280886001600160a01b0316815260200160006001600160a01b03168152602001876001600160a01b031681526020018681526020018581526020018481526020016000815260200160008152509050806040516020016135949190615341565b60408051601f19818403018152828252805160209182012060fc805460018101909155600081815260ff8452849020919091558084526001600160a01b038b81169285019290925290891683830152606083018890526080830187905260a0830186905290519093507f1d0c2455e7d4e618f457a481b4202c8e4837d7f73b41c7e136fa59e353f7bbaf9181900360c00190a15095945050505050565b804710156136815760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610df0565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146136ce576040519150601f19603f3d011682016040523d82523d6000602084013e6136d3565b606091505b505090508061374a5760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610df0565b505050565b610e8d61394d565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561378a5761374a83614747565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156137e4575060408051601f3d908101601f191682019092526137e191810190615440565b60015b6138475760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610df0565b6000805160206156ab83398151915281146138b65760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610df0565b5061374a8383836147e3565b80821115613908576138d48183615459565b6001600160a01b03841660009081526101006020526040812080549091906138fd908490615459565b9091555061374a9050565b8181111561374a5761391a8282615459565b6001600160a01b038416600090815261010060205260408120805490919061394390849061532e565b9091555050505050565b6033546001600160a01b031633146118c25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610df0565b60c0840135156139ca5760405163577d3ffb60e01b815260040160405180910390fd5b60006139d96020860186614d50565b6001600160a01b031603613a0057604051630eb2e98f60e31b815260040160405180910390fd5b610bba82608086013561123c848761532e565b60408051610100810190915280613a2d6020870187614d50565b6001600160a01b03168152602001826001600160a01b03168152602001856040016020810190613a5d9190614d50565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020014281526020016000815250604051602001613aa49190615341565b60408051808303601f190181528282528051602091820120600087815260ff8352839020558583526001600160a01b0384169083015281018390524260608201527f2a3d416f574ebbd2ff065eb2dcaa051e8193b2f928088debd9b826b5535d7bad9060800160405180910390a150505050565b60fd548015613bc7576040516311fbaf5560e31b8152600481018390526024810182905260009073d04eb5594b4e6b50c27d1062e2d22d5c10a299bf90638fdd7aa890604401602060405180830381865af4158015613b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9f9190615440565b90508060fe6000828254613bb3919061532e565b90915550613bc390508184615459565b9250505b6001600160a01b0383166000908152610100602052604081208054849290613bf090849061532e565b9091555050604080516001600160a01b0385168152602081018490527fdcf38454e4a88aabad69fa0440c623dba63d38fb63c4813ddb034e2fece02648910160405180910390a1505050565b6001600160a01b0383166000908152610101602052604090205460ff16613c7657604051635998d66f60e01b815260040160405180910390fd5b6040516331a9108f60e11b81526004810187905230906001600160a01b03891690636352211e90602401602060405180830381865afa158015613cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce191906154e2565b6001600160a01b031603613d08576040516362251d0d60e11b815260040160405180910390fd5b6040516370a0823160e01b815230600482015247906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015613d71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d959190615440565b905060006001600160a01b038716613e0f57856001600160a01b0316888686604051613dc29291906155fe565b60006040518083038185875af1925050503d8060008114613dff576040519150601f19603f3d011682016040523d82523d6000602084013e613e04565b606091505b505080915050613f7a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0896040518263ffffffff1660e01b81526004016000604051808303818588803b158015613e6a57600080fd5b505af1158015613e7e573d6000803e3d6000fd5b505060405163095ea7b360e01b81526001600160a01b038b81166004830152602482018d90527f000000000000000000000000000000000000000000000000000000000000000016935063095ea7b3925060440190506020604051808303816000875af1158015613ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f17919061560e565b50856001600160a01b03168585604051613f329291906155fe565b6000604051808303816000865af19150503d8060008114613f6f576040519150601f19603f3d011682016040523d82523d6000602084013e613f74565b606091505b50909150505b80613f9857604051635917920d60e11b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015613fff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140239190615440565b905080156140a657604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561408d57600080fd5b505af11580156140a1573d6000803e3d6000fd5b505050505b6040516331a9108f60e11b8152600481018b905230906001600160a01b038d1690636352211e90602401602060405180830381865afa1580156140ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061411191906154e2565b6001600160a01b031614158061413b5750884761412e858761532e565b6141389190615459565b14155b15614159576040516362251d0d60e11b815260040160405180910390fd5b5050505050505050505050565b606580546001600160a01b0319169055610e8d81614808565b608083015160a084015160c08501516040516316147d4d60e31b815260009373d04eb5594b4e6b50c27d1062e2d22d5c10a299bf9363b0a3ea68936141d7936004019283526020830191909152604082015260600190565b602060405180830381865af41580156141f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142189190615440565b9050600081856080015161422c9190615459565b90508015614268576020808601516001600160a01b0316600090815261010090915260408120805483929061426290849061532e565b90915550505b84516142749083613b18565b60405180610100016040528086600001516001600160a01b0316815260200160006001600160a01b0316815260200186604001516001600160a01b03168152602001848152602001866080015181526020018660a0015181526020016000815260200160008152506040516020016142ec9190615341565b60408051808303601f190181528282528051602091820120600088815260ff83528390205586835282018590527f7d7be60a03206cce6542b753ae6252f45891ec167a68dee14ed0a0439d2059df910161345e565b600061434c846144c2565b604080890151905163095ea7b360e01b81526001600160a01b038681166004830152602482018a905292935091169063095ea7b390604401600060405180830381600087803b15801561439e57600080fd5b505af11580156143b2573d6000803e3d6000fd5b505050506000846001600160a01b0316836040516143d09190615630565b6000604051808303816000865af19150503d806000811461440d576040519150601f19603f3d011682016040523d82523d6000602084013e614412565b606091505b505090508061443457604051635917920d60e11b815260040160405180910390fd5b61159b8888888561458e565b600054610100900460ff166118c25760405162461bcd60e51b8152600401610df09061564c565b600054610100900460ff1661448e5760405162461bcd60e51b8152600401610df09061564c565b6118c261485a565b60606144bb83836040518060600160405280602781526020016156cb6027913961488a565b9392505050565b6001600160a01b0381166000908152610101602052604081205460ff166144fc57604051635998d66f60e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015614560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145849190615440565b612737904761532e565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156145f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146199190615440565b9050801561469c57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561468357600080fd5b505af1158015614697573d6000803e3d6000fd5b505050505b60408581015190516331a9108f60e11b81526004810186905230916001600160a01b031690636352211e90602401602060405180830381865afa1580156146e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061470b91906154e2565b6001600160a01b031614806147295750826147268347615459565b14155b156108155760405163afe9b87960e01b815260040160405180910390fd5b6001600160a01b0381163b6147b45760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610df0565b6000805160206156ab83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6147ec83614902565b6000825111806147f95750805b1561374a57610bba8383614942565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166148815760405162461bcd60e51b8152600401610df09061564c565b6118c233614166565b6060600080856001600160a01b0316856040516148a79190615630565b600060405180830381855af49150503d80600081146148e2576040519150601f19603f3d011682016040523d82523d6000602084013e6148e7565b606091505b50915091506148f886838387614a36565b9695505050505050565b61490b81614747565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b6149aa5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610df0565b600080846001600160a01b0316846040516149c59190615630565b600060405180830381855af49150503d8060008114614a00576040519150601f19603f3d011682016040523d82523d6000602084013e614a05565b606091505b5091509150614a2d82826040518060600160405280602781526020016156cb60279139614aaf565b95945050505050565b60608315614aa5578251600003614a9e576001600160a01b0385163b614a9e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610df0565b5081610a3c565b610a3c8383614ac4565b60608315614abe5750816144bb565b6144bb83835b815115614ad45781518083602001fd5b8060405162461bcd60e51b8152600401610df09190615697565b60006101008284031215614b0157600080fd5b50919050565b60008060006101408486031215614b1d57600080fd5b614b278585614aee565b956101008501359550610120909401359392505050565b6001600160a01b0381168114610e8d57600080fd5b8035614b5e81614b3e565b919050565b60008083601f840112614b7557600080fd5b50813567ffffffffffffffff811115614b8d57600080fd5b602083019150836020828501011115614ba557600080fd5b9250929050565b600080600080600060808688031215614bc457600080fd5b8535614bcf81614b3e565b94506020860135614bdf81614b3e565b935060408601359250606086013567ffffffffffffffff811115614c0257600080fd5b614c0e88828901614b63565b969995985093965092949392505050565b60008060008060008060006101a0888a031215614c3b57600080fd5b614c458989614aee565b9650610100880135955061012088013594506101408801359350610160880135614c6e81614b3e565b925061018088013567ffffffffffffffff811115614c8b57600080fd5b614c978a828b01614b63565b989b979a50959850939692959293505050565b60008060008060808587031215614cc057600080fd5b8435614ccb81614b3e565b966020860135965060408601359560600135945092505050565b6000806101208385031215614cf957600080fd5b614d038484614aee565b94610100939093013593505050565b6000806000806101608587031215614d2957600080fd5b614d338686614aee565b966101008601359650610120860135956101400135945092505050565b600060208284031215614d6257600080fd5b81356144bb81614b3e565b60008060008060006101808688031215614d8657600080fd5b614d908787614aee565b9761010087013597506101208701359661014081013596506101600135945092505050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112614ddc57600080fd5b813567ffffffffffffffff80821115614df757614df7614db5565b604051601f8301601f19908116603f01168101908282118183101715614e1f57614e1f614db5565b81604052838152866020858801011115614e3857600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215614e6b57600080fd5b8235614e7681614b3e565b9150602083013567ffffffffffffffff811115614e9257600080fd5b614e9e85828601614dcb565b9150509250929050565b6000806000806000806101808789031215614ec257600080fd5b614ecc8888614aee565b955061010087013594506101208701359350610140870135614eed81614b3e565b925061016087013567ffffffffffffffff811115614f0a57600080fd5b614f1689828a01614b63565b979a9699509497509295939492505050565b6000806000806000806000806101c0898b031215614f4557600080fd5b614f4f8a8a614aee565b9750610100890135965061012089013595506101408901359450610160890135614f7881614b3e565b9350610180890135614f8981614b3e565b92506101a089013567ffffffffffffffff811115614fa657600080fd5b614fb28b828c01614b63565b999c989b5096995094979396929594505050565b6000806000806102408587031215614fdd57600080fd5b614fe78686614aee565b93506101008501359250614fff866101208701614aee565b939692955092936102200135925050565b60008060008060008060006101a0888a03121561502c57600080fd5b6150368989614aee565b96506101008801359550610120880135945061014088013561505781614b3e565b9350610160880135614c6e81614b3e565b6000806020838503121561507b57600080fd5b823567ffffffffffffffff8082111561509357600080fd5b818501915085601f8301126150a757600080fd5b8135818111156150b657600080fd5b8660208260051b85010111156150cb57600080fd5b60209290920196919550909350505050565b60005b838110156150f85781810151838201526020016150e0565b50506000910152565b600081518084526151198160208601602086016150dd565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561518257603f19888603018452615170858351615101565b94509285019290850190600101615154565b5092979650505050505050565b6000602082840312156151a157600080fd5b5035919050565b610100810182356151b881614b3e565b6001600160a01b0390811683526020840135906151d482614b3e565b90811660208401526040840135906151eb82614b3e565b80821660408501525050606083013560608301526080830135608083015260a083013560a083015260c083013560c083015260e083013560e083015292915050565b600061010080838503121561524157600080fd5b6040519081019067ffffffffffffffff8211818310171561526457615264614db5565b816040528092508335915061527882614b3e565b81815261528760208501614b53565b602082015261529860408501614b53565b6040820152606084013560608201526080840135608082015260a084013560a082015260c084013560c082015260e084013560e0820152505092915050565b600061010082840312156152ea57600080fd5b6144bb838361522d565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561273757612737615318565b60006101008201905060018060a01b0380845116835280602085015116602084015280604085015116604084015250606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015292915050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b60006020828403121561545257600080fd5b5051919050565b8181038181111561273757612737615318565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261549957600080fd5b83018035915067ffffffffffffffff8211156154b457600080fd5b602001915036819003821315614ba557600080fd5b6000600182016154db576154db615318565b5060010190565b6000602082840312156154f457600080fd5b81516144bb81614b3e565b6000806040838503121561551257600080fd5b50508035926020909101359150565b600080610120838503121561553557600080fd5b614d03848461522d565b6000806000806000806101a0878903121561555957600080fd5b615563888861522d565b95506101008701359450610120870135935061014087013561558481614b3e565b925061016087013561559581614b3e565b915061018087013567ffffffffffffffff8111156155b257600080fd5b6155be89828a01614dcb565b9150509295509295509295565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906148f890830184615101565b8183823760009101908152919050565b60006020828403121561562057600080fd5b815180151581146144bb57600080fd5b600082516156428184602087016150dd565b9190910192915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020815260006144bb602083018461510156fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d35bb0f79dcec9f8dbea8ef65aac6655f62f1a43cc785468973719f99496d2ea64736f6c63430008130033000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Deployed Bytecode
0x6080604052600436106102295760003560e01c80637f898fa011610123578063bde938cb116100ab578063e6200dc21161006f578063e6200dc214610675578063ea9cf4be1461068a578063f2fde38b1461069d578063f86c9e9a146106bd578063f8887546146106dd57600080fd5b8063bde938cb146105bc578063c63f6052146105dc578063d0bf9c5414610609578063d294cb0f14610629578063e30c39781461065757600080fd5b8063871ba096116100f2578063871ba096146104f05780638da5cb5b14610531578063a88acabd1461054f578063aa3296de1461056f578063ac9650d81461058f57600080fd5b80637f898fa0146104885780638077ec66146104a85780638129fc1c146104bb578063838a61f9146104d057600080fd5b80634489961a116101b15780636d8c39e4116101755780636d8c39e41461040b578063715018a61461042b57806377fa66561461044057806379942ba61461045357806379ba50971461047357600080fd5b80634489961a1461039d57806344ef1390146103bd5780634f1ef286146103d057806352d1902d146103e3578063564d200a146103f857600080fd5b8063335d0e13116101f8578063335d0e13146102fc5780633390f7111461032a57806333b9aa231461034a5780633659cfe61461036a5780633692aae41461038a57600080fd5b806302bfb2c814610235578063040141e514610257578063150b7a02146102a35780632a130bf2146102dc57600080fd5b3661023057005b600080fd5b34801561024157600080fd5b50610255610250366004614b07565b6106fd565b005b34801561026357600080fd5b507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102af57600080fd5b506102c36102be366004614bac565b61081c565b6040516001600160e01b0319909116815260200161029a565b3480156102e857600080fd5b506102556102f7366004614c1f565b61084c565b34801561030857600080fd5b5061031c610317366004614caa565b6109b6565b60405190815260200161029a565b34801561033657600080fd5b50610255610345366004614ce5565b610a44565b34801561035657600080fd5b50610255610365366004614d12565b610bc0565b34801561037657600080fd5b50610255610385366004614d50565b610da8565b610255610398366004614ce5565b610e90565b3480156103a957600080fd5b506102556103b8366004614d50565b6110bd565b6102556103cb366004614d6d565b61111e565b6102556103de366004614e58565b611343565b3480156103ef57600080fd5b5061031c611413565b610255610406366004614ea8565b6114c6565b34801561041757600080fd5b50610255610426366004614f28565b6115a5565b34801561043757600080fd5b506102556118b0565b61025561044e366004614fc6565b6118c4565b34801561045f57600080fd5b5061025561046e366004614ce5565b611cff565b34801561047f57600080fd5b50610255611eda565b34801561049457600080fd5b506102556104a3366004614b07565b611f51565b6102556104b6366004615010565b61202d565b3480156104c757600080fd5b506102556120f9565b3480156104dc57600080fd5b506102556104eb366004614ce5565b61220b565b3480156104fc57600080fd5b5061052161050b366004614d50565b6101016020526000908152604090205460ff1681565b604051901515815260200161029a565b34801561053d57600080fd5b506033546001600160a01b0316610286565b34801561055b57600080fd5b5061025561056a366004614f28565b612382565b34801561057b57600080fd5b5061025561058a366004614ce5565b6124e2565b34801561059b57600080fd5b506105af6105aa366004615068565b612647565b60405161029a919061512d565b3480156105c857600080fd5b506102556105d7366004614d50565b61273d565b3480156105e857600080fd5b5061031c6105f736600461518f565b60ff6020526000908152604090205481565b34801561061557600080fd5b5061025561062436600461518f565b61279a565b34801561063557600080fd5b5061031c610644366004614d50565b6101006020526000908152604090205481565b34801561066357600080fd5b506065546001600160a01b0316610286565b34801561068157600080fd5b506102556127fa565b61031c610698366004614caa565b612881565b3480156106a957600080fd5b506102556106b8366004614d50565b6129d5565b3480156106c957600080fd5b506102556106d8366004614d50565b612a46565b3480156106e957600080fd5b506102556106f8366004614ce5565b612adc565b82828160405160200161071091906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461075357604051636946eab760e01b815260040160405180910390fd5b61075b612cc5565b8460e00135600003610780576040516301dff5d560e71b815260040160405180910390fd5b61079a610792368790038701876152d7565b858533612d1e565b6107aa6060860160408701614d50565b6001600160a01b03166323b872dd3330866040518463ffffffff1660e01b81526004016107d9939291906152f4565b600060405180830381600087803b1580156107f357600080fd5b505af1158015610807573d6000803e3d6000fd5b50505050610815600160fb55565b5050505050565b600061082a60fb5460021490565b61083a5761083a85858585612fcc565b50630a85bd0160e11b95945050505050565b86868160405160200161085f91906151a8565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146108a257604051636946eab760e01b815260040160405180910390fd5b6108aa612cc5565b6108c26108bc368b90038b018b6152d7565b876132fb565b6108dd6108d4368b90038b018b6152d7565b8989893361337a565b6108ed60608a0160408b01614d50565b6001600160a01b03166323b872dd33308a6040518463ffffffff1660e01b815260040161091c939291906152f4565b600060405180830381600087803b15801561093657600080fd5b505af115801561094a573d6000803e3d6000fd5b505050506109a18980360381019061096291906152d7565b88888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061346d92505050565b6109ab600160fb55565b505050505050505050565b60006109c0612cc5565b6109cd33868686866134ee565b6040516323b872dd60e01b81529091506001600160a01b038616906323b872dd90610a00903390309089906004016152f4565b600060405180830381600087803b158015610a1a57600080fd5b505af1158015610a2e573d6000803e3d6000fd5b50505050610a3c600160fb55565b949350505050565b818181604051602001610a5791906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610a9a57604051636946eab760e01b815260040160405180910390fd5b610aa2612cc5565b610aaf6020850185614d50565b6001600160a01b0316336001600160a01b031614610adf576040516282b42960e81b815260040160405180910390fd5b8360c00135600003610b04576040516367bec58d60e01b815260040160405180910390fd5b60e08401351580610b255750610b216201fa4060e086013561532e565b4211155b15610b4357604051633f3db73560e21b815260040160405180910390fd5b600083815260ff60209081526040822091909155610b7c90608086013590610b6d90870187614d50565b6001600160a01b031690613631565b6040518381527f94effa14ea3a1ef396fa2fd829336d1597f1d76b548c26bfa2332869706638af906020015b60405180910390a1610bba600160fb55565b50505050565b838381604051602001610bd391906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610c1657604051636946eab760e01b815260040160405180910390fd5b610c1e612cc5565b610c2b6020870187614d50565b6001600160a01b0316336001600160a01b031614610c5b576040516282b42960e81b815260040160405180910390fd5b60c086013515610c7e5760405163577d3ffb60e01b815260040160405180910390fd5b683635c9adc5dea00000841180610c975750620186a083115b15610cb557604051630e52390960e41b815260040160405180910390fd5b60408051610100810190915280610ccf6020890189614d50565b6001600160a01b0316815260006020820152604090810190610cf79060608a01908a01614d50565b6001600160a01b0316815260200187606001358152602001858152602001848152602001600081526020016000815250604051602001610d379190615341565b60408051808303601f190181528282528051602091820120600089815260ff835283902055878352820186905281018490527f27a96079a4426127077f0e9053dceae2d9a50ad31109773b6cbef3683af0900b9060600160405180910390a1610da0600160fb55565b505050505050565b6001600160a01b037f000000000000000000000000e4764f9cd8ecc9659d3abf35259638b20ac536e4163003610df95760405162461bcd60e51b8152600401610df0906153a8565b60405180910390fd5b7f000000000000000000000000e4764f9cd8ecc9659d3abf35259638b20ac536e46001600160a01b0316610e426000805160206156ab833981519152546001600160a01b031690565b6001600160a01b031614610e685760405162461bcd60e51b8152600401610df0906153f4565b610e718161374f565b60408051600080825260208201909252610e8d91839190613757565b50565b818181604051602001610ea391906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414610ee657604051636946eab760e01b815260040160405180910390fd5b610eee612cc5565b60c084013515610f115760405163577d3ffb60e01b815260040160405180910390fd5b6000610f206020860186614d50565b6001600160a01b031603610f4757604051630eb2e98f60e31b815260040160405180910390fd5b610f56338560800135346138c2565b60408051610100810190915280610f706020870187614d50565b6001600160a01b03168152336020820152604090810190610f979060608801908801614d50565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020014281526020016000815250604051602001610fde9190615341565b60408051601f198184030181529181528151602092830120600086815260ff90935291819020919091556110189060608601908601614d50565b6001600160a01b03166342842e0e303387606001356040518463ffffffff1660e01b815260040161104b939291906152f4565b600060405180830381600087803b15801561106557600080fd5b505af1158015611079573d6000803e3d6000fd5b50506040805186815233602082015242918101919091527f7018ea7d1ccfe49000acdb52059c03871a92ffb8da722f9b785ec81866cf00b892506060019050610ba8565b6110c561394d565b6001600160a01b03811660008181526101016020908152604091829020805460ff1916905590519182527fda68a0228a216daf1cfe2cbce9d172fc0d4a0181f04518aafae1cb2f8e638dee91015b60405180910390a150565b84848160405160200161113191906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461117457604051636946eab760e01b815260040160405180910390fd5b61117c612cc5565b61118c6040880160208901614d50565b6001600160a01b0316336001600160a01b0316146111bc576040516282b42960e81b815260040160405180910390fd5b60006111cb6020890189614d50565b6001600160a01b0316146111f257604051633c10be4b60e21b815260040160405180910390fd5b683635c9adc5dea0000084118061120b5750620186a083115b1561122957604051630e52390960e41b815260040160405180910390fd5b611241338661123c3460608c013561532e565b6138c2565b60405180610100016040528060006001600160a01b031681526020018860200160208101906112709190614d50565b6001600160a01b0316815260200161128e60608a0160408b01614d50565b6001600160a01b031681526020018681526020018581526020018481526020016000815260200160008152506040516020016112ca9190615341565b60408051808303601f19018152828252805160209182012060008a815260ff83528390205588835282018790528101859052606081018490527f699d32d6654f5041063117eee3b5e6d16b2af3e2c78347aabf2a48f0db5df84f9060800160405180910390a161133a600160fb55565b50505050505050565b6001600160a01b037f000000000000000000000000e4764f9cd8ecc9659d3abf35259638b20ac536e416300361138b5760405162461bcd60e51b8152600401610df0906153a8565b7f000000000000000000000000e4764f9cd8ecc9659d3abf35259638b20ac536e46001600160a01b03166113d46000805160206156ab833981519152546001600160a01b031690565b6001600160a01b0316146113fa5760405162461bcd60e51b8152600401610df0906153f4565b6114038261374f565b61140f82826001613757565b5050565b6000306001600160a01b037f000000000000000000000000e4764f9cd8ecc9659d3abf35259638b20ac536e416146114b35760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610df0565b506000805160206156ab83398151915290565b8585816040516020016114d991906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461151c57604051636946eab760e01b815260040160405180910390fd5b611524612cc5565b611530888733346139a7565b61153c88888833613a13565b61159161154e368a90038a018a6152d7565b8960600135888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061346d92505050565b61159b600160fb55565b5050505050505050565b8787816040516020016115b891906151a8565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146115fb57604051636946eab760e01b815260040160405180910390fd5b611603612cc5565b61161360408b0160208c01614d50565b6001600160a01b0316336001600160a01b031614611643576040516282b42960e81b815260040160405180910390fd5b8960c00135600003611668576040516367bec58d60e01b815260040160405180910390fd5b6040516316147d4d60e31b815260808b0135600482015260a08b0135602482015260c08b0135604482015260009073d04eb5594b4e6b50c27d1062e2d22d5c10a299bf9063b0a3ea6890606401602060405180830381865af41580156116d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f69190615440565b90506000816117098a60808f0135615459565b6117139190615459565b905061172b61172560208e018e614d50565b83613b18565b801561177f578061010060008e602001602081019061174a9190614d50565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254611779919061532e565b90915550505b6040805161010081019091528061179960208f018f614d50565b6001600160a01b0316815260200160006001600160a01b031681526020018d60400160208101906117ca9190614d50565b6001600160a01b031681526020018b81526020018d6080013581526020018d60a00135815260200160008152602001600081525060405160200161180e9190615341565b60408051601f19818403018152918152815160209283012060008e815260ff90935291819020919091556118579061184c9060608f01908f01614d50565b8b8b8b8b8b8b613c3c565b604080518c8152602081018c90529081018a90527fac76107e19044e50d0526f5983962056aff4f8d4a4bb07a3730e609dc3cf9d129060600160405180910390a150506118a4600160fb55565b50505050505050505050565b6118b861394d565b6118c26000614166565b565b8383816040516020016118d791906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461191a57604051636946eab760e01b815260040160405180910390fd5b83838160405160200161192d91906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461197057604051636946eab760e01b815260040160405180910390fd5b611978612cc5565b6119886040890160208a01614d50565b6001600160a01b0316336001600160a01b0316146119b8576040516282b42960e81b815260040160405180910390fd5b8760c001356000036119dd576040516367bec58d60e01b815260040160405180910390fd5b60c086013515611a005760405163577d3ffb60e01b815260040160405180910390fd5b6000611a0f6020880188614d50565b6001600160a01b031603611a3657604051630eb2e98f60e31b815260040160405180910390fd5b611a466060870160408801614d50565b6001600160a01b0316611a5f60608a0160408b01614d50565b6001600160a01b031614611a86576040516352bbeac560e01b815260040160405180910390fd5b6040516316147d4d60e31b81526080890135600482015260a0890135602482015260c0890135604482015260009073d04eb5594b4e6b50c27d1062e2d22d5c10a299bf9063b0a3ea6890606401602060405180830381865af4158015611af0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b149190615440565b9050611b3633611b288360808b013561532e565b61123c3460808e013561532e565b611b4c611b4660208b018b614d50565b82613b18565b60408051610100810190915280611b6660208c018c614d50565b6001600160a01b0316815260006020820152604090810190611b8e9060608d01908d01614d50565b6001600160a01b03168152602001886060013581526020018a6080013581526020018a60a001358152602001600081526020016000815250604051602001611bd69190615341565b60408051601f19818403018152828252805160209182012060008c815260ff83528390205561010083019091528190611c11908a018a614d50565b6001600160a01b031681526020018a6020016020810190611c329190614d50565b6001600160a01b03168152602001611c5060608a0160408b01614d50565b6001600160a01b0316815260200188606001358152602001886080013581526020018860a0013581526020014281526020016000815250604051602001611c979190615341565b60408051601f19818403018152828252805160209182012060008a815260ff8352839020558a835282018890524282820152517fabdbeebdc0a5c123625afdabd45e1c7cb5193d257ae81f27aa8f9865e0b867fc9181900360600190a15061159b600160fb55565b818181604051602001611d1291906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414611d5557604051636946eab760e01b815260040160405180910390fd5b611d5d612cc5565b611d6a6020850185614d50565b6001600160a01b0316336001600160a01b031614611d9a576040516282b42960e81b815260040160405180910390fd5b8360c00135600003611dbf576040516367bec58d60e01b815260040160405180910390fd5b60e084013515611de25760405163647ccdcd60e11b815260040160405180910390fd5b60408051610100810190915280611dfc6020870187614d50565b6001600160a01b03168152602001856020016020810190611e1d9190614d50565b6001600160a01b03168152602001611e3b6060870160408801614d50565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020018560c00135815260200142815250604051602001611e859190615341565b60408051808303601f190181528282528051602091820120600087815260ff83528390205585835242908301527f8b31d3b4bc191b98ddfb3298ea923ba81c7121b9d7169f47a2cf1079c7010acf9101610ba8565b60655433906001600160a01b03168114611f485760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401610df0565b610e8d81614166565b828281604051602001611f6491906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414611fa757604051636946eab760e01b815260040160405180910390fd5b611faf612cc5565b611fbf6040860160208701614d50565b6001600160a01b0316336001600160a01b031614611fef576040516282b42960e81b815260040160405180910390fd5b8460c00135600003612014576040516367bec58d60e01b815260040160405180910390fd5b61079a612026368790038701876152d7565b858561417f565b86868160405160200161204091906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461208357604051636946eab760e01b815260040160405180910390fd5b61208b612cc5565b612097898833346139a7565b6120a389898933613a13565b6109a16120b5368b90038b018b6152d7565b8a6060013589898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061434192505050565b600054610100900460ff16158080156121195750600054600160ff909116105b806121335750303b158015612133575060005460ff166001145b6121965760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610df0565b6000805460ff1916600117905580156121b9576000805461ff0019166101001790555b6121c1614440565b6121c9614467565b8015610e8d576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001611113565b81818160405160200161221e91906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461226157604051636946eab760e01b815260040160405180910390fd5b612269612cc5565b6122766020850185614d50565b6001600160a01b0316336001600160a01b0316146122a6576040516282b42960e81b815260040160405180910390fd5b60c0840135156122c95760405163577d3ffb60e01b815260040160405180910390fd5b600083815260ff6020526040808220919091556122ec9060608601908601614d50565b6001600160a01b03166323b872dd303387606001356040518463ffffffff1660e01b815260040161231f939291906152f4565b600060405180830381600087803b15801561233957600080fd5b505af115801561234d573d6000803e3d6000fd5b505050507fd18ab7eec3067b4a8e15f1c1f5299c77c05218c5718857eae55ac13c190f287583604051610ba891815260200190565b87878160405160200161239591906151a8565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146123d857604051636946eab760e01b815260040160405180910390fd5b6123e0612cc5565b6123f86123f2368c90038c018c6152d7565b886132fb565b61241361240a368c90038c018c6152d7565b8a8a8a3361337a565b61242360608b0160408c01614d50565b6001600160a01b03166323b872dd33308b6040518463ffffffff1660e01b8152600401612452939291906152f4565b600060405180830381600087803b15801561246c57600080fd5b505af1158015612480573d6000803e3d6000fd5b505050506124d88a80360381019061249891906152d7565b8989898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061434192505050565b6118a4600160fb55565b8181816040516020016124f591906151a8565b60408051601f198184030181529181528151602092830120600084815260ff9093529120541461253857604051636946eab760e01b815260040160405180910390fd5b612540612cc5565b6125506040850160208601614d50565b6001600160a01b0316336001600160a01b031614612580576040516282b42960e81b815260040160405180910390fd5b600061258f6020860186614d50565b6001600160a01b0316146125b657604051633c10be4b60e21b815260040160405180910390fd5b606084013561010060006125d06040880160208901614d50565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008282546125ff919061532e565b9091555050600083815260ff602052604080822091909155517f7687efe94566d20f7ebb8eff43bb57b2c014749dfd9ad179089e58c338ecdfa790610ba89085815260200190565b60608167ffffffffffffffff81111561266257612662614db5565b60405190808252806020026020018201604052801561269557816020015b60608152602001906001900390816126805790505b50905060005b8281101561273557612705308585848181106126b9576126b961546c565b90506020028101906126cb9190615482565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061449692505050565b8282815181106127175761271761546c565b6020026020010181905250808061272d906154c9565b91505061269b565b505b92915050565b61274561394d565b6001600160a01b03811660008181526101016020908152604091829020805460ff1916600117905590519182527f9d26696f1250d555e1136fcc68cc61c008bfdbc4edc53223e9e87ee94c530df59101611113565b6127a261394d565b6103e88111156127c557604051630e52390960e41b815260040160405180910390fd5b60fd8190556040518181527f2f1e1f4c9db00c1f5b9f1fb7b358f5beb59f9d4f72b9ba22a03240abf234494690602001611113565b612802612cc5565b3360009081526101006020526040812054908190036128215750612877565b336000818152610100602052604081205561283c9082613631565b60408051338152602081018390527f3efd984b5a13f92c04233a1e4a17098601b9effd13622786eab024424b9a4b02910160405180910390a1505b6118c2600160fb55565b600061288b612cc5565b683635c9adc5dea000008311806128a45750620186a082115b156128c257604051630e52390960e41b815260040160405180910390fd5b6128cd3385346138c2565b600060405180610100016040528060006001600160a01b03168152602001336001600160a01b03168152602001876001600160a01b0316815260200186815260200185815260200184815260200160008152602001600081525090508060405160200161293a9190615341565b60408051601f19818403018152828252805160209182012060fc805460018101909155600081815260ff84528490209190915580845233918401919091526001600160a01b03891683830152606083018890526080830187905260a0830186905290519093507f6386159f9aeea426c15aaec24295e5deef70a311ffe87a52fe8c875acc9941519181900360c00190a150610a3c600160fb55565b6129dd61394d565b606580546001600160a01b0383166001600160a01b03199091168117909155612a0e6033546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b612a4e61394d565b60fe54801561140f576001600160a01b038216612a7e57604051630e52390960e41b815260040160405180910390fd5b600060fe55612a966001600160a01b03831682613631565b604080516001600160a01b0384168152602081018390527f905d2a9b2639a94f09720cfd7b061c3b7a9e27921a009e954d67c8aff6e73667910160405180910390a15050565b818181604051602001612aef91906151a8565b60408051601f198184030181529181528151602092830120600084815260ff90935291205414612b3257604051636946eab760e01b815260040160405180910390fd5b612b3a612cc5565b612b476020850185614d50565b6001600160a01b0316336001600160a01b031614612b77576040516282b42960e81b815260040160405180910390fd5b8360e00135600003612b9c576040516301dff5d560e71b815260040160405180910390fd5b612bac610e1060e086013561532e565b421015612bcc5760405163b882dff360e01b815260040160405180910390fd5b60408051610100810190915280612be66020870187614d50565b6001600160a01b03168152602001856020016020810190612c079190614d50565b6001600160a01b03168152602001612c256060870160408801614d50565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020018560c0013581526020016000815250604051602001612c709190615341565b60408051601f198184030181528282528051602091820120600087815260ff909252919020557f35dd1796423ce8f6a16296e4b6f10f75f26bc954cbb4014ae929416d0476abac90610ba89085815260200190565b600260fb5403612d175760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610df0565b600260fb55565b608084015160a085015160c08601516040516316147d4d60e31b815260009373d04eb5594b4e6b50c27d1062e2d22d5c10a299bf9363b0a3ea6893612d76936004019283526020830191909152604082015260600190565b602060405180830381865af4158015612d93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612db79190615440565b9050600073d04eb5594b4e6b50c27d1062e2d22d5c10a299bf63b87a5ded838860800151612de59190615459565b60e0890151612df49042615459565b6040516001600160e01b031960e085901b168152600481019290925260248201526201fa406044820152606401602060405180830381865af4158015612e3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e629190615440565b9050600082828860800151612e779190615459565b612e819190615459565b90508015612ebd576020808801516001600160a01b03166000908152610100909152604081208054839290612eb790849061532e565b90915550505b612ed06001600160a01b03851683613631565b8651612edc9084613b18565b60405180610100016040528088600001516001600160a01b0316815260200160006001600160a01b0316815260200188604001516001600160a01b03168152602001868152602001886080015181526020018860a001518152602001600081526020016000815250604051602001612f549190615341565b60408051808303601f19018152828252805160209182012060008a815260ff8352839020558883526001600160a01b038716908301528101869052606081018390527fdd79deab13d35b6c83e88ee7f630110a06d72c9b0d6532310060518dce8946169060800160405180910390a150505050505050565b612fd4612cc5565b6040516331a9108f60e11b81526004810184905230903390636352211e90602401602060405180830381865afa158015613012573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061303691906154e2565b6001600160a01b03161461305d57604051634f95e6e560e01b815260040160405180910390fd5b604081900361308e57600080613075838501856154ff565b9150915061308686338785856134ee565b5050506132f1565b6101208190036131bf576000806130a783850185615521565b91509150816040516020016130bc9190615341565b60408051601f198184030181529181528151602092830120600084815260ff909352912054146130ff57604051636946eab760e01b815260040160405180910390fd5b81604001516001600160a01b0316336001600160a01b031614613135576040516352bbeac560e01b815260040160405180910390fd5b81602001516001600160a01b0316866001600160a01b031603613187578160c00151600003613177576040516367bec58d60e01b815260040160405180910390fd5b61318282828761417f565b6131b8565b8160e001516000036131ac576040516301dff5d560e71b815260040160405180910390fd5b6131b882828789612d1e565b50506132f1565b61018081106132d857600080808080806131db8789018961553f565b955095509550955095509550856040516020016131f89190615341565b60408051601f198184030181529181528151602092830120600088815260ff9093529120541461323b57604051636946eab760e01b815260040160405180910390fd5b85604001516001600160a01b0316336001600160a01b031614613271576040516352bbeac560e01b815260040160405180910390fd5b6001600160a01b0382166132a85761328986856132fb565b61329686868b878e61337a565b6132a3868a86868561346d565b6132cd565b6132b286856132fb565b6132bf86868b878e61337a565b6132cd868a86868686614341565b5050505050506132f1565b604051630e52390960e41b815260040160405180910390fd5b610bba600160fb55565b81516001600160a01b03161561332457604051633c10be4b60e21b815260040160405180910390fd5b8160800151818360600151613339919061532e565b6133439190615459565b6020808401516001600160a01b0316600090815261010090915260408120805490919061337190849061532e565b90915550505050565b604051806101000160405280826001600160a01b0316815260200186602001516001600160a01b0316815260200186604001516001600160a01b03168152602001848152602001866080015181526020018660a00151815260200142815260200160008152506040516020016133f09190615341565b60408051808303601f190181528282528051602091820120600088815260ff8352839020558683526001600160a01b038416908301528101849052606081018390524260808201527fa4797a6bc9b727c487bf6fc5d5e062bd2ba98a9e7777d09b10f8ebee56b9bcd59060a0015b60405180910390a15050505050565b6000613478836144c2565b905085604001516001600160a01b031663b88d4fde308588866040518563ffffffff1660e01b81526004016134b094939291906155cb565b600060405180830381600087803b1580156134ca57600080fd5b505af11580156134de573d6000803e3d6000fd5b50505050610da08686868461458e565b6000683635c9adc5dea000008311806135095750620186a082115b1561352757604051630e52390960e41b815260040160405180910390fd5b6000604051806101000160405280886001600160a01b0316815260200160006001600160a01b03168152602001876001600160a01b031681526020018681526020018581526020018481526020016000815260200160008152509050806040516020016135949190615341565b60408051601f19818403018152828252805160209182012060fc805460018101909155600081815260ff8452849020919091558084526001600160a01b038b81169285019290925290891683830152606083018890526080830187905260a0830186905290519093507f1d0c2455e7d4e618f457a481b4202c8e4837d7f73b41c7e136fa59e353f7bbaf9181900360c00190a15095945050505050565b804710156136815760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610df0565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146136ce576040519150601f19603f3d011682016040523d82523d6000602084013e6136d3565b606091505b505090508061374a5760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610df0565b505050565b610e8d61394d565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561378a5761374a83614747565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156137e4575060408051601f3d908101601f191682019092526137e191810190615440565b60015b6138475760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608401610df0565b6000805160206156ab83398151915281146138b65760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608401610df0565b5061374a8383836147e3565b80821115613908576138d48183615459565b6001600160a01b03841660009081526101006020526040812080549091906138fd908490615459565b9091555061374a9050565b8181111561374a5761391a8282615459565b6001600160a01b038416600090815261010060205260408120805490919061394390849061532e565b9091555050505050565b6033546001600160a01b031633146118c25760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610df0565b60c0840135156139ca5760405163577d3ffb60e01b815260040160405180910390fd5b60006139d96020860186614d50565b6001600160a01b031603613a0057604051630eb2e98f60e31b815260040160405180910390fd5b610bba82608086013561123c848761532e565b60408051610100810190915280613a2d6020870187614d50565b6001600160a01b03168152602001826001600160a01b03168152602001856040016020810190613a5d9190614d50565b6001600160a01b0316815260200185606001358152602001856080013581526020018560a0013581526020014281526020016000815250604051602001613aa49190615341565b60408051808303601f190181528282528051602091820120600087815260ff8352839020558583526001600160a01b0384169083015281018390524260608201527f2a3d416f574ebbd2ff065eb2dcaa051e8193b2f928088debd9b826b5535d7bad9060800160405180910390a150505050565b60fd548015613bc7576040516311fbaf5560e31b8152600481018390526024810182905260009073d04eb5594b4e6b50c27d1062e2d22d5c10a299bf90638fdd7aa890604401602060405180830381865af4158015613b7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9f9190615440565b90508060fe6000828254613bb3919061532e565b90915550613bc390508184615459565b9250505b6001600160a01b0383166000908152610100602052604081208054849290613bf090849061532e565b9091555050604080516001600160a01b0385168152602081018490527fdcf38454e4a88aabad69fa0440c623dba63d38fb63c4813ddb034e2fece02648910160405180910390a1505050565b6001600160a01b0383166000908152610101602052604090205460ff16613c7657604051635998d66f60e01b815260040160405180910390fd5b6040516331a9108f60e11b81526004810187905230906001600160a01b03891690636352211e90602401602060405180830381865afa158015613cbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ce191906154e2565b6001600160a01b031603613d08576040516362251d0d60e11b815260040160405180910390fd5b6040516370a0823160e01b815230600482015247906000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa158015613d71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d959190615440565b905060006001600160a01b038716613e0f57856001600160a01b0316888686604051613dc29291906155fe565b60006040518083038185875af1925050503d8060008114613dff576040519150601f19603f3d011682016040523d82523d6000602084013e613e04565b606091505b505080915050613f7a565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0896040518263ffffffff1660e01b81526004016000604051808303818588803b158015613e6a57600080fd5b505af1158015613e7e573d6000803e3d6000fd5b505060405163095ea7b360e01b81526001600160a01b038b81166004830152602482018d90527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216935063095ea7b3925060440190506020604051808303816000875af1158015613ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f17919061560e565b50856001600160a01b03168585604051613f329291906155fe565b6000604051808303816000865af19150503d8060008114613f6f576040519150601f19603f3d011682016040523d82523d6000602084013e613f74565b606091505b50909150505b80613f9857604051635917920d60e11b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa158015613fff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140239190615440565b905080156140a657604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561408d57600080fd5b505af11580156140a1573d6000803e3d6000fd5b505050505b6040516331a9108f60e11b8152600481018b905230906001600160a01b038d1690636352211e90602401602060405180830381865afa1580156140ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061411191906154e2565b6001600160a01b031614158061413b5750884761412e858761532e565b6141389190615459565b14155b15614159576040516362251d0d60e11b815260040160405180910390fd5b5050505050505050505050565b606580546001600160a01b0319169055610e8d81614808565b608083015160a084015160c08501516040516316147d4d60e31b815260009373d04eb5594b4e6b50c27d1062e2d22d5c10a299bf9363b0a3ea68936141d7936004019283526020830191909152604082015260600190565b602060405180830381865af41580156141f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142189190615440565b9050600081856080015161422c9190615459565b90508015614268576020808601516001600160a01b0316600090815261010090915260408120805483929061426290849061532e565b90915550505b84516142749083613b18565b60405180610100016040528086600001516001600160a01b0316815260200160006001600160a01b0316815260200186604001516001600160a01b03168152602001848152602001866080015181526020018660a0015181526020016000815260200160008152506040516020016142ec9190615341565b60408051808303601f190181528282528051602091820120600088815260ff83528390205586835282018590527f7d7be60a03206cce6542b753ae6252f45891ec167a68dee14ed0a0439d2059df910161345e565b600061434c846144c2565b604080890151905163095ea7b360e01b81526001600160a01b038681166004830152602482018a905292935091169063095ea7b390604401600060405180830381600087803b15801561439e57600080fd5b505af11580156143b2573d6000803e3d6000fd5b505050506000846001600160a01b0316836040516143d09190615630565b6000604051808303816000865af19150503d806000811461440d576040519150601f19603f3d011682016040523d82523d6000602084013e614412565b606091505b505090508061443457604051635917920d60e11b815260040160405180910390fd5b61159b8888888561458e565b600054610100900460ff166118c25760405162461bcd60e51b8152600401610df09061564c565b600054610100900460ff1661448e5760405162461bcd60e51b8152600401610df09061564c565b6118c261485a565b60606144bb83836040518060600160405280602781526020016156cb6027913961488a565b9392505050565b6001600160a01b0381166000908152610101602052604081205460ff166144fc57604051635998d66f60e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa158015614560573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145849190615440565b612737904761532e565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401602060405180830381865afa1580156145f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146199190615440565b9050801561469c57604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561468357600080fd5b505af1158015614697573d6000803e3d6000fd5b505050505b60408581015190516331a9108f60e11b81526004810186905230916001600160a01b031690636352211e90602401602060405180830381865afa1580156146e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061470b91906154e2565b6001600160a01b031614806147295750826147268347615459565b14155b156108155760405163afe9b87960e01b815260040160405180910390fd5b6001600160a01b0381163b6147b45760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610df0565b6000805160206156ab83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6147ec83614902565b6000825111806147f95750805b1561374a57610bba8383614942565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166148815760405162461bcd60e51b8152600401610df09061564c565b6118c233614166565b6060600080856001600160a01b0316856040516148a79190615630565b600060405180830381855af49150503d80600081146148e2576040519150601f19603f3d011682016040523d82523d6000602084013e6148e7565b606091505b50915091506148f886838387614a36565b9695505050505050565b61490b81614747565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b6149aa5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610df0565b600080846001600160a01b0316846040516149c59190615630565b600060405180830381855af49150503d8060008114614a00576040519150601f19603f3d011682016040523d82523d6000602084013e614a05565b606091505b5091509150614a2d82826040518060600160405280602781526020016156cb60279139614aaf565b95945050505050565b60608315614aa5578251600003614a9e576001600160a01b0385163b614a9e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610df0565b5081610a3c565b610a3c8383614ac4565b60608315614abe5750816144bb565b6144bb83835b815115614ad45781518083602001fd5b8060405162461bcd60e51b8152600401610df09190615697565b60006101008284031215614b0157600080fd5b50919050565b60008060006101408486031215614b1d57600080fd5b614b278585614aee565b956101008501359550610120909401359392505050565b6001600160a01b0381168114610e8d57600080fd5b8035614b5e81614b3e565b919050565b60008083601f840112614b7557600080fd5b50813567ffffffffffffffff811115614b8d57600080fd5b602083019150836020828501011115614ba557600080fd5b9250929050565b600080600080600060808688031215614bc457600080fd5b8535614bcf81614b3e565b94506020860135614bdf81614b3e565b935060408601359250606086013567ffffffffffffffff811115614c0257600080fd5b614c0e88828901614b63565b969995985093965092949392505050565b60008060008060008060006101a0888a031215614c3b57600080fd5b614c458989614aee565b9650610100880135955061012088013594506101408801359350610160880135614c6e81614b3e565b925061018088013567ffffffffffffffff811115614c8b57600080fd5b614c978a828b01614b63565b989b979a50959850939692959293505050565b60008060008060808587031215614cc057600080fd5b8435614ccb81614b3e565b966020860135965060408601359560600135945092505050565b6000806101208385031215614cf957600080fd5b614d038484614aee565b94610100939093013593505050565b6000806000806101608587031215614d2957600080fd5b614d338686614aee565b966101008601359650610120860135956101400135945092505050565b600060208284031215614d6257600080fd5b81356144bb81614b3e565b60008060008060006101808688031215614d8657600080fd5b614d908787614aee565b9761010087013597506101208701359661014081013596506101600135945092505050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112614ddc57600080fd5b813567ffffffffffffffff80821115614df757614df7614db5565b604051601f8301601f19908116603f01168101908282118183101715614e1f57614e1f614db5565b81604052838152866020858801011115614e3857600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060408385031215614e6b57600080fd5b8235614e7681614b3e565b9150602083013567ffffffffffffffff811115614e9257600080fd5b614e9e85828601614dcb565b9150509250929050565b6000806000806000806101808789031215614ec257600080fd5b614ecc8888614aee565b955061010087013594506101208701359350610140870135614eed81614b3e565b925061016087013567ffffffffffffffff811115614f0a57600080fd5b614f1689828a01614b63565b979a9699509497509295939492505050565b6000806000806000806000806101c0898b031215614f4557600080fd5b614f4f8a8a614aee565b9750610100890135965061012089013595506101408901359450610160890135614f7881614b3e565b9350610180890135614f8981614b3e565b92506101a089013567ffffffffffffffff811115614fa657600080fd5b614fb28b828c01614b63565b999c989b5096995094979396929594505050565b6000806000806102408587031215614fdd57600080fd5b614fe78686614aee565b93506101008501359250614fff866101208701614aee565b939692955092936102200135925050565b60008060008060008060006101a0888a03121561502c57600080fd5b6150368989614aee565b96506101008801359550610120880135945061014088013561505781614b3e565b9350610160880135614c6e81614b3e565b6000806020838503121561507b57600080fd5b823567ffffffffffffffff8082111561509357600080fd5b818501915085601f8301126150a757600080fd5b8135818111156150b657600080fd5b8660208260051b85010111156150cb57600080fd5b60209290920196919550909350505050565b60005b838110156150f85781810151838201526020016150e0565b50506000910152565b600081518084526151198160208601602086016150dd565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561518257603f19888603018452615170858351615101565b94509285019290850190600101615154565b5092979650505050505050565b6000602082840312156151a157600080fd5b5035919050565b610100810182356151b881614b3e565b6001600160a01b0390811683526020840135906151d482614b3e565b90811660208401526040840135906151eb82614b3e565b80821660408501525050606083013560608301526080830135608083015260a083013560a083015260c083013560c083015260e083013560e083015292915050565b600061010080838503121561524157600080fd5b6040519081019067ffffffffffffffff8211818310171561526457615264614db5565b816040528092508335915061527882614b3e565b81815261528760208501614b53565b602082015261529860408501614b53565b6040820152606084013560608201526080840135608082015260a084013560a082015260c084013560c082015260e084013560e0820152505092915050565b600061010082840312156152ea57600080fd5b6144bb838361522d565b6001600160a01b039384168152919092166020820152604081019190915260600190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561273757612737615318565b60006101008201905060018060a01b0380845116835280602085015116602084015280604085015116604084015250606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015292915050565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b60006020828403121561545257600080fd5b5051919050565b8181038181111561273757612737615318565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261549957600080fd5b83018035915067ffffffffffffffff8211156154b457600080fd5b602001915036819003821315614ba557600080fd5b6000600182016154db576154db615318565b5060010190565b6000602082840312156154f457600080fd5b81516144bb81614b3e565b6000806040838503121561551257600080fd5b50508035926020909101359150565b600080610120838503121561553557600080fd5b614d03848461522d565b6000806000806000806101a0878903121561555957600080fd5b615563888861522d565b95506101008701359450610120870135935061014087013561558481614b3e565b925061016087013561559581614b3e565b915061018087013567ffffffffffffffff8111156155b257600080fd5b6155be89828a01614dcb565b9150509295509295509295565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906148f890830184615101565b8183823760009101908152919050565b60006020828403121561562057600080fd5b815180151581146144bb57600080fd5b600082516156428184602087016150dd565b9190910192915050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6020815260006144bb602083018461510156fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220d35bb0f79dcec9f8dbea8ef65aac6655f62f1a43cc785468973719f99496d2ea64736f6c63430008130033
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.