Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
- Contract name:
- RentRegistry
- Optimization enabled
- true
- Compiler version
- v0.8.17+commit.8df45f5f
- Optimization runs
- 200
- EVM Version
- london
- Verified at
- 2024-09-05T07:38:37.437692Z
Constructor Arguments
0x0000000000000000000000009f59adf8ca58d0ffd9372af68d747c3dbb4cb02f0000000000000000000000009ab18990c9035f7878a59e134bce5d618cb19d55000000000000000000000000ea6a031bbaf2eadb5ecfd32b8aa39e9a95659e4600000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000099ebd96615a50933c69b435f8a59539caff95d7c000000000000000000000000750449925085a335b58b6706e0cf17039caa606f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000002bc
Arg [0] (address) : 0x9f59adf8ca58d0ffd9372af68d747c3dbb4cb02f
Arg [1] (address) : 0x9ab18990c9035f7878a59e134bce5d618cb19d55
Arg [2] (address) : 0xea6a031bbaf2eadb5ecfd32b8aa39e9a95659e46
Arg [3] (address[]) : [0x99ebd96615a50933c69b435f8a59539caff95d7c, 0x750449925085a335b58b6706e0cf17039caa606f]
Arg [4] (uint256[]) : [500, 700]
project:/contracts/rent/RentRegistry.sol
// SPDX-License-Identifier: PROPRIERTARY // For development, we used some code from open source with an MIT license // https://github.com/re-nft/legacy-contracts pragma solidity =0.8.17; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "./interfaces/IRentResolver.sol"; import "./interfaces/IRentRegistry.sol"; import "../utils/GuardExtension.sol"; error Paused(); error AlreadyRented(); error RentNotCompleted(); error RentAlreadyCompleted(); error LendingNotExists(); error RentingNotExists(); error LendingAlreadyExists(); error RentingAlreadyExists(); error AssertionError(); error NothingToPay(); error LenderRequired(); error RenterRequired(); error InvalidInput(bytes32 parameter); error SameValue(); contract RentRegistry is IRentRegistry, ERC721Holder, ERC1155Holder, GuardExtension, ReentrancyGuard { using SafeERC20 for ERC20; bytes1 private constant DOMAIN_SEPARATOR_LENDING_ID = 0x01; bytes1 private constant DOMAIN_SEPARATOR_RENTING_ID = 0x02; IRentResolver private _resolver; address private _beneficiary; uint256 private _lendingID = 1; uint256 private _rentingID = 1; bool public _paused = false; mapping(address => uint256) private _rentFee; mapping(bytes32 => Lending) private _lendings; mapping(bytes32 => Renting) private _rentings; modifier notPaused() { if (_paused) { revert Paused(); } _; } constructor( address resolver_, address beneficiary_, address rights_, address[] memory feeTokens_, uint256[] memory feePercents_ ) GuardExtension(rights_) ReentrancyGuard() { if (feeTokens_.length != feePercents_.length) { revert InvalidInput("feeTokens_"); } ensureIsNotZeroAddr(resolver_); ensureIsNotZeroAddr(beneficiary_); ensureIsNotZeroAddr(rights_); _resolver = IRentResolver(resolver_); _beneficiary = beneficiary_; for (uint256 i = 0; i < feeTokens_.length; ++i) { ensureIsNotZeroAddr(feeTokens_[i]); _setRentFee(feeTokens_[i], feePercents_[i]); } } function lend( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendAmount_, uint8[] memory maxRentDuration_, bytes4[] memory dailyRentPrice_, uint8[] memory paymentToken_, bool[] memory willAutoRenew_ ) external override notPaused nonReentrant { bundleCall( handleLend, createLendCallData( nftStandard_, nftAddress_, tokenId_, lendAmount_, maxRentDuration_, dailyRentPrice_, paymentToken_, willAutoRenew_ ) ); } function stopLend( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendingId_ ) external override notPaused nonReentrant { bundleCall( handleStopLend, createActionCallData( nftStandard_, nftAddress_, tokenId_, lendingId_, new uint256[](0) ) ); } /** * @param nftStandard_ NFT standart (0 - ERC721, 1 - ERC1155) * @param nftAddress_ NFT contract address * @param tokenId_ NFT token Id * @param lendingId_ The landing Id * @param rentDuration_ Rent duration in days * @param rentAmount_ Token amount (for ERC721 always 1) */ function rent( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendingId_, uint8[] memory rentDuration_, uint256[] memory rentAmount_ ) external override notPaused nonReentrant { bundleCall( handleRent, createRentCallData( nftStandard_, nftAddress_, tokenId_, lendingId_, rentDuration_, rentAmount_ ) ); } function stopRent( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendingId_, uint256[] memory rentingId_ ) external override notPaused nonReentrant { bundleCall( handleStopRent, createActionCallData( nftStandard_, nftAddress_, tokenId_, lendingId_, rentingId_ ) ); } function claimRent( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendingId_, uint256[] memory rentingId_ ) external override notPaused nonReentrant { bundleCall( handleClaimRent, createActionCallData( nftStandard_, nftAddress_, tokenId_, lendingId_, rentingId_ ) ); } function handleLend(CallData memory cd_) private { for (uint256 i = cd_.left; i < cd_.right; i++) { ensureIsLendable(cd_, i); bytes32 identifier = getLendingId( cd_.nftAddress[cd_.left], cd_.tokenID[i], _lendingID ); Lending storage lending = _lendings[identifier]; ensureIsNull(lending); ensureTokenNotSentinel(uint8(cd_.paymentToken[i])); bool is721 = cd_.nftStandard[i] == NFTStandard.E721; uint16 _lendAmount = uint16(cd_.lendAmount[i]); if (is721 && _lendAmount != 1) { revert InvalidInput("_lendAmount"); } _lendings[identifier] = Lending({ nftStandard: cd_.nftStandard[i], lenderAddress: msg.sender, maxRentDuration: cd_.maxRentDuration[i], dailyRentPrice: cd_.dailyRentPrice[i], lendAmount: _lendAmount, availableAmount: _lendAmount, paymentToken: cd_.paymentToken[i], willAutoRenew: cd_.willAutoRenew[i] }); emit Lend( is721, msg.sender, cd_.nftAddress[cd_.left], cd_.tokenID[i], _lendingID, cd_.maxRentDuration[i], cd_.dailyRentPrice[i], _lendAmount, cd_.paymentToken[i], cd_.willAutoRenew[i] ); _lendingID++; } safeTransfer( cd_, msg.sender, address(this), sliceArr(cd_.tokenID, cd_.left, cd_.right, 0), sliceArr(cd_.lendAmount, cd_.left, cd_.right, 0) ); } function handleStopLend(CallData memory cd_) private { uint256[] memory lentAmounts = new uint256[](cd_.right - cd_.left); for (uint256 i = cd_.left; i < cd_.right; i++) { bytes32 lendingIdentifier = getLendingId( cd_.nftAddress[cd_.left], cd_.tokenID[i], cd_.lendingID[i] ); Lending storage lending = _lendings[lendingIdentifier]; ensureIsNotNull(lending); ensureIsStoppable(lending, msg.sender); if (cd_.nftStandard[i] != lending.nftStandard) { revert InvalidInput("nftStandard"); } if (lending.lendAmount != lending.availableAmount) { revert AlreadyRented(); } lentAmounts[i - cd_.left] = lending.lendAmount; emit StopLend( cd_.lendingID[i], uint32(block.timestamp), lending.lendAmount ); delete _lendings[lendingIdentifier]; } safeTransfer( cd_, address(this), msg.sender, sliceArr(cd_.tokenID, cd_.left, cd_.right, 0), sliceArr(lentAmounts, cd_.left, cd_.right, cd_.left) ); } function handleRent(CallData memory cd_) private { for (uint256 i = cd_.left; i < cd_.right; i++) { bytes32 lendingIdentifier = getLendingId( cd_.nftAddress[cd_.left], cd_.tokenID[i], cd_.lendingID[i] ); bytes32 rentingIdentifier = getRentingId( cd_.nftAddress[cd_.left], cd_.tokenID[i], _rentingID ); Lending storage lending = _lendings[lendingIdentifier]; Renting storage renting = _rentings[rentingIdentifier]; ensureIsNotNull(lending); ensureIsNull(renting); ensureIsRentable(lending, cd_, i, msg.sender); if (cd_.nftStandard[i] != lending.nftStandard) { revert InvalidInput("nftStandard"); } if (cd_.rentAmount[i] > lending.availableAmount) { revert InvalidInput("rentAmount"); } uint8 paymentTokenIx = uint8(lending.paymentToken); ERC20 paymentToken = ERC20( _resolver.getPaymentToken(paymentTokenIx) ); uint256 decimals = paymentToken.decimals(); { uint256 scale = 10 ** decimals; uint256 rentPrice = cd_.rentAmount[i] * cd_.rentDuration[i] * unpackPrice(lending.dailyRentPrice, scale); if (rentPrice == 0) { revert InvalidInput("rentDuration"); } paymentToken.safeTransferFrom( msg.sender, address(this), rentPrice ); } _rentings[rentingIdentifier] = Renting({ renterAddress: msg.sender, rentAmount: uint16(cd_.rentAmount[i]), rentDuration: cd_.rentDuration[i], rentedAt: uint32(block.timestamp) }); _lendings[lendingIdentifier].availableAmount -= uint16( cd_.rentAmount[i] ); emit Rent( msg.sender, cd_.lendingID[i], _rentingID, uint16(cd_.rentAmount[i]), cd_.rentDuration[i], renting.rentedAt ); _rentingID++; } } function handleStopRent(CallData memory cd_) private { for (uint256 i = cd_.left; i < cd_.right; i++) { bytes32 lendingIdentifier = getLendingId( cd_.nftAddress[cd_.left], cd_.tokenID[i], cd_.lendingID[i] ); bytes32 rentingIdentifier = getRentingId( cd_.nftAddress[cd_.left], cd_.tokenID[i], cd_.rentingID[i] ); Lending storage lending = _lendings[lendingIdentifier]; Renting memory renting = _rentings[rentingIdentifier]; // Remove renting to avoid reentry attack delete _rentings[rentingIdentifier]; ensureIsNotNull(lending); ensureIsNotNull(renting); ensureIsReturnable(renting, msg.sender, block.timestamp); if (cd_.nftStandard[i] != lending.nftStandard) { revert InvalidInput("nftStandard"); } if (renting.rentAmount > lending.lendAmount) { revert AssertionError(); } uint256 secondsSinceRentStart = block.timestamp - renting.rentedAt; ( uint256 sendRenterAmt, uint256 sendLenderAmt, uint256 fee ) = distributePayments(lending, renting, secondsSinceRentStart); manageWillAutoRenew( lending, renting, cd_.nftAddress[cd_.left], cd_.nftStandard[cd_.left], cd_.tokenID[i], cd_.lendingID[i] ); emit StopRent( cd_.rentingID[i], sendRenterAmt, sendLenderAmt, fee, uint32(block.timestamp) ); } } function handleClaimRent(CallData memory cd_) private { for (uint256 i = cd_.left; i < cd_.right; i++) { bytes32 lendingIdentifier = getLendingId( cd_.nftAddress[cd_.left], cd_.tokenID[i], cd_.lendingID[i] ); bytes32 rentingIdentifier = getRentingId( cd_.nftAddress[cd_.left], cd_.tokenID[i], cd_.rentingID[i] ); Lending storage lending = _lendings[lendingIdentifier]; Renting memory renting = _rentings[rentingIdentifier]; // Remove renting to avoid reentry attack delete _rentings[rentingIdentifier]; ensureIsNotNull(lending); ensureIsNotNull(renting); ensureIsClaimable(renting, block.timestamp); (uint256 amount, uint256 fee) = distributeClaimPayment( lending, renting ); manageWillAutoRenew( lending, renting, cd_.nftAddress[cd_.left], cd_.nftStandard[cd_.left], cd_.tokenID[i], cd_.lendingID[i] ); emit RentClaimed( cd_.rentingID[i], amount, fee, uint32(block.timestamp) ); } } function manageWillAutoRenew( Lending storage lending_, Renting memory renting_, address nftAddress_, NFTStandard nftStandard_, uint256 tokenId_, uint256 lendingId_ ) private { if (lending_.willAutoRenew == false) { // No automatic renewal, stop the lending (or a portion of it) completely! // We must be careful here, because the lending might be for an ERC1155 token, which means // that the renting.rentAmount might not be the same as the lending.lendAmount. In this case, we // must NOT delete the lending, but only decrement the lending.lendAmount by the renting.rentAmount. // Notice: this is only possible for an ERC1155 tokens! if (lending_.lendAmount > renting_.rentAmount) { // update lending lendAmount to reflect NOT renewing the lending // Do not update lending.availableAmount, because the assets will not be lent out again lending_.lendAmount -= renting_.rentAmount; // return the assets to the lender IERC1155(nftAddress_).safeTransferFrom( address(this), lending_.lenderAddress, tokenId_, uint256(renting_.rentAmount), "" ); } // If the lending is for an ERC721 token, then the renting.rentAmount is always the same as the // lending.lendAmount, and we can delete the lending. If the lending is for an ERC1155 token and // the renting.rentAmount is the same as the lending.lendAmount, then we can also delete the // lending. else if (lending_.lendAmount == renting_.rentAmount) { // return the assets to the lender if (nftStandard_ == NFTStandard.E721) { IERC721(nftAddress_).safeTransferFrom( address(this), lending_.lenderAddress, tokenId_ ); } else { IERC1155(nftAddress_).safeTransferFrom( address(this), lending_.lenderAddress, tokenId_, uint256(renting_.rentAmount), "" ); } delete _lendings[ getLendingId(nftAddress_, tokenId_, lendingId_) ]; } // StopLend event but only the amount that was not renewed (or all of it) emit StopLend( lendingId_, uint32(block.timestamp), renting_.rentAmount ); } else { // automatic renewal, make the assets available to be lent out again lending_.availableAmount += renting_.rentAmount; } } function bundleCall( function(CallData memory) handler_, CallData memory cd_ ) private { if (cd_.nftAddress.length == 0) { revert InvalidInput("bundle"); } while (cd_.right != cd_.nftAddress.length) { if ( (cd_.nftAddress[cd_.left] == cd_.nftAddress[cd_.right]) && (cd_.nftStandard[cd_.right] == NFTStandard.E1155) ) { cd_.right++; } else { handler_(cd_); cd_.left = cd_.right; cd_.right++; } } handler_(cd_); } function takeFee( uint256 rentAmount_, ERC20 token_ ) private returns (uint256 fee) { uint256 feePercent = _rentFee[address(token_)]; if (feePercent > 0) { fee = rentAmount_ * feePercent; fee /= 10000; token_.safeTransfer(_beneficiary, fee); } else { fee = 0; } } function distributePayments( Lending memory lending_, Renting memory renting_, uint256 secondsSinceRentStart ) private returns (uint256 sendRenterAmt, uint256 sendLenderAmt, uint256 takenFee) { uint8 paymentTokenIx = uint8(lending_.paymentToken); ERC20 paymentToken = ERC20(_resolver.getPaymentToken(paymentTokenIx)); uint256 decimals = paymentToken.decimals(); uint256 scale = 10 ** decimals; uint256 rentPrice = renting_.rentAmount * unpackPrice(lending_.dailyRentPrice, scale); uint256 totalRenterPmt = rentPrice * renting_.rentDuration; sendLenderAmt = (secondsSinceRentStart * rentPrice) / 1 days; if (totalRenterPmt == 0 || sendLenderAmt == 0) { revert NothingToPay(); } sendRenterAmt = totalRenterPmt - sendLenderAmt; takenFee = takeFee(sendLenderAmt, paymentToken); sendLenderAmt -= takenFee; paymentToken.safeTransfer(lending_.lenderAddress, sendLenderAmt); if (sendRenterAmt > 0) { paymentToken.safeTransfer(renting_.renterAddress, sendRenterAmt); } } function distributeClaimPayment( Lending memory lending_, Renting memory renting_ ) private returns (uint256 amount, uint256 fee) { uint8 paymentTokenIx = uint8(lending_.paymentToken); ERC20 paymentToken = ERC20(_resolver.getPaymentToken(paymentTokenIx)); uint256 decimals = paymentToken.decimals(); uint256 scale = 10 ** decimals; uint256 rentPrice = renting_.rentAmount * unpackPrice(lending_.dailyRentPrice, scale); uint256 fullAmount = rentPrice * renting_.rentDuration; fee = takeFee(fullAmount, paymentToken); amount = fullAmount - fee; paymentToken.safeTransfer(lending_.lenderAddress, amount); } function safeTransfer( CallData memory cd_, address from_, address to_, uint256[] memory tokenId_, uint256[] memory lendAmount_ ) private { if (cd_.nftStandard[cd_.left] == NFTStandard.E721) { IERC721(cd_.nftAddress[cd_.left]).safeTransferFrom( from_, to_, cd_.tokenID[cd_.left] ); } else { IERC1155(cd_.nftAddress[cd_.left]).safeBatchTransferFrom( from_, to_, tokenId_, lendAmount_, "" ); } } function getLending( address nftAddress_, uint256 tokenId_, uint256 lendingId_ ) external view returns (Lending memory lending) { lending = _lendings[getLendingId(nftAddress_, tokenId_, lendingId_)]; } function getRenting( address nftAddress_, uint256 tokenId_, uint256 rentingId_ ) external view returns (Renting memory renting) { renting = _rentings[getRentingId(nftAddress_, tokenId_, rentingId_)]; } function createLendCallData( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendAmount_, uint8[] memory maxRentDuration_, bytes4[] memory dailyRentPrice_, uint8[] memory paymentToken_, bool[] memory willAutoRenew_ ) private pure returns (CallData memory cd) { cd = CallData({ left: 0, right: 1, nftStandard: nftStandard_, nftAddress: nftAddress_, tokenID: tokenId_, lendAmount: lendAmount_, lendingID: new uint256[](0), rentingID: new uint256[](0), rentDuration: new uint8[](0), rentAmount: new uint256[](0), maxRentDuration: maxRentDuration_, dailyRentPrice: dailyRentPrice_, paymentToken: paymentToken_, willAutoRenew: willAutoRenew_ }); } function createRentCallData( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendingId_, uint8[] memory rentDuration_, uint256[] memory rentAmount_ ) private pure returns (CallData memory cd) { cd = CallData({ left: 0, right: 1, nftStandard: nftStandard_, nftAddress: nftAddress_, tokenID: tokenId_, lendAmount: new uint256[](0), lendingID: lendingId_, rentingID: new uint256[](0), rentDuration: rentDuration_, rentAmount: rentAmount_, maxRentDuration: new uint8[](0), dailyRentPrice: new bytes4[](0), paymentToken: new uint8[](0), willAutoRenew: new bool[](0) }); } function createActionCallData( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendingId_, uint256[] memory rentingId_ ) private pure returns (CallData memory cd) { cd = CallData({ left: 0, right: 1, nftStandard: nftStandard_, nftAddress: nftAddress_, tokenID: tokenId_, lendAmount: new uint256[](0), lendingID: lendingId_, rentingID: rentingId_, rentDuration: new uint8[](0), rentAmount: new uint256[](0), maxRentDuration: new uint8[](0), dailyRentPrice: new bytes4[](0), paymentToken: new uint8[](0), willAutoRenew: new bool[](0) }); } function unpackPrice( bytes4 price_, uint256 scale_ ) private pure returns (uint256 fullPrice) { ensureIsUnpackablePrice(price_, scale_); uint16 whole = uint16(bytes2(price_)); uint16 decimal = uint16(bytes2(price_ << 16)); uint256 decimalScale = scale_ / 10000; if (whole > 9999) { whole = 9999; } if (decimal > 9999) { decimal = 9999; } uint256 w = whole * scale_; uint256 d = decimal * decimalScale; fullPrice = w + d; } function sliceArr( uint256[] memory arr_, uint256 fromIx_, uint256 toIx_, uint256 arrOffset_ ) private pure returns (uint256[] memory r) { r = new uint256[](toIx_ - fromIx_); for (uint256 i = fromIx_; i < toIx_; i++) { r[i - fromIx_] = arr_[i - arrOffset_]; } } function ensureIsNotZeroAddr(address addr_) private pure { if (addr_ == address(0)) { revert InvalidInput("address"); } } function ensureIsNull(Lending memory lending_) private pure { if ( lending_.lenderAddress != address(0) || lending_.maxRentDuration != 0 || lending_.dailyRentPrice != 0 ) { revert LendingAlreadyExists(); } } function ensureIsNotNull(Lending memory lending_) private pure { if ( lending_.lenderAddress == address(0) || lending_.maxRentDuration == 0 || lending_.dailyRentPrice == 0 ) { revert LendingNotExists(); } } function ensureIsNull(Renting memory renting_) private pure { if ( renting_.renterAddress != address(0) || renting_.rentDuration != 0 || renting_.rentedAt != 0 ) { revert RentingAlreadyExists(); } } function ensureIsNotNull(Renting memory renting_) private pure { if ( renting_.renterAddress == address(0) || renting_.rentDuration == 0 || renting_.rentedAt == 0 ) { revert RentingNotExists(); } } function ensureIsLendable( CallData memory cd_, uint256 index_ ) private pure { if ( cd_.lendAmount[index_] == 0 || cd_.lendAmount[index_] > type(uint16).max ) { revert InvalidInput("lendAmount"); } if ( cd_.maxRentDuration[index_] == 0 || cd_.maxRentDuration[index_] > type(uint8).max ) { revert InvalidInput("maxRentDuration"); } if (uint32(cd_.dailyRentPrice[index_]) == 0) { revert InvalidInput("dailyRentPrice"); } } function ensureIsRentable( Lending memory lending_, CallData memory cd_, uint256 index_, address msgSender ) private pure { if (msgSender == lending_.lenderAddress) { revert InvalidInput("lenderAddress"); } if ( cd_.rentDuration[index_] == 0 || cd_.rentDuration[index_] > type(uint8).max ) { revert InvalidInput("rentDuration"); } if ( cd_.rentAmount[index_] == 0 || cd_.rentAmount[index_] > type(uint16).max ) { revert InvalidInput("rentAmount"); } if (cd_.rentDuration[index_] > lending_.maxRentDuration) { revert InvalidInput("rentDuration"); } } function ensureIsReturnable( Renting memory renting_, address msgSender_, uint256 blockTimestamp_ ) private pure { if (renting_.renterAddress != msgSender_) { revert RenterRequired(); } if (isPastReturnDate(renting_, blockTimestamp_)) { revert RentAlreadyCompleted(); } } function ensureIsStoppable( Lending memory lending_, address msgSender_ ) private pure { if (lending_.lenderAddress != msgSender_) { revert LenderRequired(); } } function ensureIsUnpackablePrice( bytes4 price_, uint256 scale_ ) private pure { if (uint32(price_) == 0 || scale_ < 10000) { revert InvalidInput("price"); } } function ensureTokenNotSentinel(uint8 paymentIx_) private pure { if (paymentIx_ == 0) { revert InvalidInput("paymentIx_"); } } function ensureIsClaimable( Renting memory renting_, uint256 blockTimestamp_ ) private pure { if (!isPastReturnDate(renting_, blockTimestamp_)) { revert RentNotCompleted(); } } function isPastReturnDate( Renting memory renting_, uint256 nowTime_ ) private pure returns (bool isPast) { if (nowTime_ <= renting_.rentedAt) { revert AssertionError(); } isPast = nowTime_ - renting_.rentedAt > renting_.rentDuration * 1 days; } function getRentFee(address token_) external view returns (uint256 fee) { fee = _rentFee[token_]; } function getBeneficiary() external view returns (address beneficiaryAddress) { beneficiaryAddress = _beneficiary; } function setRentFee( address token_, uint256 newRentFee_ ) external haveRights { _setRentFee(token_, newRentFee_); } function setBeneficiary(address newBeneficiary_) external haveRights { if (_beneficiary != newBeneficiary_) { _beneficiary = newBeneficiary_; } else { revert SameValue(); } } function setPaused(bool newPaused_) external haveRights { if (_paused != newPaused_) { _paused = newPaused_; } else { revert SameValue(); } } function _setRentFee(address token_, uint256 newRentFee_) private { if (newRentFee_ > 2000) { revert InvalidInput("newRentFee_"); } if (_rentFee[token_] != newRentFee_) { _rentFee[token_] = newRentFee_; emit RentFeeUpdated(token_, newRentFee_); } else { revert SameValue(); } } function getRentingId( address nftAddress_, uint256 tokenId_, uint256 rentingId_ ) private pure returns (bytes32 rentId) { rentId = keccak256( abi.encodePacked( DOMAIN_SEPARATOR_RENTING_ID, nftAddress_, tokenId_, rentingId_ ) ); } function getLendingId( address nftAddress_, uint256 tokenId_, uint256 lendingId_ ) private pure returns (bytes32 lendId) { lendId = keccak256( abi.encodePacked( DOMAIN_SEPARATOR_LENDING_ID, nftAddress_, tokenId_, lendingId_ ) ); } }
@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol) pragma solidity ^0.8.0; import "../IERC1155Receiver.sol"; import "../../../utils/introspection/ERC165.sol"; /** * @dev _Available since v3.1._ */ abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } }
@openzeppelin/contracts/token/ERC20/ERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
@openzeppelin/contracts/security/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @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; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
@openzeppelin/contracts/token/ERC1155/IERC1155.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch( address[] calldata accounts, uint256[] calldata ids ) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev _Available since v3.1._ */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol) pragma solidity ^0.8.0; import "./ERC1155Receiver.sol"; /** * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. * * @dev _Available since v3.1._ */ contract ERC1155Holder is ERC1155Receiver { function onERC1155Received( address, address, uint256, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
@openzeppelin/contracts/token/ERC721/IERC721.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.0; import "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
@openzeppelin/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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 * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [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://consensys.net/diligence/blog/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.8.0/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); } } }
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
@openzeppelin/contracts/utils/introspection/ERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
@openzeppelin/contracts/utils/introspection/IERC165.sol
// 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); }
project:/contracts/rent/interfaces/IRentRegistry.sol
// SPDX-License-Identifier: PROPRIERTARY pragma solidity =0.8.17; interface IRentRegistry { event Lend( bool is721, address indexed lenderAddress, address indexed nftAddress, uint256 indexed tokenID, uint256 lendingID, uint8 maxRentDuration, bytes4 dailyRentPrice, uint16 lendAmount, uint8 paymentToken, bool willAutoRenew ); event Rent( address indexed renterAddress, uint256 indexed lendingID, uint256 indexed rentingID, uint16 rentAmount, uint8 rentDuration, uint32 rentedAt ); event StopLend(uint256 indexed lendingID, uint32 stoppedAt, uint16 amount); event StopRent( uint256 indexed rentingID, uint256 renterAmount, uint256 lenderAmount, uint256 fee, uint32 stoppedAt ); event RentClaimed( uint256 indexed rentingID, uint256 amount, uint256 fee, uint32 collectedAt ); event RentFeeUpdated(address indexed token, uint256 feePercent); enum NFTStandard { E721, E1155 } struct CallData { uint256 left; uint256 right; NFTStandard[] nftStandard; address[] nftAddress; uint256[] tokenID; uint256[] lendAmount; uint8[] maxRentDuration; bytes4[] dailyRentPrice; uint256[] lendingID; uint256[] rentingID; uint8[] rentDuration; uint256[] rentAmount; uint8[] paymentToken; bool[] willAutoRenew; } // fits into a single storage slot // nftStandard 2 // lenderAddress 162 // maxRentDuration 170 // dailyRentPrice 202 // lendAmount 218 // availableAmount 234 // paymentToken 242 // willAutoRenew 250 // leaves a spare byte struct Lending { NFTStandard nftStandard; address lenderAddress; uint8 maxRentDuration; bytes4 dailyRentPrice; uint16 lendAmount; uint16 availableAmount; uint8 paymentToken; bool willAutoRenew; } // fits into a single storage slot // renterAddress 160 // rentDuration 168 // rentedAt 216 // rentAmount 232 // leaves 3 spare bytes struct Renting { address renterAddress; uint8 rentDuration; uint32 rentedAt; uint16 rentAmount; } // creates the lending structs and adds them to the enumerable set function lend( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendAmount_, uint8[] memory maxRentDuration_, bytes4[] memory dailyRentPrice_, uint8[] memory paymentToken_, bool[] memory willAutoRenew_ ) external; function stopLend( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendingId_ ) external; // creates the renting structs and adds them to the enumerable set function rent( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenID_, uint256[] memory lendingId_, uint8[] memory rentDuration_, uint256[] memory rentAmount ) external; function stopRent( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendingId_, uint256[] memory rentingId ) external; function claimRent( NFTStandard[] memory nftStandard_, address[] memory nftAddress_, uint256[] memory tokenId_, uint256[] memory lendingId_, uint256[] memory rentingId ) external; }
project:/contracts/rent/interfaces/IRentResolver.sol
// SPDX-License-Identifier: PROPRIERTARY pragma solidity =0.8.17; interface IRentResolver { event PaymentTokenAdded(uint8 pt, address tokenAddress); function getPaymentToken(uint8 pt_) external view returns (address); function setPaymentToken(uint8 pt_, address v_) external; }
project:/contracts/utils/Guard.sol
// SPDX-License-Identifier: PROPRIERTARY // Author: Ilya A. Shlyakhovoy // Email: is@unicsoft.com pragma solidity 0.8.17; import "./interfaces/IRights.sol"; abstract contract Guard { string constant NO_RIGHTS = "Guard: No rights"; /// @notice only if person with rights calls the contract modifier haveRights() { require(_rights().haveRights(address(this), msg.sender), NO_RIGHTS); _; } /// @notice only if someone with rights calls the contract modifier haveRightsPerson(address who_) { require(_rights().haveRights(address(this), who_), NO_RIGHTS); _; } /// @notice only if who with rights calls the target function modifier haveRightsExt(address target_, address who_) { require(_rights().haveRights(target_, who_), NO_RIGHTS); _; } function _rights() internal view virtual returns (IRights); function setRights(address rights_) external virtual; }
project:/contracts/utils/GuardExtension.sol
// SPDX-License-Identifier: PROPRIERTARY // Author: Ilya A. Shlyakhovoy // Email: is@unicsoft.com pragma solidity 0.8.17; import "./interfaces/IRights.sol"; import "../utils/Guard.sol"; abstract contract GuardExtension is Guard { IRights private _rightsContract; string private constant SAME_VALUE = "Guard: same value"; string private constant ZERO_ADDRESS = "Guard: zero address"; constructor(address rights_) { require(rights_ != address(0), ZERO_ADDRESS); _rightsContract = IRights(rights_); } function _rights() internal view virtual override returns (IRights) { return _rightsContract; } function setRights(address rights_) external virtual override haveRights { require(address(_rightsContract) != rights_, SAME_VALUE); require(rights_ != address(0), ZERO_ADDRESS); _rightsContract = IRights(rights_); } }
project:/contracts/utils/interfaces/IRights.sol
// SPDX-License-Identifier: PROPRIERTARY // Author: Ilya A. Shlyakhovoy // Email: is@unicsoft.com pragma solidity 0.8.17; interface IRights { event AdminAdded(address indexed admin); event AdminDefined(address indexed admin, address indexed contractHash); event AdminRemoved(address indexed admin); event AdminCleared(address indexed admin, address indexed contractHash); /** @notice Add a new admin for the Rigths contract @param admin_ New admin address */ function addAdmin(address admin_) external; /** @notice Add a new admin for the any other contract @param contract_ Contract address packed into address @param admin_ New admin address */ function addAdmin(address contract_, address admin_) external; /** @notice Remove the existing admin from the Rigths contract @param admin_ Admin address */ function removeAdmin(address admin_) external; /** @notice Remove the existing admin from the specified contract @param contract_ Contract address packed into address @param admin_ Admin address */ function removeAdmin(address contract_, address admin_) external; /** @notice Get the rights for the contract for the caller @param contract_ Contract address packed into address @return have rights or not */ function haveRights(address contract_) external view returns (bool); /** @notice Get the rights for the contract @param contract_ Contract address packed into address @param admin_ Admin address @return have rights or not */ function haveRights(address contract_, address admin_) external view returns (bool); }
Compiler Settings
{"viaIR":true,"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"london"}
Contract ABI
[{"type":"constructor","inputs":[{"type":"address","name":"resolver_","internalType":"address"},{"type":"address","name":"beneficiary_","internalType":"address"},{"type":"address","name":"rights_","internalType":"address"},{"type":"address[]","name":"feeTokens_","internalType":"address[]"},{"type":"uint256[]","name":"feePercents_","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"_paused","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimRent","inputs":[{"type":"uint8[]","name":"nftStandard_","internalType":"enum IRentRegistry.NFTStandard[]"},{"type":"address[]","name":"nftAddress_","internalType":"address[]"},{"type":"uint256[]","name":"tokenId_","internalType":"uint256[]"},{"type":"uint256[]","name":"lendingId_","internalType":"uint256[]"},{"type":"uint256[]","name":"rentingId_","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"beneficiaryAddress","internalType":"address"}],"name":"getBeneficiary","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"lending","internalType":"struct IRentRegistry.Lending","components":[{"type":"uint8"},{"type":"address"},{"type":"uint8"},{"type":"bytes4"},{"type":"uint16"},{"type":"uint16"},{"type":"uint8"},{"type":"bool"}]}],"name":"getLending","inputs":[{"type":"address","name":"nftAddress_","internalType":"address"},{"type":"uint256","name":"tokenId_","internalType":"uint256"},{"type":"uint256","name":"lendingId_","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"fee","internalType":"uint256"}],"name":"getRentFee","inputs":[{"type":"address","name":"token_","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"renting","internalType":"struct IRentRegistry.Renting","components":[{"type":"address"},{"type":"uint8"},{"type":"uint32"},{"type":"uint16"}]}],"name":"getRenting","inputs":[{"type":"address","name":"nftAddress_","internalType":"address"},{"type":"uint256","name":"tokenId_","internalType":"uint256"},{"type":"uint256","name":"rentingId_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"lend","inputs":[{"type":"uint8[]","name":"nftStandard_","internalType":"enum IRentRegistry.NFTStandard[]"},{"type":"address[]","name":"nftAddress_","internalType":"address[]"},{"type":"uint256[]","name":"tokenId_","internalType":"uint256[]"},{"type":"uint256[]","name":"lendAmount_","internalType":"uint256[]"},{"type":"uint8[]","name":"maxRentDuration_","internalType":"uint8[]"},{"type":"bytes4[]","name":"dailyRentPrice_","internalType":"bytes4[]"},{"type":"uint8[]","name":"paymentToken_","internalType":"uint8[]"},{"type":"bool[]","name":"willAutoRenew_","internalType":"bool[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC1155BatchReceived","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint256[]","name":"","internalType":"uint256[]"},{"type":"uint256[]","name":"","internalType":"uint256[]"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC1155Received","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC721Received","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rent","inputs":[{"type":"uint8[]","name":"nftStandard_","internalType":"enum IRentRegistry.NFTStandard[]"},{"type":"address[]","name":"nftAddress_","internalType":"address[]"},{"type":"uint256[]","name":"tokenId_","internalType":"uint256[]"},{"type":"uint256[]","name":"lendingId_","internalType":"uint256[]"},{"type":"uint8[]","name":"rentDuration_","internalType":"uint8[]"},{"type":"uint256[]","name":"rentAmount_","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBeneficiary","inputs":[{"type":"address","name":"newBeneficiary_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPaused","inputs":[{"type":"bool","name":"newPaused_","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRentFee","inputs":[{"type":"address","name":"token_","internalType":"address"},{"type":"uint256","name":"newRentFee_","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRights","inputs":[{"type":"address","name":"rights_","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stopLend","inputs":[{"type":"uint8[]","name":"nftStandard_","internalType":"enum IRentRegistry.NFTStandard[]"},{"type":"address[]","name":"nftAddress_","internalType":"address[]"},{"type":"uint256[]","name":"tokenId_","internalType":"uint256[]"},{"type":"uint256[]","name":"lendingId_","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stopRent","inputs":[{"type":"uint8[]","name":"nftStandard_","internalType":"enum IRentRegistry.NFTStandard[]"},{"type":"address[]","name":"nftAddress_","internalType":"address[]"},{"type":"uint256[]","name":"tokenId_","internalType":"uint256[]"},{"type":"uint256[]","name":"lendingId_","internalType":"uint256[]"},{"type":"uint256[]","name":"rentingId_","internalType":"uint256[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]},{"type":"event","name":"Lend","inputs":[{"type":"bool","name":"is721","indexed":false},{"type":"address","name":"lenderAddress","indexed":true},{"type":"address","name":"nftAddress","indexed":true},{"type":"uint256","name":"tokenID","indexed":true},{"type":"uint256","name":"lendingID","indexed":false},{"type":"uint8","name":"maxRentDuration","indexed":false},{"type":"bytes4","name":"dailyRentPrice","indexed":false},{"type":"uint16","name":"lendAmount","indexed":false},{"type":"uint8","name":"paymentToken","indexed":false},{"type":"bool","name":"willAutoRenew","indexed":false}],"anonymous":false},{"type":"event","name":"Rent","inputs":[{"type":"address","name":"renterAddress","indexed":true},{"type":"uint256","name":"lendingID","indexed":true},{"type":"uint256","name":"rentingID","indexed":true},{"type":"uint16","name":"rentAmount","indexed":false},{"type":"uint8","name":"rentDuration","indexed":false},{"type":"uint32","name":"rentedAt","indexed":false}],"anonymous":false},{"type":"event","name":"RentClaimed","inputs":[{"type":"uint256","name":"rentingID","indexed":true},{"type":"uint256","name":"amount","indexed":false},{"type":"uint256","name":"fee","indexed":false},{"type":"uint32","name":"collectedAt","indexed":false}],"anonymous":false},{"type":"event","name":"RentFeeUpdated","inputs":[{"type":"address","name":"token","indexed":true},{"type":"uint256","name":"feePercent","indexed":false}],"anonymous":false},{"type":"event","name":"StopLend","inputs":[{"type":"uint256","name":"lendingID","indexed":true},{"type":"uint32","name":"stoppedAt","indexed":false},{"type":"uint16","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"StopRent","inputs":[{"type":"uint256","name":"rentingID","indexed":true},{"type":"uint256","name":"renterAmount","indexed":false},{"type":"uint256","name":"lenderAmount","indexed":false},{"type":"uint256","name":"fee","indexed":false},{"type":"uint32","name":"stoppedAt","indexed":false}],"anonymous":false},{"type":"error","name":"AlreadyRented","inputs":[]},{"type":"error","name":"AssertionError","inputs":[]},{"type":"error","name":"InvalidInput","inputs":[{"type":"bytes32","name":"parameter","internalType":"bytes32"}]},{"type":"error","name":"LenderRequired","inputs":[]},{"type":"error","name":"LendingAlreadyExists","inputs":[]},{"type":"error","name":"LendingNotExists","inputs":[]},{"type":"error","name":"NothingToPay","inputs":[]},{"type":"error","name":"Paused","inputs":[]},{"type":"error","name":"RentAlreadyCompleted","inputs":[]},{"type":"error","name":"RentNotCompleted","inputs":[]},{"type":"error","name":"RenterRequired","inputs":[]},{"type":"error","name":"RentingAlreadyExists","inputs":[]},{"type":"error","name":"RentingNotExists","inputs":[]},{"type":"error","name":"SameValue","inputs":[]}]
Contract Creation Code
0x604060808152346200039357620039e990813803806200001f81620003b3565b93843982019160a08184031262000393576200003b81620003d9565b9060206200004b818301620003d9565b9462000059858401620003d9565b60608401516001600160401b039491939190858111620003935781019083601f8301121562000393578151916200009a6200009484620003ee565b620003b3565b92848085838152019160051b83010191868311620003935785809101915b8383106200039857505050506080810151908682116200039357019280601f8501121562000393578351620000f16200009482620003ee565b94848087848152019260051b820101928311620003935784809101915b8383106200038257505088516001600160a01b038781169890949350909150818a01908111828210176200036c578952601381527f47756172643a207a65726f2061646472657373000000000000000000000000008482015286156200030c575060018060a01b0319600096818854161787556001978880556004968988558960055560ff19600654166006558351875103620002e9579a8482620001cb8c9e620001ba849662000431565b620001c58562000431565b62000431565b168360025416176002551690600354161760035585985b620001f7575b87516135849081620004658239f35b8051891015620002e3576200021a82620002128b8462000406565b511662000431565b81620002278a8362000406565b5116620002358a8662000406565b516107d08111620002bf5781885260078086528a8920548214620002af577f5820e211ee8cba31a6b5e7909a12b6dac26ce15657d066c5269d1e60f5abd316918691848b528252808c8b20558b51908152a260001989146200029c579786019786620001e2565b634e487b7160e01b865260118552602486fd5b8a5163c23f6ccb60e01b81528890fd5b895163e1f2fb3d60e01b81526a6e657752656e744665655f60a81b81890152602490fd5b620001e8565b8a5163e1f2fb3d60e01b815269666565546f6b656e735f60b01b818a0152602490fd5b83908951809262461bcd60e51b82528060048301528251908160248401526000935b82851062000352575050604492506000838284010152601f80199101168101030190fd5b84810182015186860160440152938101938593506200032e565b634e487b7160e01b600052604160045260246000fd5b82518152918101918591016200010e565b600080fd5b8190620003a584620003d9565b8152019101908590620000b8565b6040519190601f01601f191682016001600160401b038111838210176200036c57604052565b51906001600160a01b03821682036200039357565b6001600160401b0381116200036c5760051b60200190565b80518210156200041b5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b0316156200044257565b60405163e1f2fb3d60e01b8152666164647265737360c81b6004820152602490fdfe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146110755750806314b5685c14610fa5578063150b7a0214610f5057806316c38b3c14610ea757806316c61ccc14610e845780631c31f71014610de0578063296c21b714610d0157806337d2aae914610bfb578063565a2e2c14610bd2578063937821a114610afd578063a4052a9514610ac3578063bc197c8114610a3b578063c9c40183146108b5578063cbe55e541461067e578063d7e0936014610539578063dc68a142146101ca578063f23a6e61146101755763fe46b7cd146100e557600080fd5b346101705761011d6100f6366113fc565b916000606060405161010781611116565b8281528260208201528260408201520152612192565b600052600960205260806101346040600020611605565b61ffff60606040519260018060a01b03815116845260ff602082015116602085015263ffffffff60408201511660408501520151166060820152f35b600080fd5b346101705760a03660031901126101705761018e611219565b5061019761122f565b506084356001600160401b038111610170576101b79036906004016113b5565b5060405163f23a6e6160e01b8152602090f35b3461017057610100366003190112610170576001600160401b03600435818111610170576101fc9036906004016111b2565b9060243581811161017057610215903690600401611245565b906044358181116101705761022e9036906004016112b3565b606435828111610170576102469036906004016112b3565b936084358381116101705761025f903690600401611426565b9160a4359584871161017057366023880112156101705786600401356102848161119b565b97610292604051998a61117a565b818952602460208a019260051b8201019036821161017057602401915b8183106105185750505060c435858111610170576102d1903690600401611426565b9360e4359586116101705736602387011215610170578560040135956102f68761119b565b96610304604051988961117a565b80885260208801913660248360051b83010111610170579160248301925b60248360051b82010184106104f8575050505060ff600654166104e65760209761034a61148e565b610352611e2d565b50604051916103608361115f565b60008352604051936103718561115f565b60008552604051956103828761115f565b60008752604051976103938961115f565b6000895260016040519d8e6103a7816110fa565b60008152015260408d01528a60608d015260808c015260a08b015260c08a015260e08901526101008801526101208701526101408601526101608501526101808401526101a083015251156104c5575b60208101516060820151908151146104b65781516001600160a01b0391829161041f9161153b565b511690610435606084015160208501519061153b565b51161480610473575b1561045a576104506020820151611516565b60208201526103f7565b61046381613027565b6104506020820151808352611516565b5061048f61048a604083015160208401519061153b565b6115eb565b60028110156104a05760011461043e565b634e487b7160e01b600052602160045260246000fd5b6104bf82613027565b60018055005b60405163e1f2fb3d60e01b81526562756e646c6560d01b6004820152602490fd5b6040516313d0ff5960e31b8152600490fd5b833515158435036101705760208060249386358152019401939150610322565b82356001600160e01b031981168103610170578152602092830192016102af565b3461017057604036600319011261017057610552611219565b600054604051630f6266a760e01b8152306004820152336024808301919091526020939035926001600160a01b03929085908290604490829087165afa8015610672576105b091600091610645575b506105aa61215e565b9061218a565b6107d0831161061f571691826000526007815281604060002054141560001461060d577f5820e211ee8cba31a6b5e7909a12b6dac26ce15657d066c5269d1e60f5abd31691836000526007825280604060002055604051908152a2005b60405163c23f6ccb60e01b8152600490fd5b60405163e1f2fb3d60e01b81526a6e657752656e744665655f60a81b6004820152602490fd5b6106659150863d881161066b575b61065d818361117a565b8101906116b8565b866105a1565b503d610653565b6040513d6000823e3d90fd5b346101705760c0366003190112610170576001600160401b03600435818111610170576106af9036906004016111b2565b602435828111610170576106c7903690600401611245565b604435838111610170576106df9036906004016112b3565b91606435848111610170576106f89036906004016112b3565b60843585811161017057610710903690600401611426565b9460a435908111610170576107299036906004016112b3565b60ff600654166104e65760209561073e61148e565b610746611e2d565b50604051926107548461115f565b60008452604051906107658261115f565b600082526040516107758161115f565b60008152604051906107868261115f565b60008252604051966107978861115f565b60008852604051986107a88a61115f565b60008a5260016040519d8e6107bc816110fa565b60008152015260408d015260608c019a8a8c5260808d015260a08c015260c08b015260e08a01526101008901526101208801526101408701526101608601526101808501526101a084015251156104c5575b60208201518151908151146108ac5782516001600160a01b039182916108339161153b565b511690610846835160208601519061153b565b51161480610884575b1561086b576108616020830151611516565b602083015261080e565b61087482612ade565b6108616020830151808452611516565b5061089b61048a604084015160208501519061153b565b60028110156104a05760011461084f565b6104bf83612ade565b34610170576080366003190112610170576001600160401b03600435818111610170576108e69036906004016111b2565b90602491823582811161017057610901903690600401611245565b916044358181116101705761091a9036906004016112b3565b90606435908111610170576109339036906004016112b3565b9060ff600654166104e6576109609361094a61148e565b604051936109578561115f565b60008552611e96565b606081019182515115610a1d5760208201925b8351815190815114610a145783516001600160a01b039182916109959161153b565b5116906109a5835187519061153b565b511614806109da575b156109c4576109bd8451611516565b8452610973565b6109cd836128b2565b6109bd8451808552611516565b506109ee61048a604085015186519061153b565b60028110156109ff576001146109ae565b82634e487b7160e01b60005260216004526000fd5b6104bf846128b2565b60405163e1f2fb3d60e01b81526562756e646c6560d01b6004820152fd5b346101705760a036600319011261017057610a54611219565b50610a5d61122f565b506001600160401b0360443581811161017057610a7e9036906004016112b3565b5060643581811161017057610a979036906004016112b3565b5060843590811161017057610ab09036906004016113b5565b5060405163bc197c8160e01b8152602090f35b34610170576020366003190112610170576001600160a01b03610ae4611219565b1660005260076020526020604060002054604051908152f35b3461017057610b0b36611311565b9260ff600693929354166104e657610b2a94610b2561148e565b611e96565b6060810190815151156104c55760208101915b8251815190815114610bc95782516001600160a01b03918291610b5f9161153b565b511690610b6f835186519061153b565b51161480610ba4575b15610b8e57610b878351611516565b8352610b3d565b610b9782612641565b610b878351808452611516565b50610bb861048a604084015185519061153b565b60028110156104a057600114610b78565b6104bf83612641565b34610170576000366003190112610170576003546040516001600160a01b039091168152602090f35b346101705760208060031936011261017057610c15611219565b600054604051630f6266a760e01b81523060048201523360248201526001600160a01b03808316949293919291908284604481895afa91821561067257610c6d610ca193610cd496600091610ce457506105aa61215e565b16948560405191610c7d83611144565b601183527047756172643a2073616d652076616c756560781b85840152141561218a565b7247756172643a207a65726f206164647265737360681b60405191610cc583611144565b6013835282015283151561218a565b6001600160a01b03191617600055005b610cfb9150863d881161066b5761065d818361117a565b896105a1565b3461017057610d51610d12366113fc565b91600060e0604051610d23816110c8565b8281528260208201528260408201528260608201528260808201528260a08201528260c082015201526121d8565b6000526008602052610d666040600020611571565b604051815160028110156104a0576101009260e091835260018060a01b03602082015116602084015260ff604082015116604084015263ffffffff821b606082015116606084015261ffff80608083015116608085015260a08201511660a084015260ff60c08201511660c08401520151151560e0820152f35b3461017057602036600319011261017057610df9611219565b600054604051630f6266a760e01b81523060048201523360248201526001600160a01b0392916020908290604490829087165afa801561067257610e4791600091610e6657506105aa61215e565b600354908216918116821461060d576001600160a01b03191617600355005b610e7e915060203d811161066b5761065d818361117a565b846105a1565b3461017057600036600319011261017057602060ff600654166040519015158152f35b346101705760203660031901126101705760043580151580910361017057600054604051630f6266a760e01b815230600482015233602482015290602090829060449082906001600160a01b03165afa801561067257610f1191600091610f3257506105aa61215e565b6006549060ff82161515811461060d5760ff169060ff191617600655600080f35b610f4a915060203d811161066b5761065d818361117a565b836105a1565b3461017057608036600319011261017057610f69611219565b50610f7261122f565b506064356001600160401b03811161017057610f929036906004016113b5565b50604051630a85bd0160e11b8152602090f35b3461017057610fb336611311565b9260ff600693929354166104e657610fcd94610b2561148e565b6060810190815151156104c55760208101915b825181519081511461106c5782516001600160a01b039182916110029161153b565b511690611012835186519061153b565b51161480611047575b156110315761102a8351611516565b8352610fe0565b61103a82612218565b61102a8351808452611516565b5061105b61048a604084015185519061153b565b60028110156104a05760011461101b565b6104bf83612218565b34610170576020366003190112610170576004359063ffffffff60e01b821680920361017057602091630271189760e51b81149081156110b7575b5015158152f35b6301ffc9a760e01b149050836110b0565b61010081019081106001600160401b038211176110e457604052565b634e487b7160e01b600052604160045260246000fd5b6101c081019081106001600160401b038211176110e457604052565b608081019081106001600160401b038211176110e457604052565b6001600160401b0381116110e457604052565b604081019081106001600160401b038211176110e457604052565b602081019081106001600160401b038211176110e457604052565b90601f801991011681019081106001600160401b038211176110e457604052565b6001600160401b0381116110e45760051b60200190565b81601f82011215610170578035916111c98361119b565b926111d7604051948561117a565b808452602092838086019260051b820101928311610170578301905b828210611201575050505090565b813560028110156101705781529083019083016111f3565b600435906001600160a01b038216820361017057565b602435906001600160a01b038216820361017057565b81601f820112156101705780359161125c8361119b565b9261126a604051948561117a565b808452602092838086019260051b820101928311610170578301905b828210611294575050505090565b81356001600160a01b0381168103610170578152908301908301611286565b81601f82011215610170578035916112ca8361119b565b926112d8604051948561117a565b808452602092838086019260051b820101928311610170578301905b828210611302575050505090565b813581529083019083016112f4565b60a0600319820112610170576004906001600160401b038235818111610170578261133d9185016111b2565b936024358281116101705783611354918601611245565b93604435838111610170578461136b9183016112b3565b9360643584811161017057816113829184016112b3565b936084359081116101705761139792016112b3565b90565b6001600160401b0381116110e457601f01601f191660200190565b81601f82011215610170578035906113cc8261139a565b926113da604051948561117a565b8284526020838301011161017057816000926020809301838601378301015290565b6060906003190112610170576004356001600160a01b038116810361017057906024359060443590565b81601f820112156101705780359161143d8361119b565b9261144b604051948561117a565b808452602092838086019260051b820101928311610170578301905b828210611475575050505090565b813560ff81168103610170578152908301908301611467565b60026001541461149f576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b906114ee8261119b565b6114fb604051918261117a565b828152809261150c601f199161119b565b0190602036910137565b60001981146115255760010190565b634e487b7160e01b600052601160045260246000fd5b805182101561154f5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b60028210156104a05752565b9060405161157e816110c8565b60e081935461159060ff821684611565565b60018060a01b038160081c16602084015260ff8160a81c16604084015263ffffffff821b8160301b16606084015261ffff808260d01c16608085015281831c1660a084015260ff8160f01c1660c084015260f81c1515910152565b5160028110156104a05790565b9190820391821161152557565b9060405161161281611116565b91546001600160a01b038116835260a081901c60ff16602084015260a881901c63ffffffff16604084015260c81c61ffff166060830152565b9081602091031261017057516001600160a01b03811681036101705790565b90816020910312610170575160ff811681036101705790565b604d811161152557600a0a90565b8181029291811591840414171561152557565b61ffff918216908216039190821161152557565b90816020910312610170575180151581036101705790565b60405161174d916001600160a01b03166116e982611144565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af13d156117d5573d916117318361139a565b9261173f604051948561117a565b83523d60008785013e6117d9565b8051908282159283156117bd575b505050156117665750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b6117cd93508201810191016116b8565b38828161175b565b6060915b9192901561183b57508151156117ed575090565b3b156117f65790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b82519091501561184e5750805190602001fd5b60405162461bcd60e51b815290819061186a906004830161186e565b0390fd5b6020808252825181830181905290939260005b8281106118a357505060409293506000838284010152601f8019910116010190565b818101860151848201604001528501611881565b91939092938254926000938060f81c15600014611bd45750805461ffff966060888360d01c169701968888511690818111600014611a0657505050509061192661190a8787511688855460d01c166116a4565b835461ffff60d01b191660d09190911b61ffff60d01b16178355565b905484518616926001600160a01b0392831692909160081c16823b15611a0257604051637921219560e11b81523060048201526001600160a01b039190911660248201526044810191909152606481019290925260a06084830152600060a48301528290829060c490829084905af180156119f7576119e0575b505060008051602061352f833981519152916119db915b516040805163ffffffff421681529290911661ffff16602083015290918291820190565b0390a2565b6119ea8291611131565b6119f457806119a0565b80fd5b6040513d84823e3d90fd5b8480fd5b14611a2b575b50505050505060008051602061352f833981519152916119db916119b7565b6002811015611bc057611afc5750546001600160a01b038281169160081c16813b15611a0257604051632142170760e11b81523060048201526001600160a01b03919091166024820152604481018490529084908290606490829084905af18015611af1579087939291611ad2575b506119db949260008051602061352f833981519152969492611abb926121d8565b815260086020526040812055918193388080611a0c565b8491929350611ae090611131565b611aed5790859138611a9a565b8280fd5b6040513d86823e3d90fd5b855192949392871691506001600160a01b0380861691823b15611bbc57604051637921219560e11b815230600482015260089190911c919091166001600160a01b0316602482015260448101849052606481019290925260a06084830152600060a48301528390829060c490829084905af18015611bb15760008051602061352f8339815191529694926119db9694928992611b9e575b50611abb92936121d8565b92611bab611abb94611131565b92611b93565b6040513d85823e3d90fd5b8580fd5b634e487b7160e01b86526021600452602486fd5b93979650939150506060935061ffff809481920151169160e01c1601918211611c1a57805461ffff60e01b191660e09290921b61ffff60e01b169190911790559050565b565b634e487b7160e01b84526011600452602484fd5b60405163a9059cbb60e01b60208201526001600160a01b039092166024830152604480830193909352918152611c1891611c6782611116565b6116d0565b6001600160a01b03918216600081815260076020526040902054909392918115611caf57611ca1611c18939261271092611691565b049384916003541690611c2e565b50600093505050565b90815180825260208080930193019160005b828110611cd8575050505090565b835185529381019392810192600101611cca565b9193929092611d0461048a604085015185519061153b565b60028110156104a057611d9857505060608101518151611d40916001600160a01b0391611d309161153b565b511691608081015190519061153b565b5190803b1561017057604051632142170760e11b81526001600160a01b03938416600482015293909216602484015260448301526000908290606490829084905af1801561067257611d8f5750565b611c1890611131565b9092606083015192611db460018060a01b03948592519061153b565b511691823b156101705760206000959186611e10611dfd8295896040519c8d9b8c9a631759616b60e11b8c521660048b015216602489015260a0604489015260a4880190611cb8565b6003199384888303016064890152611cb8565b85810392830160848701525201925af1801561067257611d8f5750565b60405190611e3a826110fa565b8160008152600060208201526101a060609182604082015282808201528260808201528260a08201528260c08201528260e082015282610100820152826101208201528261014082015282610160820152826101808201520152565b9193929093611ea3611e2d565b50604093845192611eb38461115f565b600096878552865193611ec58561115f565b888552875195611ed48761115f565b898752885191611ee38361115f565b8a8352895193611ef28561115f565b8b85528a5199611f018b61115f565b8c8b528b519b611f108d61115f565b8d8d528051809e611f20826110fa565b8152602001600190528d015260608c015260808b015260a08a015260c089015260e08801526101008701526101208601526101408501526101608401526101808301526101a082015290565b8060e01c80158015611ff7575b611fd757611fb99160f01c908361ffff8092169261270f808211611fcf575b808511611fc5575b506127109183611fb09216611691565b94049116611691565b81018091116115255790565b9350612710611fa0565b905080611f98565b60405163e1f2fb3d60e01b815264707269636560d81b6004820152602490fd5b506127108310611f79565b92919061201761201282846115f8565b6114e4565b93815b8381106120275750505050565b8061203561204f928461153b565b5161204961204386846115f8565b8961153b565b52611516565b61201a565b60208101516001600160a01b0316159081156120a2575b811561208b575b5061207957565b604051631c9bac5160e21b8152600490fd5b606001516001600160e01b03191615905038612072565b604081015160ff1615915061206b565b80516001600160a01b0316159081156120f9575b81156120e6575b506120d457565b604051630269a7b160e11b8152600490fd5b63ffffffff9150604001511615386120cd565b602081015160ff161591506120c6565b90604082019063ffffffff8083511682111561214c5761213560ff9260209262015180955116906115f8565b93015116029062ffffff8216918203611525571190565b60405163b009d33760e01b8152600490fd5b6040519061216b82611144565b601082526f47756172643a204e6f2072696768747360801b6020830152565b1561184e5750565b91604051916020830193600160f91b85526bffffffffffffffffffffffff199060601b16602184015260358301526055820152605581526121d281611116565b51902090565b91604051916020830193600160f81b85526bffffffffffffffffffffffff199060601b16602184015260358301526055820152605581526121d281611116565b9081515b602083015181101561263c576060830151835161226c916001600160a01b03916122459161153b565b511661225583608087015161153b565b516122658461010088015161153b565b51916121d8565b606084015184519192916122b3916001600160a01b039161228c9161153b565b511661229c83608088015161153b565b516122ac8461012089015161153b565b5191612192565b9160005260086020526040600020826000526009806020526122d86040600020611605565b93600052602052600060408120556122f76122f282611571565b612054565b612300836120b2565b8251336001600160a01b039091160361262a5761231d4284612109565b6126185761233261048a83604088015161153b565b81549060ff82169060028210156104a05760028110156104a057036125f25761ffff806060860151169160d01c161061214c5761237963ffffffff604085015116426115f8565b9061238381611571565b9160ff60c084015116602060018060a01b03600254169160246040518094819363c6ee427f60e01b835260048301525afa908115610672576000916125c3575b5060405163313ce56760e01b81526020816004816001600160a01b0386165afa80156106725761242f61240960ff612446936201518095600091612594575b5016611683565b61242961ffff60608c0151169163ffffffff60e01b60608b015116611f6c565b90611691565b61244060ff60208b01511682611691565b94611691565b048215801561258c575b61257a576125237fb09142df05002174e1dd0d23b856f0f7df7c6c43a6491a53e7f07c828f4d6939948a6125569961248a856080986115f8565b956124c66124ab6124a46001600160a01b03841689611c6c565b80986115f8565b6020909b01518b906001600160a01b03908116908416611c2e565b868061255b575b5050606082015182516001600160a01b03916124e9919061153b565b51166124fe61048a604085015185519061153b565b9161251c8c610100612513828d89015161153b565b5196015161153b565b51946118b7565b612532866101208b015161153b565b51946040519283526020830152604082015263ffffffff42166060820152a2611516565b61221c565b8251612573926001600160a01b039182169116611c2e565b38866124cd565b6040516326b1e12960e11b8152600490fd5b508015612450565b6125b6915060203d6020116125bc575b6125ae818361117a565b81019061166a565b38612402565b503d6125a4565b6125e5915060203d6020116125eb575b6125dd818361117a565b81019061164b565b386123c3565b503d6125d3565b60405163e1f2fb3d60e01b81526a1b999d14dd185b99185c9960aa1b6004820152602490fd5b604051639d9e029f60e01b8152600490fd5b604051631c962d0560e01b8152600490fd5b509050565b9081515b602083015181101561263c576060830151835161266e916001600160a01b03916122459161153b565b6060840151845191929161268e916001600160a01b039161228c9161153b565b916000526008602052604060002091806000526009806020526126b46040600020611605565b91600052602052600060408120556126ce6122f284611571565b6126d7816120b2565b6126e14282612109565b156128a0576126ef83611571565b9060ff60c083015116906024602060018060a01b03600254166040519283809263c6ee427f60e01b8252600497888301525afa90811561067257600091612881575b5060405163313ce56760e01b8152926020908490816001600160a01b0385165afa9283156106725761287c968960609461280a6127d06127c26127a360ff7fbcc1719994927933c5e16aafb3b01e6ec102fb62f89c2bb8d5832bd00e4619679b61284e99600091612594575016611683565b61242961ffff8b87015116918d8c63ffffffff60e01b91015116611f6c565b60ff60208501511690611691565b986127ee6127e76001600160a01b0389168c611c6c565b809b6115f8565b602090910151909687916001600160a01b039081169116611c2e565b8186015182516001600160a01b0391612823919061153b565b511661283861048a604085015185519061153b565b9161251c8b61010061251382608089015161153b565b61285d856101208a015161153b565b5193604051918252602082015263ffffffff42166040820152a2611516565b612645565b61289a915060203d6020116125eb576125dd818361117a565b38612731565b60405163de50443160e01b8152600490fd5b602091828201916128c961201284518351906115f8565b9381519263ffffffff4216935b8551811015612a6f57606084015184516001600160a01b039182916128fa9161153b565b511661292061290d84608089015161153b565b519161010088019261226586855161153b565b91600092808452600891828852604093848620916129406122f284611571565b33908a61294c85611571565b01511603612a5e5761296461048a88878d015161153b565b91549160ff831690600280831015612a4a57811015612a365703612a115761ffff808360d01c169260e01c168203612a00579060008051602061352f8339815191526129d2888f94846129cb8f976129c56129fb9e9d9c9b9a9951866115f8565b9061153b565b525161153b565b51855163ffffffff8e16815261ffff93909316602084015291604090a283528652812055611516565b6128d6565b8451633c42e29760e11b8152600490fd5b845163e1f2fb3d60e01b81526a1b999d14dd185b99185c9960aa1b6004820152602490fd5b634e487b7160e01b88526021600452602488fd5b634e487b7160e01b89526021600452602489fd5b8451631837e8d760e11b8152600490fd5b5093925050612a8660808201518251845191612002565b9080519251612a9861201285836115f8565b93805b828110612ab457505050611c1893945033903090611cec565b80612acb612ac584612ad9946115f8565b8a61153b565b5161204961204385846115f8565b612a9b565b9081515b602083015181101561263c576060830180518451919291612b62916001600160a01b0391612b0f9161153b565b5116612b5883612b386080890193612b2883865161153b565b51612265846101008d015161153b565b955188516001600160a01b0391612b4f919061153b565b5116925161153b565b5160055491612192565b82600052600860205260406000208160005260096020526040600020612b8a6122f283611571565b612b9381611605565b80516001600160a01b03161580159190613016575b8115613002575b50612ff057612bbd82611571565b60208101516001600160a01b03163314612fc85760ff612be2866101408b015161153b565b5116158015612fad575b612f2657612bff856101608a015161153b565b51158015612f93575b612f6e5760ff604081612c20886101408d015161153b565b51169201511610612f2657612c3c61048a8560408a015161153b565b91549160ff83169060028210156104a05760028110156104a057036125f257612c6a8461016089015161153b565b5161ffff8360e01c1610612f6e5760025460405163c6ee427f60e01b815260f084901c60ff1660048201529290602090849060249082906001600160a01b03165afa92831561067257600093612f4d575b5060405163313ce56760e01b8152906020826004816001600160a01b0388165afa91821561067257612cfe60ff612d3e9461242993600091612594575016611683565b612d2b8b60ff612d238b610140612d1a8261016087015161153b565b5194015161153b565b511690611691565b9260301b6001600160e01b031916611f6c565b8015612f26576040516323b872dd60e01b6020820152336024820152306044820152606480820192909252908152612f2195612f19948994612e9593612d9791612d8960848361117a565b6001600160a01b03166116d0565b61ffff612da98861016088015161153b565b51169060ff612dbd8961014089015161153b565b51169160405192612dcd84611116565b338452602084015263ffffffff421660408401526060830152600052600960205260406000209060018060a01b038151169082549160ff60a01b602083015160a01b1690604083015192606061ffff60c81b91015160c81b169364ffffffffff60d81b1617179063ffffffff60a81b9060a81b161717905561ffff612e578761016087015161153b565b5116906000526008602052612e7960406000209161ffff835460e01c166116a4565b815461ffff60e01b191660e09190911b61ffff60e01b16179055565b612ea48461010084015161153b565b5160055492839263ffffffff60ff612ed58961014061ffff612ecb836101608a015161153b565b511696015161153b565b5116915460a81c1690604051928352602083015260408201527f61e1a1e6f89eaba4ba0119b0023bd32b1bb0412ab96ccd8d0588a3e98a09763160603392a4611516565b600555611516565b612ae2565b60405163e1f2fb3d60e01b81526b3932b73a223ab930ba34b7b760a11b6004820152602490fd5b612f6791935060203d6020116125eb576125dd818361117a565b9138612cbb565b60405163e1f2fb3d60e01b8152691c995b9d105b5bdd5b9d60b21b6004820152602490fd5b5061ffff612fa6866101608b015161153b565b5111612c08565b5060ff80612fc0876101408c015161153b565b511611612bec565b60405163e1f2fb3d60e01b81526c6c656e6465724164647265737360981b6004820152602490fd5b6040516308e15a0360e21b8152600490fd5b63ffffffff91506040015116151538612baf565b602081015160ff1615159150612ba8565b9081515b60208301518110156134f2576130458160a085015161153b565b511580156134d9575b6134b45760ff6130628260c086015161153b565b511615801561349a575b6134705761307e8160e085015161153b565b5160e01c1561344757606083015183516130be916001600160a01b03916130a49161153b565b51166130b483608087015161153b565b51600454916121d8565b908160005260086020526130d56040600020611571565b60208101516001600160a01b03161580159190613436575b811561341e575b5061340c5760ff61310a8261018087015161153b565b5116156133e75761312261048a82604087015161153b565b60028110156104a05761ffff61313c8360a088015161153b565b519115911681806133dc575b6133b65761315d61048a84604089015161153b565b9360ff61316e8560c08a015161153b565b511663ffffffff60e01b6131868660e08b015161153b565b511660ff613199876101808c015161153b565b5116906131ab876101a08c015161153b565b511515926131c5604051996131bf8b6110c8565b8a611565565b3360208a0152604089015260608801528360808801528360a088015260c087015260e0860152600052600860205260406000209184519260028410156104a057805460208701516040880151606089015160808a01516001600160e01b031990941660ff9098169790971760089290921b610100600160a81b03169190911760a89190911b60ff60a81b161760309590951c63ffffffff60b01b169490941760d09490941b61ffff60d01b169390931783556133b1946133a9939060a0810151825461ffff60e01b191660e09190911b61ffff60e01b1617825560c0810151825460e0909201516001600160f01b0390921660f09190911b60ff60f01b161790151560f81b6001600160f81b031916179055606087015187516001600160a01b03916132f1919061153b565b51166133018560808a015161153b565b5191600454938960ff6133188960c084015161153b565b51169163ffffffff60e01b6133318a60e085015161153b565b51166133558a6101a060ff61334b8361018089015161153b565b511695015161153b565b5115159360405195865288602087015260408601526060850152608084015260a083015260c08201527ff8d82fdbb496215c151d63910926322dcb6ba0f8cbd5fa216ef261106bb1ab4660e03392a4611516565b600455611516565b61302b565b60405163e1f2fb3d60e01b81526a17db195b99105b5bdd5b9d60aa1b6004820152602490fd5b506001811415613148565b60405163e1f2fb3d60e01b8152697061796d656e7449785f60b01b6004820152602490fd5b60405163b9a87ba760e01b8152600490fd5b606001516001600160e01b03191615159050386130f4565b604081015160ff16151591506130ed565b60405163e1f2fb3d60e01b81526d6461696c7952656e74507269636560901b6004820152602490fd5b60405163e1f2fb3d60e01b81526e36b0bc2932b73a223ab930ba34b7b760891b6004820152602490fd5b5060ff806134ac8360c087015161153b565b51161161306c565b60405163e1f2fb3d60e01b8152691b195b99105b5bdd5b9d60b21b6004820152602490fd5b5061ffff6134eb8260a086015161153b565b511161304e565b5090611c189060808101516135246135138351926020850193845191612002565b9160a0840151908451905191612002565b9130903390611cec56fefc33a7c95ee492cb6247bd90b28bbe1f459d8f80f3dc65f934cd020cf1e83efba2646970667358221220c275f1e4de3a5e6ad379ae04fda28b286916212950fe140c0e6b057c1807221064736f6c634300081100330000000000000000000000009f59adf8ca58d0ffd9372af68d747c3dbb4cb02f0000000000000000000000009ab18990c9035f7878a59e134bce5d618cb19d55000000000000000000000000ea6a031bbaf2eadb5ecfd32b8aa39e9a95659e4600000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000099ebd96615a50933c69b435f8a59539caff95d7c000000000000000000000000750449925085a335b58b6706e0cf17039caa606f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000002bc
Deployed ByteCode
0x608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a7146110755750806314b5685c14610fa5578063150b7a0214610f5057806316c38b3c14610ea757806316c61ccc14610e845780631c31f71014610de0578063296c21b714610d0157806337d2aae914610bfb578063565a2e2c14610bd2578063937821a114610afd578063a4052a9514610ac3578063bc197c8114610a3b578063c9c40183146108b5578063cbe55e541461067e578063d7e0936014610539578063dc68a142146101ca578063f23a6e61146101755763fe46b7cd146100e557600080fd5b346101705761011d6100f6366113fc565b916000606060405161010781611116565b8281528260208201528260408201520152612192565b600052600960205260806101346040600020611605565b61ffff60606040519260018060a01b03815116845260ff602082015116602085015263ffffffff60408201511660408501520151166060820152f35b600080fd5b346101705760a03660031901126101705761018e611219565b5061019761122f565b506084356001600160401b038111610170576101b79036906004016113b5565b5060405163f23a6e6160e01b8152602090f35b3461017057610100366003190112610170576001600160401b03600435818111610170576101fc9036906004016111b2565b9060243581811161017057610215903690600401611245565b906044358181116101705761022e9036906004016112b3565b606435828111610170576102469036906004016112b3565b936084358381116101705761025f903690600401611426565b9160a4359584871161017057366023880112156101705786600401356102848161119b565b97610292604051998a61117a565b818952602460208a019260051b8201019036821161017057602401915b8183106105185750505060c435858111610170576102d1903690600401611426565b9360e4359586116101705736602387011215610170578560040135956102f68761119b565b96610304604051988961117a565b80885260208801913660248360051b83010111610170579160248301925b60248360051b82010184106104f8575050505060ff600654166104e65760209761034a61148e565b610352611e2d565b50604051916103608361115f565b60008352604051936103718561115f565b60008552604051956103828761115f565b60008752604051976103938961115f565b6000895260016040519d8e6103a7816110fa565b60008152015260408d01528a60608d015260808c015260a08b015260c08a015260e08901526101008801526101208701526101408601526101608501526101808401526101a083015251156104c5575b60208101516060820151908151146104b65781516001600160a01b0391829161041f9161153b565b511690610435606084015160208501519061153b565b51161480610473575b1561045a576104506020820151611516565b60208201526103f7565b61046381613027565b6104506020820151808352611516565b5061048f61048a604083015160208401519061153b565b6115eb565b60028110156104a05760011461043e565b634e487b7160e01b600052602160045260246000fd5b6104bf82613027565b60018055005b60405163e1f2fb3d60e01b81526562756e646c6560d01b6004820152602490fd5b6040516313d0ff5960e31b8152600490fd5b833515158435036101705760208060249386358152019401939150610322565b82356001600160e01b031981168103610170578152602092830192016102af565b3461017057604036600319011261017057610552611219565b600054604051630f6266a760e01b8152306004820152336024808301919091526020939035926001600160a01b03929085908290604490829087165afa8015610672576105b091600091610645575b506105aa61215e565b9061218a565b6107d0831161061f571691826000526007815281604060002054141560001461060d577f5820e211ee8cba31a6b5e7909a12b6dac26ce15657d066c5269d1e60f5abd31691836000526007825280604060002055604051908152a2005b60405163c23f6ccb60e01b8152600490fd5b60405163e1f2fb3d60e01b81526a6e657752656e744665655f60a81b6004820152602490fd5b6106659150863d881161066b575b61065d818361117a565b8101906116b8565b866105a1565b503d610653565b6040513d6000823e3d90fd5b346101705760c0366003190112610170576001600160401b03600435818111610170576106af9036906004016111b2565b602435828111610170576106c7903690600401611245565b604435838111610170576106df9036906004016112b3565b91606435848111610170576106f89036906004016112b3565b60843585811161017057610710903690600401611426565b9460a435908111610170576107299036906004016112b3565b60ff600654166104e65760209561073e61148e565b610746611e2d565b50604051926107548461115f565b60008452604051906107658261115f565b600082526040516107758161115f565b60008152604051906107868261115f565b60008252604051966107978861115f565b60008852604051986107a88a61115f565b60008a5260016040519d8e6107bc816110fa565b60008152015260408d015260608c019a8a8c5260808d015260a08c015260c08b015260e08a01526101008901526101208801526101408701526101608601526101808501526101a084015251156104c5575b60208201518151908151146108ac5782516001600160a01b039182916108339161153b565b511690610846835160208601519061153b565b51161480610884575b1561086b576108616020830151611516565b602083015261080e565b61087482612ade565b6108616020830151808452611516565b5061089b61048a604084015160208501519061153b565b60028110156104a05760011461084f565b6104bf83612ade565b34610170576080366003190112610170576001600160401b03600435818111610170576108e69036906004016111b2565b90602491823582811161017057610901903690600401611245565b916044358181116101705761091a9036906004016112b3565b90606435908111610170576109339036906004016112b3565b9060ff600654166104e6576109609361094a61148e565b604051936109578561115f565b60008552611e96565b606081019182515115610a1d5760208201925b8351815190815114610a145783516001600160a01b039182916109959161153b565b5116906109a5835187519061153b565b511614806109da575b156109c4576109bd8451611516565b8452610973565b6109cd836128b2565b6109bd8451808552611516565b506109ee61048a604085015186519061153b565b60028110156109ff576001146109ae565b82634e487b7160e01b60005260216004526000fd5b6104bf846128b2565b60405163e1f2fb3d60e01b81526562756e646c6560d01b6004820152fd5b346101705760a036600319011261017057610a54611219565b50610a5d61122f565b506001600160401b0360443581811161017057610a7e9036906004016112b3565b5060643581811161017057610a979036906004016112b3565b5060843590811161017057610ab09036906004016113b5565b5060405163bc197c8160e01b8152602090f35b34610170576020366003190112610170576001600160a01b03610ae4611219565b1660005260076020526020604060002054604051908152f35b3461017057610b0b36611311565b9260ff600693929354166104e657610b2a94610b2561148e565b611e96565b6060810190815151156104c55760208101915b8251815190815114610bc95782516001600160a01b03918291610b5f9161153b565b511690610b6f835186519061153b565b51161480610ba4575b15610b8e57610b878351611516565b8352610b3d565b610b9782612641565b610b878351808452611516565b50610bb861048a604084015185519061153b565b60028110156104a057600114610b78565b6104bf83612641565b34610170576000366003190112610170576003546040516001600160a01b039091168152602090f35b346101705760208060031936011261017057610c15611219565b600054604051630f6266a760e01b81523060048201523360248201526001600160a01b03808316949293919291908284604481895afa91821561067257610c6d610ca193610cd496600091610ce457506105aa61215e565b16948560405191610c7d83611144565b601183527047756172643a2073616d652076616c756560781b85840152141561218a565b7247756172643a207a65726f206164647265737360681b60405191610cc583611144565b6013835282015283151561218a565b6001600160a01b03191617600055005b610cfb9150863d881161066b5761065d818361117a565b896105a1565b3461017057610d51610d12366113fc565b91600060e0604051610d23816110c8565b8281528260208201528260408201528260608201528260808201528260a08201528260c082015201526121d8565b6000526008602052610d666040600020611571565b604051815160028110156104a0576101009260e091835260018060a01b03602082015116602084015260ff604082015116604084015263ffffffff821b606082015116606084015261ffff80608083015116608085015260a08201511660a084015260ff60c08201511660c08401520151151560e0820152f35b3461017057602036600319011261017057610df9611219565b600054604051630f6266a760e01b81523060048201523360248201526001600160a01b0392916020908290604490829087165afa801561067257610e4791600091610e6657506105aa61215e565b600354908216918116821461060d576001600160a01b03191617600355005b610e7e915060203d811161066b5761065d818361117a565b846105a1565b3461017057600036600319011261017057602060ff600654166040519015158152f35b346101705760203660031901126101705760043580151580910361017057600054604051630f6266a760e01b815230600482015233602482015290602090829060449082906001600160a01b03165afa801561067257610f1191600091610f3257506105aa61215e565b6006549060ff82161515811461060d5760ff169060ff191617600655600080f35b610f4a915060203d811161066b5761065d818361117a565b836105a1565b3461017057608036600319011261017057610f69611219565b50610f7261122f565b506064356001600160401b03811161017057610f929036906004016113b5565b50604051630a85bd0160e11b8152602090f35b3461017057610fb336611311565b9260ff600693929354166104e657610fcd94610b2561148e565b6060810190815151156104c55760208101915b825181519081511461106c5782516001600160a01b039182916110029161153b565b511690611012835186519061153b565b51161480611047575b156110315761102a8351611516565b8352610fe0565b61103a82612218565b61102a8351808452611516565b5061105b61048a604084015185519061153b565b60028110156104a05760011461101b565b6104bf83612218565b34610170576020366003190112610170576004359063ffffffff60e01b821680920361017057602091630271189760e51b81149081156110b7575b5015158152f35b6301ffc9a760e01b149050836110b0565b61010081019081106001600160401b038211176110e457604052565b634e487b7160e01b600052604160045260246000fd5b6101c081019081106001600160401b038211176110e457604052565b608081019081106001600160401b038211176110e457604052565b6001600160401b0381116110e457604052565b604081019081106001600160401b038211176110e457604052565b602081019081106001600160401b038211176110e457604052565b90601f801991011681019081106001600160401b038211176110e457604052565b6001600160401b0381116110e45760051b60200190565b81601f82011215610170578035916111c98361119b565b926111d7604051948561117a565b808452602092838086019260051b820101928311610170578301905b828210611201575050505090565b813560028110156101705781529083019083016111f3565b600435906001600160a01b038216820361017057565b602435906001600160a01b038216820361017057565b81601f820112156101705780359161125c8361119b565b9261126a604051948561117a565b808452602092838086019260051b820101928311610170578301905b828210611294575050505090565b81356001600160a01b0381168103610170578152908301908301611286565b81601f82011215610170578035916112ca8361119b565b926112d8604051948561117a565b808452602092838086019260051b820101928311610170578301905b828210611302575050505090565b813581529083019083016112f4565b60a0600319820112610170576004906001600160401b038235818111610170578261133d9185016111b2565b936024358281116101705783611354918601611245565b93604435838111610170578461136b9183016112b3565b9360643584811161017057816113829184016112b3565b936084359081116101705761139792016112b3565b90565b6001600160401b0381116110e457601f01601f191660200190565b81601f82011215610170578035906113cc8261139a565b926113da604051948561117a565b8284526020838301011161017057816000926020809301838601378301015290565b6060906003190112610170576004356001600160a01b038116810361017057906024359060443590565b81601f820112156101705780359161143d8361119b565b9261144b604051948561117a565b808452602092838086019260051b820101928311610170578301905b828210611475575050505090565b813560ff81168103610170578152908301908301611467565b60026001541461149f576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b906114ee8261119b565b6114fb604051918261117a565b828152809261150c601f199161119b565b0190602036910137565b60001981146115255760010190565b634e487b7160e01b600052601160045260246000fd5b805182101561154f5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b60028210156104a05752565b9060405161157e816110c8565b60e081935461159060ff821684611565565b60018060a01b038160081c16602084015260ff8160a81c16604084015263ffffffff821b8160301b16606084015261ffff808260d01c16608085015281831c1660a084015260ff8160f01c1660c084015260f81c1515910152565b5160028110156104a05790565b9190820391821161152557565b9060405161161281611116565b91546001600160a01b038116835260a081901c60ff16602084015260a881901c63ffffffff16604084015260c81c61ffff166060830152565b9081602091031261017057516001600160a01b03811681036101705790565b90816020910312610170575160ff811681036101705790565b604d811161152557600a0a90565b8181029291811591840414171561152557565b61ffff918216908216039190821161152557565b90816020910312610170575180151581036101705790565b60405161174d916001600160a01b03166116e982611144565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af13d156117d5573d916117318361139a565b9261173f604051948561117a565b83523d60008785013e6117d9565b8051908282159283156117bd575b505050156117665750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b6117cd93508201810191016116b8565b38828161175b565b6060915b9192901561183b57508151156117ed575090565b3b156117f65790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b82519091501561184e5750805190602001fd5b60405162461bcd60e51b815290819061186a906004830161186e565b0390fd5b6020808252825181830181905290939260005b8281106118a357505060409293506000838284010152601f8019910116010190565b818101860151848201604001528501611881565b91939092938254926000938060f81c15600014611bd45750805461ffff966060888360d01c169701968888511690818111600014611a0657505050509061192661190a8787511688855460d01c166116a4565b835461ffff60d01b191660d09190911b61ffff60d01b16178355565b905484518616926001600160a01b0392831692909160081c16823b15611a0257604051637921219560e11b81523060048201526001600160a01b039190911660248201526044810191909152606481019290925260a06084830152600060a48301528290829060c490829084905af180156119f7576119e0575b505060008051602061352f833981519152916119db915b516040805163ffffffff421681529290911661ffff16602083015290918291820190565b0390a2565b6119ea8291611131565b6119f457806119a0565b80fd5b6040513d84823e3d90fd5b8480fd5b14611a2b575b50505050505060008051602061352f833981519152916119db916119b7565b6002811015611bc057611afc5750546001600160a01b038281169160081c16813b15611a0257604051632142170760e11b81523060048201526001600160a01b03919091166024820152604481018490529084908290606490829084905af18015611af1579087939291611ad2575b506119db949260008051602061352f833981519152969492611abb926121d8565b815260086020526040812055918193388080611a0c565b8491929350611ae090611131565b611aed5790859138611a9a565b8280fd5b6040513d86823e3d90fd5b855192949392871691506001600160a01b0380861691823b15611bbc57604051637921219560e11b815230600482015260089190911c919091166001600160a01b0316602482015260448101849052606481019290925260a06084830152600060a48301528390829060c490829084905af18015611bb15760008051602061352f8339815191529694926119db9694928992611b9e575b50611abb92936121d8565b92611bab611abb94611131565b92611b93565b6040513d85823e3d90fd5b8580fd5b634e487b7160e01b86526021600452602486fd5b93979650939150506060935061ffff809481920151169160e01c1601918211611c1a57805461ffff60e01b191660e09290921b61ffff60e01b169190911790559050565b565b634e487b7160e01b84526011600452602484fd5b60405163a9059cbb60e01b60208201526001600160a01b039092166024830152604480830193909352918152611c1891611c6782611116565b6116d0565b6001600160a01b03918216600081815260076020526040902054909392918115611caf57611ca1611c18939261271092611691565b049384916003541690611c2e565b50600093505050565b90815180825260208080930193019160005b828110611cd8575050505090565b835185529381019392810192600101611cca565b9193929092611d0461048a604085015185519061153b565b60028110156104a057611d9857505060608101518151611d40916001600160a01b0391611d309161153b565b511691608081015190519061153b565b5190803b1561017057604051632142170760e11b81526001600160a01b03938416600482015293909216602484015260448301526000908290606490829084905af1801561067257611d8f5750565b611c1890611131565b9092606083015192611db460018060a01b03948592519061153b565b511691823b156101705760206000959186611e10611dfd8295896040519c8d9b8c9a631759616b60e11b8c521660048b015216602489015260a0604489015260a4880190611cb8565b6003199384888303016064890152611cb8565b85810392830160848701525201925af1801561067257611d8f5750565b60405190611e3a826110fa565b8160008152600060208201526101a060609182604082015282808201528260808201528260a08201528260c08201528260e082015282610100820152826101208201528261014082015282610160820152826101808201520152565b9193929093611ea3611e2d565b50604093845192611eb38461115f565b600096878552865193611ec58561115f565b888552875195611ed48761115f565b898752885191611ee38361115f565b8a8352895193611ef28561115f565b8b85528a5199611f018b61115f565b8c8b528b519b611f108d61115f565b8d8d528051809e611f20826110fa565b8152602001600190528d015260608c015260808b015260a08a015260c089015260e08801526101008701526101208601526101408501526101608401526101808301526101a082015290565b8060e01c80158015611ff7575b611fd757611fb99160f01c908361ffff8092169261270f808211611fcf575b808511611fc5575b506127109183611fb09216611691565b94049116611691565b81018091116115255790565b9350612710611fa0565b905080611f98565b60405163e1f2fb3d60e01b815264707269636560d81b6004820152602490fd5b506127108310611f79565b92919061201761201282846115f8565b6114e4565b93815b8381106120275750505050565b8061203561204f928461153b565b5161204961204386846115f8565b8961153b565b52611516565b61201a565b60208101516001600160a01b0316159081156120a2575b811561208b575b5061207957565b604051631c9bac5160e21b8152600490fd5b606001516001600160e01b03191615905038612072565b604081015160ff1615915061206b565b80516001600160a01b0316159081156120f9575b81156120e6575b506120d457565b604051630269a7b160e11b8152600490fd5b63ffffffff9150604001511615386120cd565b602081015160ff161591506120c6565b90604082019063ffffffff8083511682111561214c5761213560ff9260209262015180955116906115f8565b93015116029062ffffff8216918203611525571190565b60405163b009d33760e01b8152600490fd5b6040519061216b82611144565b601082526f47756172643a204e6f2072696768747360801b6020830152565b1561184e5750565b91604051916020830193600160f91b85526bffffffffffffffffffffffff199060601b16602184015260358301526055820152605581526121d281611116565b51902090565b91604051916020830193600160f81b85526bffffffffffffffffffffffff199060601b16602184015260358301526055820152605581526121d281611116565b9081515b602083015181101561263c576060830151835161226c916001600160a01b03916122459161153b565b511661225583608087015161153b565b516122658461010088015161153b565b51916121d8565b606084015184519192916122b3916001600160a01b039161228c9161153b565b511661229c83608088015161153b565b516122ac8461012089015161153b565b5191612192565b9160005260086020526040600020826000526009806020526122d86040600020611605565b93600052602052600060408120556122f76122f282611571565b612054565b612300836120b2565b8251336001600160a01b039091160361262a5761231d4284612109565b6126185761233261048a83604088015161153b565b81549060ff82169060028210156104a05760028110156104a057036125f25761ffff806060860151169160d01c161061214c5761237963ffffffff604085015116426115f8565b9061238381611571565b9160ff60c084015116602060018060a01b03600254169160246040518094819363c6ee427f60e01b835260048301525afa908115610672576000916125c3575b5060405163313ce56760e01b81526020816004816001600160a01b0386165afa80156106725761242f61240960ff612446936201518095600091612594575b5016611683565b61242961ffff60608c0151169163ffffffff60e01b60608b015116611f6c565b90611691565b61244060ff60208b01511682611691565b94611691565b048215801561258c575b61257a576125237fb09142df05002174e1dd0d23b856f0f7df7c6c43a6491a53e7f07c828f4d6939948a6125569961248a856080986115f8565b956124c66124ab6124a46001600160a01b03841689611c6c565b80986115f8565b6020909b01518b906001600160a01b03908116908416611c2e565b868061255b575b5050606082015182516001600160a01b03916124e9919061153b565b51166124fe61048a604085015185519061153b565b9161251c8c610100612513828d89015161153b565b5196015161153b565b51946118b7565b612532866101208b015161153b565b51946040519283526020830152604082015263ffffffff42166060820152a2611516565b61221c565b8251612573926001600160a01b039182169116611c2e565b38866124cd565b6040516326b1e12960e11b8152600490fd5b508015612450565b6125b6915060203d6020116125bc575b6125ae818361117a565b81019061166a565b38612402565b503d6125a4565b6125e5915060203d6020116125eb575b6125dd818361117a565b81019061164b565b386123c3565b503d6125d3565b60405163e1f2fb3d60e01b81526a1b999d14dd185b99185c9960aa1b6004820152602490fd5b604051639d9e029f60e01b8152600490fd5b604051631c962d0560e01b8152600490fd5b509050565b9081515b602083015181101561263c576060830151835161266e916001600160a01b03916122459161153b565b6060840151845191929161268e916001600160a01b039161228c9161153b565b916000526008602052604060002091806000526009806020526126b46040600020611605565b91600052602052600060408120556126ce6122f284611571565b6126d7816120b2565b6126e14282612109565b156128a0576126ef83611571565b9060ff60c083015116906024602060018060a01b03600254166040519283809263c6ee427f60e01b8252600497888301525afa90811561067257600091612881575b5060405163313ce56760e01b8152926020908490816001600160a01b0385165afa9283156106725761287c968960609461280a6127d06127c26127a360ff7fbcc1719994927933c5e16aafb3b01e6ec102fb62f89c2bb8d5832bd00e4619679b61284e99600091612594575016611683565b61242961ffff8b87015116918d8c63ffffffff60e01b91015116611f6c565b60ff60208501511690611691565b986127ee6127e76001600160a01b0389168c611c6c565b809b6115f8565b602090910151909687916001600160a01b039081169116611c2e565b8186015182516001600160a01b0391612823919061153b565b511661283861048a604085015185519061153b565b9161251c8b61010061251382608089015161153b565b61285d856101208a015161153b565b5193604051918252602082015263ffffffff42166040820152a2611516565b612645565b61289a915060203d6020116125eb576125dd818361117a565b38612731565b60405163de50443160e01b8152600490fd5b602091828201916128c961201284518351906115f8565b9381519263ffffffff4216935b8551811015612a6f57606084015184516001600160a01b039182916128fa9161153b565b511661292061290d84608089015161153b565b519161010088019261226586855161153b565b91600092808452600891828852604093848620916129406122f284611571565b33908a61294c85611571565b01511603612a5e5761296461048a88878d015161153b565b91549160ff831690600280831015612a4a57811015612a365703612a115761ffff808360d01c169260e01c168203612a00579060008051602061352f8339815191526129d2888f94846129cb8f976129c56129fb9e9d9c9b9a9951866115f8565b9061153b565b525161153b565b51855163ffffffff8e16815261ffff93909316602084015291604090a283528652812055611516565b6128d6565b8451633c42e29760e11b8152600490fd5b845163e1f2fb3d60e01b81526a1b999d14dd185b99185c9960aa1b6004820152602490fd5b634e487b7160e01b88526021600452602488fd5b634e487b7160e01b89526021600452602489fd5b8451631837e8d760e11b8152600490fd5b5093925050612a8660808201518251845191612002565b9080519251612a9861201285836115f8565b93805b828110612ab457505050611c1893945033903090611cec565b80612acb612ac584612ad9946115f8565b8a61153b565b5161204961204385846115f8565b612a9b565b9081515b602083015181101561263c576060830180518451919291612b62916001600160a01b0391612b0f9161153b565b5116612b5883612b386080890193612b2883865161153b565b51612265846101008d015161153b565b955188516001600160a01b0391612b4f919061153b565b5116925161153b565b5160055491612192565b82600052600860205260406000208160005260096020526040600020612b8a6122f283611571565b612b9381611605565b80516001600160a01b03161580159190613016575b8115613002575b50612ff057612bbd82611571565b60208101516001600160a01b03163314612fc85760ff612be2866101408b015161153b565b5116158015612fad575b612f2657612bff856101608a015161153b565b51158015612f93575b612f6e5760ff604081612c20886101408d015161153b565b51169201511610612f2657612c3c61048a8560408a015161153b565b91549160ff83169060028210156104a05760028110156104a057036125f257612c6a8461016089015161153b565b5161ffff8360e01c1610612f6e5760025460405163c6ee427f60e01b815260f084901c60ff1660048201529290602090849060249082906001600160a01b03165afa92831561067257600093612f4d575b5060405163313ce56760e01b8152906020826004816001600160a01b0388165afa91821561067257612cfe60ff612d3e9461242993600091612594575016611683565b612d2b8b60ff612d238b610140612d1a8261016087015161153b565b5194015161153b565b511690611691565b9260301b6001600160e01b031916611f6c565b8015612f26576040516323b872dd60e01b6020820152336024820152306044820152606480820192909252908152612f2195612f19948994612e9593612d9791612d8960848361117a565b6001600160a01b03166116d0565b61ffff612da98861016088015161153b565b51169060ff612dbd8961014089015161153b565b51169160405192612dcd84611116565b338452602084015263ffffffff421660408401526060830152600052600960205260406000209060018060a01b038151169082549160ff60a01b602083015160a01b1690604083015192606061ffff60c81b91015160c81b169364ffffffffff60d81b1617179063ffffffff60a81b9060a81b161717905561ffff612e578761016087015161153b565b5116906000526008602052612e7960406000209161ffff835460e01c166116a4565b815461ffff60e01b191660e09190911b61ffff60e01b16179055565b612ea48461010084015161153b565b5160055492839263ffffffff60ff612ed58961014061ffff612ecb836101608a015161153b565b511696015161153b565b5116915460a81c1690604051928352602083015260408201527f61e1a1e6f89eaba4ba0119b0023bd32b1bb0412ab96ccd8d0588a3e98a09763160603392a4611516565b600555611516565b612ae2565b60405163e1f2fb3d60e01b81526b3932b73a223ab930ba34b7b760a11b6004820152602490fd5b612f6791935060203d6020116125eb576125dd818361117a565b9138612cbb565b60405163e1f2fb3d60e01b8152691c995b9d105b5bdd5b9d60b21b6004820152602490fd5b5061ffff612fa6866101608b015161153b565b5111612c08565b5060ff80612fc0876101408c015161153b565b511611612bec565b60405163e1f2fb3d60e01b81526c6c656e6465724164647265737360981b6004820152602490fd5b6040516308e15a0360e21b8152600490fd5b63ffffffff91506040015116151538612baf565b602081015160ff1615159150612ba8565b9081515b60208301518110156134f2576130458160a085015161153b565b511580156134d9575b6134b45760ff6130628260c086015161153b565b511615801561349a575b6134705761307e8160e085015161153b565b5160e01c1561344757606083015183516130be916001600160a01b03916130a49161153b565b51166130b483608087015161153b565b51600454916121d8565b908160005260086020526130d56040600020611571565b60208101516001600160a01b03161580159190613436575b811561341e575b5061340c5760ff61310a8261018087015161153b565b5116156133e75761312261048a82604087015161153b565b60028110156104a05761ffff61313c8360a088015161153b565b519115911681806133dc575b6133b65761315d61048a84604089015161153b565b9360ff61316e8560c08a015161153b565b511663ffffffff60e01b6131868660e08b015161153b565b511660ff613199876101808c015161153b565b5116906131ab876101a08c015161153b565b511515926131c5604051996131bf8b6110c8565b8a611565565b3360208a0152604089015260608801528360808801528360a088015260c087015260e0860152600052600860205260406000209184519260028410156104a057805460208701516040880151606089015160808a01516001600160e01b031990941660ff9098169790971760089290921b610100600160a81b03169190911760a89190911b60ff60a81b161760309590951c63ffffffff60b01b169490941760d09490941b61ffff60d01b169390931783556133b1946133a9939060a0810151825461ffff60e01b191660e09190911b61ffff60e01b1617825560c0810151825460e0909201516001600160f01b0390921660f09190911b60ff60f01b161790151560f81b6001600160f81b031916179055606087015187516001600160a01b03916132f1919061153b565b51166133018560808a015161153b565b5191600454938960ff6133188960c084015161153b565b51169163ffffffff60e01b6133318a60e085015161153b565b51166133558a6101a060ff61334b8361018089015161153b565b511695015161153b565b5115159360405195865288602087015260408601526060850152608084015260a083015260c08201527ff8d82fdbb496215c151d63910926322dcb6ba0f8cbd5fa216ef261106bb1ab4660e03392a4611516565b600455611516565b61302b565b60405163e1f2fb3d60e01b81526a17db195b99105b5bdd5b9d60aa1b6004820152602490fd5b506001811415613148565b60405163e1f2fb3d60e01b8152697061796d656e7449785f60b01b6004820152602490fd5b60405163b9a87ba760e01b8152600490fd5b606001516001600160e01b03191615159050386130f4565b604081015160ff16151591506130ed565b60405163e1f2fb3d60e01b81526d6461696c7952656e74507269636560901b6004820152602490fd5b60405163e1f2fb3d60e01b81526e36b0bc2932b73a223ab930ba34b7b760891b6004820152602490fd5b5060ff806134ac8360c087015161153b565b51161161306c565b60405163e1f2fb3d60e01b8152691b195b99105b5bdd5b9d60b21b6004820152602490fd5b5061ffff6134eb8260a086015161153b565b511161304e565b5090611c189060808101516135246135138351926020850193845191612002565b9160a0840151908451905191612002565b9130903390611cec56fefc33a7c95ee492cb6247bd90b28bbe1f459d8f80f3dc65f934cd020cf1e83efba2646970667358221220c275f1e4de3a5e6ad379ae04fda28b286916212950fe140c0e6b057c1807221064736f6c63430008110033