More Info
Private Name Tags
ContractCreator
Multichain Info
1 address found via
Latest 25 from a total of 220 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Close Loan | 17707858 | 645 days ago | IN | 0 ETH | 0.00170731 | ||||
Close Loan | 17707854 | 645 days ago | IN | 0 ETH | 0.00175988 | ||||
Seize Collateral | 17702928 | 645 days ago | IN | 0 ETH | 0.00189067 | ||||
Close Loan | 17387009 | 690 days ago | IN | 0 ETH | 0.0061452 | ||||
Repay And Close ... | 17029510 | 740 days ago | IN | 0 ETH | 0.00221814 | ||||
Lend | 17022551 | 741 days ago | IN | 0 ETH | 0.00270337 | ||||
Create Loan | 16911791 | 757 days ago | IN | 0 ETH | 0.00366317 | ||||
Close Loan | 16846013 | 766 days ago | IN | 0 ETH | 0.00172545 | ||||
Close Loan | 16825140 | 769 days ago | IN | 0 ETH | 0.00118075 | ||||
Create Loan | 16806982 | 772 days ago | IN | 0 ETH | 0.00932896 | ||||
Seize Collateral | 16757732 | 778 days ago | IN | 0 ETH | 0.00301617 | ||||
Lend | 16748490 | 780 days ago | IN | 0 ETH | 0.00457091 | ||||
Create Loan | 16745194 | 780 days ago | IN | 0 ETH | 0.00720119 | ||||
Create Loan | 16744238 | 780 days ago | IN | 0 ETH | 0.00536428 | ||||
Create Loan | 16735900 | 782 days ago | IN | 0 ETH | 0.01283944 | ||||
Create Loan | 16702559 | 786 days ago | IN | 0 ETH | 0.0048847 | ||||
Create Loan | 16697399 | 787 days ago | IN | 0 ETH | 0.0061399 | ||||
Create Loan | 16677270 | 790 days ago | IN | 0 ETH | 0.00751735 | ||||
Create Loan | 16610835 | 799 days ago | IN | 0 ETH | 0.00325314 | ||||
Create Loan | 16610798 | 799 days ago | IN | 0 ETH | 0.00406128 | ||||
Seize Collateral | 16338680 | 837 days ago | IN | 0 ETH | 0.00162879 | ||||
Repay And Close ... | 16256170 | 849 days ago | IN | 0 ETH | 0.0018898 | ||||
Create Loan | 16101821 | 870 days ago | IN | 0 ETH | 0.00331506 | ||||
Close Loan | 16078848 | 873 days ago | IN | 0 ETH | 0.00163212 | ||||
Create Loan | 16032722 | 880 days ago | IN | 0 ETH | 0.00398408 |
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
- | 14636317 | 1095 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
NFTLoanFacilitator
Compiler Version
v0.8.12+commit.f00d7308
Optimization Enabled:
Yes with 100000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.12; import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import {SafeTransferLib, ERC20} from "@rari-capital/solmate/src/utils/SafeTransferLib.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {IERC1820Registry} from "@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol"; import {IERC777Recipient} from "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol"; import {INFTLoanFacilitator} from './interfaces/INFTLoanFacilitator.sol'; import {IERC721Mintable} from './interfaces/IERC721Mintable.sol'; import {ILendTicket} from './interfaces/ILendTicket.sol'; contract NFTLoanFacilitator is Ownable, INFTLoanFacilitator, IERC777Recipient { using SafeTransferLib for ERC20; // ==== constants ==== /** * See {INFTLoanFacilitator-INTEREST_RATE_DECIMALS}. * @dev lowest non-zero APR possible = (1/10^3) = 0.001 = 0.1% */ uint8 public constant override INTEREST_RATE_DECIMALS = 3; /// See {INFTLoanFacilitator-SCALAR}. uint256 public constant override SCALAR = 10 ** INTEREST_RATE_DECIMALS; // ==== state variables ==== /// See {INFTLoanFacilitator-originationFeeRate}. /// @dev starts at 1% uint256 public override originationFeeRate = 10 ** (INTEREST_RATE_DECIMALS - 2); /// See {INFTLoanFacilitator-requiredImprovementRate}. /// @dev starts at 10% uint256 public override requiredImprovementRate = 10 ** (INTEREST_RATE_DECIMALS - 1); /// See {INFTLoanFacilitator-lendTicketContract}. address public override lendTicketContract; /// See {INFTLoanFacilitator-borrowTicketContract}. address public override borrowTicketContract; /// See {INFTLoanFacilitator-loanInfo}. mapping(uint256 => Loan) public loanInfo; /// @dev tracks loan count uint256 private _nonce = 1; // ==== modifiers ==== modifier notClosed(uint256 loanId) { require(!loanInfo[loanId].closed, "loan closed"); _; } // ==== constructor ==== constructor(address _manager) { transferOwnership(_manager); IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24).setInterfaceImplementer( address(this), keccak256("ERC777TokensRecipient"), address(this) ); } // ==== state changing external functions ==== /// See {INFTLoanFacilitator-createLoan}. function createLoan( uint256 collateralTokenId, address collateralContractAddress, uint16 maxPerAnnumInterest, bool allowLoanAmountIncrease, uint128 minLoanAmount, address loanAssetContractAddress, uint32 minDurationSeconds, address mintBorrowTicketTo ) external override returns (uint256 id) { require(minDurationSeconds != 0, '0 duration'); require(minLoanAmount != 0, '0 loan amount'); require(collateralContractAddress != lendTicketContract, 'lend ticket collateral'); require(collateralContractAddress != borrowTicketContract, 'borrow ticket collateral'); IERC721(collateralContractAddress).transferFrom(msg.sender, address(this), collateralTokenId); unchecked { id = _nonce++; } Loan storage loan = loanInfo[id]; loan.allowLoanAmountIncrease = allowLoanAmountIncrease; loan.originationFeeRate = uint88(originationFeeRate); loan.loanAssetContractAddress = loanAssetContractAddress; loan.loanAmount = minLoanAmount; loan.collateralTokenId = collateralTokenId; loan.collateralContractAddress = collateralContractAddress; loan.perAnnumInterestRate = maxPerAnnumInterest; loan.durationSeconds = minDurationSeconds; IERC721Mintable(borrowTicketContract).mint(mintBorrowTicketTo, id); emit CreateLoan( id, msg.sender, collateralTokenId, collateralContractAddress, maxPerAnnumInterest, loanAssetContractAddress, allowLoanAmountIncrease, minLoanAmount, minDurationSeconds ); } /// See {INFTLoanFacilitator-closeLoan}. function closeLoan(uint256 loanId, address sendCollateralTo) external override notClosed(loanId) { require(IERC721(borrowTicketContract).ownerOf(loanId) == msg.sender, "borrow ticket holder only"); Loan storage loan = loanInfo[loanId]; require(loan.lastAccumulatedTimestamp == 0, "has lender"); loan.closed = true; IERC721(loan.collateralContractAddress).transferFrom(address(this), sendCollateralTo, loan.collateralTokenId); emit Close(loanId); } /// See {INFTLoanFacilitator-lend}. function lend( uint256 loanId, uint16 interestRate, uint128 amount, uint32 durationSeconds, address sendLendTicketTo ) external override notClosed(loanId) { Loan storage loan = loanInfo[loanId]; if (loan.lastAccumulatedTimestamp == 0) { address loanAssetContractAddress = loan.loanAssetContractAddress; require(loanAssetContractAddress.code.length != 0, "invalid loan"); require(interestRate <= loan.perAnnumInterestRate, 'rate too high'); require(durationSeconds >= loan.durationSeconds, 'duration too low'); if (loan.allowLoanAmountIncrease) { require(amount >= loan.loanAmount, 'amount too low'); } else { require(amount == loan.loanAmount, 'invalid amount'); } loan.perAnnumInterestRate = interestRate; loan.lastAccumulatedTimestamp = uint40(block.timestamp); loan.durationSeconds = durationSeconds; loan.loanAmount = amount; uint256 facilitatorTake = amount * uint256(loan.originationFeeRate) / SCALAR; ERC20(loanAssetContractAddress).safeTransferFrom(msg.sender, address(this), facilitatorTake); ERC20(loanAssetContractAddress).safeTransferFrom( msg.sender, IERC721(borrowTicketContract).ownerOf(loanId), amount - facilitatorTake ); IERC721Mintable(lendTicketContract).mint(sendLendTicketTo, loanId); } else { uint256 previousLoanAmount = loan.loanAmount; // implicitly checks that amount >= loan.loanAmount // will underflow if amount < previousAmount uint256 amountIncrease = amount - previousLoanAmount; if (!loan.allowLoanAmountIncrease) { require(amountIncrease == 0, 'amount increase not allowed'); } uint256 accumulatedInterest; { uint256 previousInterestRate = loan.perAnnumInterestRate; uint256 previousDurationSeconds = loan.durationSeconds; require(interestRate <= previousInterestRate, 'rate too high'); require(durationSeconds >= previousDurationSeconds, 'duration too low'); require( Math.ceilDiv(previousLoanAmount * requiredImprovementRate, SCALAR) <= amountIncrease || previousDurationSeconds + Math.ceilDiv(previousDurationSeconds * requiredImprovementRate, SCALAR) <= durationSeconds || (previousInterestRate != 0 // do not allow rate improvement if rate already 0 && previousInterestRate - Math.ceilDiv(previousInterestRate * requiredImprovementRate, SCALAR) >= interestRate), "insufficient improvement" ); accumulatedInterest = _interestOwed( previousLoanAmount, loan.lastAccumulatedTimestamp, previousInterestRate, loan.accumulatedInterest ); } require(accumulatedInterest < 1 << 128, "interest exceeds uint128"); loan.perAnnumInterestRate = interestRate; loan.lastAccumulatedTimestamp = uint40(block.timestamp); loan.durationSeconds = durationSeconds; loan.loanAmount = amount; loan.accumulatedInterest = uint128(accumulatedInterest); address currentLoanOwner = IERC721(lendTicketContract).ownerOf(loanId); ILendTicket(lendTicketContract).loanFacilitatorTransfer(currentLoanOwner, sendLendTicketTo, loanId); if(amountIncrease > 0){ handleAmountIncreaseBuyoutPayments( loanId, loan.loanAssetContractAddress, amountIncrease, loan.originationFeeRate, currentLoanOwner, accumulatedInterest, previousLoanAmount ); } else { ERC20(loan.loanAssetContractAddress).safeTransferFrom( msg.sender, currentLoanOwner, accumulatedInterest + previousLoanAmount ); } emit BuyoutLender(loanId, msg.sender, currentLoanOwner, accumulatedInterest, previousLoanAmount); } emit Lend(loanId, msg.sender, interestRate, amount, durationSeconds); } /// See {INFTLoanFacilitator-repayAndCloseLoan}. function repayAndCloseLoan(uint256 loanId) external override notClosed(loanId) { Loan storage loan = loanInfo[loanId]; uint256 loanAmount = loan.loanAmount; uint256 interest = _interestOwed( loanAmount, loan.lastAccumulatedTimestamp, loan.perAnnumInterestRate, loan.accumulatedInterest ); address lender = IERC721(lendTicketContract).ownerOf(loanId); loan.closed = true; ERC20(loan.loanAssetContractAddress).safeTransferFrom(msg.sender, lender, interest + loanAmount); IERC721(loan.collateralContractAddress).transferFrom( address(this), IERC721(borrowTicketContract).ownerOf(loanId), loan.collateralTokenId ); emit Repay(loanId, msg.sender, lender, interest, loanAmount); emit Close(loanId); } /// See {INFTLoanFacilitator-seizeCollateral}. function seizeCollateral(uint256 loanId, address sendCollateralTo) external override notClosed(loanId) { require(IERC721(lendTicketContract).ownerOf(loanId) == msg.sender, "lend ticket holder only"); Loan storage loan = loanInfo[loanId]; require(block.timestamp > loan.durationSeconds + loan.lastAccumulatedTimestamp, "payment is not late"); loan.closed = true; IERC721(loan.collateralContractAddress).transferFrom( address(this), sendCollateralTo, loan.collateralTokenId ); emit SeizeCollateral(loanId); emit Close(loanId); } /// @dev If we allowed ERC777 tokens, /// a malicious lender could revert in /// tokensReceived and block buyouts or repayment. /// So we do not support ERC777 tokens. function tokensReceived( address, address, address, uint256, bytes calldata, bytes calldata ) external pure override { revert('ERC777 unsupported'); } // === owner state changing === /** * @notice Sets lendTicketContract to _contract * @dev cannot be set if lendTicketContract is already set */ function setLendTicketContract(address _contract) external onlyOwner { require(lendTicketContract == address(0), 'already set'); lendTicketContract = _contract; } /** * @notice Sets borrowTicketContract to _contract * @dev cannot be set if borrowTicketContract is already set */ function setBorrowTicketContract(address _contract) external onlyOwner { require(borrowTicketContract == address(0), 'already set'); borrowTicketContract = _contract; } /// @notice Transfers `amount` of loan origination fees for `asset` to `to` function withdrawOriginationFees(address asset, uint256 amount, address to) external onlyOwner { ERC20(asset).safeTransfer(to, amount); emit WithdrawOriginationFees(asset, amount, to); } /** * @notice Updates originationFeeRate the facilitator keeps of each loan amount * @dev Cannot be set higher than 5% */ function updateOriginationFeeRate(uint32 _originationFeeRate) external onlyOwner { require(_originationFeeRate <= 5 * (10 ** (INTEREST_RATE_DECIMALS - 2)), "max fee 5%"); originationFeeRate = _originationFeeRate; emit UpdateOriginationFeeRate(_originationFeeRate); } /** * @notice updates the percent improvement required of at least one loan term when buying out lender * a loan that already has a lender. E.g. setting this value to 100 means duration or amount * must be 10% higher or interest rate must be 10% lower. * @dev Cannot be 0. */ function updateRequiredImprovementRate(uint256 _improvementRate) external onlyOwner { require(_improvementRate != 0, '0 improvement rate'); requiredImprovementRate = _improvementRate; emit UpdateRequiredImprovementRate(_improvementRate); } // ==== external view ==== /// See {INFTLoanFacilitator-loanInfoStruct}. function loanInfoStruct(uint256 loanId) external view override returns (Loan memory) { return loanInfo[loanId]; } /// See {INFTLoanFacilitator-totalOwed}. function totalOwed(uint256 loanId) external view override returns (uint256) { Loan storage loan = loanInfo[loanId]; uint256 lastAccumulated = loan.lastAccumulatedTimestamp; if (loan.closed || lastAccumulated == 0) return 0; return loanInfo[loanId].loanAmount + _interestOwed( loan.loanAmount, lastAccumulated, loan.perAnnumInterestRate, loan.accumulatedInterest ); } /// See {INFTLoanFacilitator-interestOwed}. function interestOwed(uint256 loanId) external view override returns (uint256) { Loan storage loan = loanInfo[loanId]; uint256 lastAccumulated = loan.lastAccumulatedTimestamp; if (loan.closed || lastAccumulated == 0) return 0; return _interestOwed( loan.loanAmount, lastAccumulated, loan.perAnnumInterestRate, loan.accumulatedInterest ); } /// See {INFTLoanFacilitator-loanEndSeconds}. function loanEndSeconds(uint256 loanId) external view override returns (uint256) { Loan storage loan = loanInfo[loanId]; uint256 lastAccumulated; require((lastAccumulated = loan.lastAccumulatedTimestamp) != 0, 'loan has no lender'); return loan.durationSeconds + lastAccumulated; } // === internal & private === /// @dev Returns the total interest owed on loan function _interestOwed( uint256 loanAmount, uint256 lastAccumulatedTimestamp, uint256 perAnnumInterestRate, uint256 accumulatedInterest ) internal view returns (uint256) { return loanAmount * (block.timestamp - lastAccumulatedTimestamp) * (perAnnumInterestRate * 1e18 / 365 days) / 1e21 // SCALAR * 1e18 + accumulatedInterest; } /// @dev handles erc20 payments in case of lender buyout /// with increased loan amount function handleAmountIncreaseBuyoutPayments( uint256 loanId, address loanAssetContractAddress, uint256 amountIncrease, uint256 loanOriginationFeeRate, address currentLoanOwner, uint256 accumulatedInterest, uint256 previousLoanAmount ) private { uint256 facilitatorTake = (amountIncrease * loanOriginationFeeRate / SCALAR); ERC20(loanAssetContractAddress).safeTransferFrom(msg.sender, address(this), facilitatorTake); ERC20(loanAssetContractAddress).safeTransferFrom( msg.sender, currentLoanOwner, accumulatedInterest + previousLoanAmount ); ERC20(loanAssetContractAddress).safeTransferFrom( msg.sender, IERC721(borrowTicketContract).ownerOf(loanId), amountIncrease - facilitatorTake ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Gnosis (https://github.com/gnosis/gp-v2-contracts/blob/main/src/contracts/libraries/GPv2SafeERC20.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. library SafeTransferLib { /*/////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool callStatus; assembly { // Transfer the ETH and store if it succeeded or not. callStatus := call(gas(), to, amount, 0, 0, 0, 0) } require(callStatus, "ETH_TRANSFER_FAILED"); } /*/////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool callStatus; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata to memory piece by piece: mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) // Begin with the function selector. mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "from" argument. mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. // Call the token and store if it succeeded or not. // We use 100 because the calldata length is 4 + 32 * 3. callStatus := call(gas(), token, 0, freeMemoryPointer, 100, 0, 0) } require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool callStatus; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata to memory piece by piece: mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // Begin with the function selector. mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. // Call the token and store if it succeeded or not. // We use 68 because the calldata length is 4 + 32 * 2. callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0) } require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool callStatus; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata to memory piece by piece: mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) // Begin with the function selector. mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. // Call the token and store if it succeeded or not. // We use 68 because the calldata length is 4 + 32 * 2. callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0) } require(didLastOptionalReturnCallSucceed(callStatus), "APPROVE_FAILED"); } /*/////////////////////////////////////////////////////////////// INTERNAL HELPER LOGIC //////////////////////////////////////////////////////////////*/ function didLastOptionalReturnCallSucceed(bool callStatus) private pure returns (bool success) { assembly { // Get how many bytes the call returned. let returnDataSize := returndatasize() // If the call reverted: if iszero(callStatus) { // Copy the revert message into memory. returndatacopy(0, 0, returnDataSize) // Revert with the same message. revert(0, returnDataSize) } switch returnDataSize case 32 { // Copy the return data into memory. returndatacopy(0, 0, returnDataSize) // Set success to whether it returned true. success := iszero(iszero(mload(0))) } case 0 { // There was no return data. success := 1 } default { // It returned some malformed input. success := 0 } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a / b + (a % b == 0 ? 0 : 1); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC1820Registry.sol) pragma solidity ^0.8.0; /** * @dev Interface of the global ERC1820 Registry, as defined in the * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register * implementers for interfaces in this registry, as well as query support. * * Implementers may be shared by multiple accounts, and can also implement more * than a single interface for each account. Contracts can implement interfaces * for themselves, but externally-owned accounts (EOA) must delegate this to a * contract. * * {IERC165} interfaces can also be queried via the registry. * * For an in-depth explanation and source code analysis, see the EIP text. */ interface IERC1820Registry { /** * @dev Sets `newManager` as the manager for `account`. A manager of an * account is able to set interface implementers for it. * * By default, each account is its own manager. Passing a value of `0x0` in * `newManager` will reset the manager to this initial state. * * Emits a {ManagerChanged} event. * * Requirements: * * - the caller must be the current manager for `account`. */ function setManager(address account, address newManager) external; /** * @dev Returns the manager for `account`. * * See {setManager}. */ function getManager(address account) external view returns (address); /** * @dev Sets the `implementer` contract as ``account``'s implementer for * `interfaceHash`. * * `account` being the zero address is an alias for the caller's address. * The zero address can also be used in `implementer` to remove an old one. * * See {interfaceHash} to learn how these are created. * * Emits an {InterfaceImplementerSet} event. * * Requirements: * * - the caller must be the current manager for `account`. * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not * end in 28 zeroes). * - `implementer` must implement {IERC1820Implementer} and return true when * queried for support, unless `implementer` is the caller. See * {IERC1820Implementer-canImplementInterfaceForAddress}. */ function setInterfaceImplementer( address account, bytes32 _interfaceHash, address implementer ) external; /** * @dev Returns the implementer of `interfaceHash` for `account`. If no such * implementer is registered, returns the zero address. * * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28 * zeroes), `account` will be queried for support of it. * * `account` being the zero address is an alias for the caller's address. */ function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address); /** * @dev Returns the interface hash for an `interfaceName`, as defined in the * corresponding * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP]. */ function interfaceHash(string calldata interfaceName) external pure returns (bytes32); /** * @notice Updates the cache with whether the contract implements an ERC165 interface or not. * @param account Address of the contract for which to update the cache. * @param interfaceId ERC165 interface for which to update the cache. */ function updateERC165Cache(address account, bytes4 interfaceId) external; /** * @notice Checks whether a contract implements an ERC165 interface or not. * If the result is not cached a direct lookup on the contract address is performed. * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling * {updateERC165Cache} with the contract address. * @param account Address of the contract to check. * @param interfaceId ERC165 interface to check. * @return True if `account` implements `interfaceId`, false otherwise. */ function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool); /** * @notice Checks whether a contract implements an ERC165 interface or not without using nor updating the cache. * @param account Address of the contract to check. * @param interfaceId ERC165 interface to check. * @return True if `account` implements `interfaceId`, false otherwise. */ function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer); event ManagerChanged(address indexed account, address indexed newManager); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC777/IERC777Recipient.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP. * * Accounts can be notified of {IERC777} tokens being sent to them by having a * contract implement this interface (contract holders can be their own * implementer) and registering it on the * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. * * See {IERC1820Registry} and {ERC1820Implementer}. */ interface IERC777Recipient { /** * @dev Called by an {IERC777} token contract whenever tokens are being * moved or created into a registered account (`to`). The type of operation * is conveyed by `from` being the zero address or not. * * This call occurs _after_ the token contract's state is updated, so * {IERC777-balanceOf}, etc., can be used to query the post-operation state. * * This function may revert to prevent the operation from being executed. */ function tokensReceived( address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.12; interface INFTLoanFacilitator { /// @notice See loanInfo struct Loan { bool closed; uint16 perAnnumInterestRate; uint32 durationSeconds; uint40 lastAccumulatedTimestamp; address collateralContractAddress; bool allowLoanAmountIncrease; uint88 originationFeeRate; address loanAssetContractAddress; uint128 accumulatedInterest; uint128 loanAmount; uint256 collateralTokenId; } /** * @notice The magnitude of SCALAR * @dev 10^INTEREST_RATE_DECIMALS = 1 = 100% */ function INTEREST_RATE_DECIMALS() external view returns (uint8); /** * @notice The SCALAR for all percentages in the loan facilitator contract * @dev Any interest rate passed to a function should already been multiplied by SCALAR */ function SCALAR() external view returns (uint256); /** * @notice The percent of the loan amount that the facilitator will take as a fee, scaled by SCALAR * @dev Starts set to 1%. Can only be set to 0 - 5%. */ function originationFeeRate() external view returns (uint256); /** * @notice The lend ticket contract associated with this loan facilitator * @dev Once set, cannot be modified */ function lendTicketContract() external view returns (address); /** * @notice The borrow ticket contract associated with this loan facilitator * @dev Once set, cannot be modified */ function borrowTicketContract() external view returns (address); /** * @notice The percent improvement required of at least one loan term when buying out current lender * a loan that already has a lender, scaled by SCALAR. * E.g. setting this value to 100 (10%) means, when replacing a lender, the new loan terms must have * at least 10% greater duration or loan amount or at least 10% lower interest rate. * @dev Starts at 100 = 10%. Only owner can set. Cannot be set to 0. */ function requiredImprovementRate() external view returns (uint256); /** * @notice Emitted when the loan is created * @param id The id of the new loan, matches the token id of the borrow ticket minted in the same transaction * @param minter msg.sender * @param collateralTokenId The token id of the collateral NFT * @param collateralContract The contract address of the collateral NFT * @param maxInterestRate The max per anum interest rate, scaled by SCALAR * @param loanAssetContract The contract address of the loan asset * @param minLoanAmount mimimum loan amount * @param minDurationSeconds minimum loan duration in seconds */ event CreateLoan( uint256 indexed id, address indexed minter, uint256 collateralTokenId, address collateralContract, uint256 maxInterestRate, address loanAssetContract, bool allowLoanAmountIncrease, uint256 minLoanAmount, uint256 minDurationSeconds ); /** * @notice Emitted when ticket is closed * @param id The id of the ticket which has been closed */ event Close(uint256 indexed id); /** * @notice Emitted when the loan is lent to * @param id The id of the loan which is being lent to * @param lender msg.sender * @param interestRate The per anum interest rate, scaled by SCALAR, for the loan * @param loanAmount The loan amount * @param durationSeconds The loan duration in seconds */ event Lend( uint256 indexed id, address indexed lender, uint256 interestRate, uint256 loanAmount, uint256 durationSeconds ); /** * @notice Emitted when a lender is being bought out: * the current loan ticket holder is being replaced by a new lender offering better terms * @param lender msg.sender * @param replacedLoanOwner The current loan ticket holder * @param interestEarned The amount of interest the loan has accrued from first lender to this buyout * @param replacedAmount The loan amount prior to buyout */ event BuyoutLender( uint256 indexed id, address indexed lender, address indexed replacedLoanOwner, uint256 interestEarned, uint256 replacedAmount ); /** * @notice Emitted when loan is repaid * @param id The loan id * @param repayer msg.sender * @param loanOwner The current holder of the lend ticket for this loan, token id matching the loan id * @param interestEarned The total interest accumulated on the loan * @param loanAmount The loan amount */ event Repay( uint256 indexed id, address indexed repayer, address indexed loanOwner, uint256 interestEarned, uint256 loanAmount ); /** * @notice Emitted when loan NFT collateral is seized * @param id The ticket id */ event SeizeCollateral(uint256 indexed id); /** * @notice Emitted when origination fees are withdrawn * @dev only owner can call * @param asset the ERC20 asset withdrawn * @param amount the amount withdrawn * @param to the address the withdrawn amount was sent to */ event WithdrawOriginationFees(address asset, uint256 amount, address to); /** * @notice Emitted when originationFeeRate is updated * @dev only owner can call, value is scaled by SCALAR, 100% = SCALAR * @param feeRate the new origination fee rate */ event UpdateOriginationFeeRate(uint32 feeRate); /** * @notice Emitted when requiredImprovementRate is updated * @dev only owner can call, value is scaled by SCALAR, 100% = SCALAR * @param improvementRate the new required improvementRate */ event UpdateRequiredImprovementRate(uint256 improvementRate); /** * @notice (1) transfers the collateral NFT to the loan facilitator contract * (2) creates the loan, populating loanInfo in the facilitator contract, * and (3) mints a Borrow Ticket to mintBorrowTicketTo * @dev loan duration or loan amount cannot be 0, * this is done to protect borrowers from accidentally passing a default value * and also because it creates odd lending and buyout behavior: possible to lend * for 0 value or 0 duration, and possible to buyout with no improvement because, for example * previousDurationSeconds + (previousDurationSeconds * requiredImprovementRate / SCALAR) <= durationSeconds * evaluates to true if previousDurationSeconds is 0 and durationSeconds is 0. * loanAssetContractAddress cannot be address(0), we check this because Solmate SafeTransferLib * does not revert with address(0) and this could cause odd behavior. * collateralContractAddress cannot be address(borrowTicket) or address(lendTicket). * @param collateralTokenId The token id of the collateral NFT * @param collateralContractAddress The contract address of the collateral NFT * @param maxPerAnnumInterest The maximum per anum interest rate for this loan, scaled by SCALAR * @param allowLoanAmountIncrease Whether the borrower is open to lenders offerring greater than minLoanAmount * @param minLoanAmount The minimum acceptable loan amount for this loan * @param loanAssetContractAddress The address of the loan asset * @param minDurationSeconds The minimum duration for this loan * @param mintBorrowTicketTo An address to mint the Borrow Ticket corresponding to this loan to * @return id of the created loan */ function createLoan( uint256 collateralTokenId, address collateralContractAddress, uint16 maxPerAnnumInterest, bool allowLoanAmountIncrease, uint128 minLoanAmount, address loanAssetContractAddress, uint32 minDurationSeconds, address mintBorrowTicketTo ) external returns (uint256 id); /** * @notice Closes the loan, sends the NFT collateral to sendCollateralTo * @dev Can only be called by the holder of the Borrow Ticket with tokenId * matching the loanId. Can only be called if loan has no lender, * i.e. lastAccumulatedInterestTimestamp = 0 * @param loanId The loan id * @param sendCollateralTo The address to send the collateral NFT to */ function closeLoan(uint256 loanId, address sendCollateralTo) external; /** * @notice Lends, meeting or beating the proposed loan terms, * transferring `amount` of the loan asset * to the facilitator contract. If the loan has not yet been lent to, * a Lend Ticket is minted to `sendLendTicketTo`. If the loan has already been * lent to, then this is a buyout, and the Lend Ticket will be transferred * from the current holder to `sendLendTicketTo`. Also in the case of a buyout, interestOwed() * is transferred from the caller to the facilitator contract, in addition to `amount`, and * totalOwed() is paid to the current Lend Ticket holder. * @dev Loan terms must meet or beat loan terms. If a buyout, at least one loan term * must be improved by at least 10%. E.g. 10% longer duration, 10% lower interest, * 10% higher amount * @param loanId The loan id * @param interestRate The per anum interest rate, scaled by SCALAR * @param amount The loan amount * @param durationSeconds The loan duration in seconds * @param sendLendTicketTo The address to send the Lend Ticket to */ function lend( uint256 loanId, uint16 interestRate, uint128 amount, uint32 durationSeconds, address sendLendTicketTo ) external; /** * @notice repays and closes the loan, transferring totalOwed() to the current Lend Ticket holder * and transferring the collateral NFT to the Borrow Ticket holder. * @param loanId The loan id */ function repayAndCloseLoan(uint256 loanId) external; /** * @notice Transfers the collateral NFT to `sendCollateralTo` and closes the loan. * @dev Can only be called by Lend Ticket holder. Can only be called * if block.timestamp > loanEndSeconds() * @param loanId The loan id * @param sendCollateralTo The address to send the collateral NFT to */ function seizeCollateral(uint256 loanId, address sendCollateralTo) external; /** * @notice returns the info for this loan * @param loanId The id of the loan * @return closed Whether or not the ticket is closed * @return perAnnumInterestRate The per anum interest rate, scaled by SCALAR * @return durationSeconds The loan duration in seconds * @return lastAccumulatedTimestamp The timestamp (in seconds) when interest was last accumulated, * i.e. the timestamp of the most recent lend * @return collateralContractAddress The contract address of the NFT collateral * @return allowLoanAmountIncrease * @return originationFeeRate * @return loanAssetContractAddress The contract address of the loan asset. * @return accumulatedInterest The amount of interest accumulated on the loan prior to the current lender * @return loanAmount The loan amount * @return collateralTokenId The token ID of the NFT collateral */ function loanInfo(uint256 loanId) external view returns ( bool closed, uint16 perAnnumInterestRate, uint32 durationSeconds, uint40 lastAccumulatedTimestamp, address collateralContractAddress, bool allowLoanAmountIncrease, uint88 originationFeeRate, address loanAssetContractAddress, uint128 accumulatedInterest, uint128 loanAmount, uint256 collateralTokenId ); /** * @notice returns the info for this loan * @dev this is a convenience method for other contracts that would prefer to have the * Loan object not decomposed. * @param loanId The id of the loan * @return Loan struct corresponding to loanId */ function loanInfoStruct(uint256 loanId) external view returns (Loan memory); /** * @notice returns the total amount owed for the loan, i.e. principal + interest * @param loanId The loan id * @return amount required to repay and close the loan corresponding to loanId */ function totalOwed(uint256 loanId) view external returns (uint256); /** * @notice returns the interest owed on the loan, in loan asset units * @param loanId The loan id * @return amount of interest owed on loan corresonding to loanId */ function interestOwed(uint256 loanId) view external returns (uint256); /** * @notice returns the unix timestamp (seconds) of the loan end * @param loanId The loan id * @return timestamp at which loan payment is due, after which lend ticket holder * can seize collateral */ function loanEndSeconds(uint256 loanId) view external returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.12; interface IERC721Mintable { /** * @notice mints an ERC721 token of tokenId to the to address * @dev only callable by nft loan facilitator * @param to The address to send the token to * @param tokenId The id of the token to mint */ function mint(address to, uint256 tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.12; interface ILendTicket { /** * @notice Transfers a lend ticket * @dev can only be called by nft loan facilitator * @param from The current holder of the lend ticket * @param to Address to send the lend ticket to * @param loanId The lend ticket token id, which is also the loan id in the facilitator contract */ function loanFacilitatorTransfer(address from, address to, uint256 loanId) external; }
// 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); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*/////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*/////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*/////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*/////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*/////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*/////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*/////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*/////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (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; } }
{ "optimizer": { "enabled": true, "runs": 100000, "details": { "yul": true, "yulDetails": { "stackAllocation": true, "optimizerSteps": "dhfoDgvulfnTUtnIf" } } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"indexed":true,"internalType":"address","name":"replacedLoanOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"interestEarned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"replacedAmount","type":"uint256"}],"name":"BuyoutLender","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Close","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralTokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"collateralContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxInterestRate","type":"uint256"},{"indexed":false,"internalType":"address","name":"loanAssetContract","type":"address"},{"indexed":false,"internalType":"bool","name":"allowLoanAmountIncrease","type":"bool"},{"indexed":false,"internalType":"uint256","name":"minLoanAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minDurationSeconds","type":"uint256"}],"name":"CreateLoan","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"interestRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loanAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"durationSeconds","type":"uint256"}],"name":"Lend","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"repayer","type":"address"},{"indexed":true,"internalType":"address","name":"loanOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"interestEarned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loanAmount","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"SeizeCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"feeRate","type":"uint32"}],"name":"UpdateOriginationFeeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"improvementRate","type":"uint256"}],"name":"UpdateRequiredImprovementRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"}],"name":"WithdrawOriginationFees","type":"event"},{"inputs":[],"name":"INTEREST_RATE_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SCALAR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowTicketContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"},{"internalType":"address","name":"sendCollateralTo","type":"address"}],"name":"closeLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateralTokenId","type":"uint256"},{"internalType":"address","name":"collateralContractAddress","type":"address"},{"internalType":"uint16","name":"maxPerAnnumInterest","type":"uint16"},{"internalType":"bool","name":"allowLoanAmountIncrease","type":"bool"},{"internalType":"uint128","name":"minLoanAmount","type":"uint128"},{"internalType":"address","name":"loanAssetContractAddress","type":"address"},{"internalType":"uint32","name":"minDurationSeconds","type":"uint32"},{"internalType":"address","name":"mintBorrowTicketTo","type":"address"}],"name":"createLoan","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"interestOwed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"},{"internalType":"uint16","name":"interestRate","type":"uint16"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint32","name":"durationSeconds","type":"uint32"},{"internalType":"address","name":"sendLendTicketTo","type":"address"}],"name":"lend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lendTicketContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"loanEndSeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"loanInfo","outputs":[{"internalType":"bool","name":"closed","type":"bool"},{"internalType":"uint16","name":"perAnnumInterestRate","type":"uint16"},{"internalType":"uint32","name":"durationSeconds","type":"uint32"},{"internalType":"uint40","name":"lastAccumulatedTimestamp","type":"uint40"},{"internalType":"address","name":"collateralContractAddress","type":"address"},{"internalType":"bool","name":"allowLoanAmountIncrease","type":"bool"},{"internalType":"uint88","name":"originationFeeRate","type":"uint88"},{"internalType":"address","name":"loanAssetContractAddress","type":"address"},{"internalType":"uint128","name":"accumulatedInterest","type":"uint128"},{"internalType":"uint128","name":"loanAmount","type":"uint128"},{"internalType":"uint256","name":"collateralTokenId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"loanInfoStruct","outputs":[{"components":[{"internalType":"bool","name":"closed","type":"bool"},{"internalType":"uint16","name":"perAnnumInterestRate","type":"uint16"},{"internalType":"uint32","name":"durationSeconds","type":"uint32"},{"internalType":"uint40","name":"lastAccumulatedTimestamp","type":"uint40"},{"internalType":"address","name":"collateralContractAddress","type":"address"},{"internalType":"bool","name":"allowLoanAmountIncrease","type":"bool"},{"internalType":"uint88","name":"originationFeeRate","type":"uint88"},{"internalType":"address","name":"loanAssetContractAddress","type":"address"},{"internalType":"uint128","name":"accumulatedInterest","type":"uint128"},{"internalType":"uint128","name":"loanAmount","type":"uint128"},{"internalType":"uint256","name":"collateralTokenId","type":"uint256"}],"internalType":"struct INFTLoanFacilitator.Loan","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"originationFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"repayAndCloseLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requiredImprovementRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"},{"internalType":"address","name":"sendCollateralTo","type":"address"}],"name":"seizeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"}],"name":"setBorrowTicketContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"}],"name":"setLendTicketContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"tokensReceived","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"loanId","type":"uint256"}],"name":"totalOwed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_originationFeeRate","type":"uint32"}],"name":"updateOriginationFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_improvementRate","type":"uint256"}],"name":"updateRequiredImprovementRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawOriginationFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040526200001260026003620001f8565b6200001f90600a6200034a565b60015560016003620000329190620001f8565b6200003f90600a6200034a565b60025560016006553480156200005457600080fd5b5060405162003e8538038062003e85833981016040819052620000779162000398565b620000823362000125565b6200008d8162000175565b6040516329965a1d60e01b8152731820a4b7618bde71dce8cdc73aab6c95905fad24906329965a1d90620000ea9030907fb281fc8c12954d22544db45de3159a39272895b169a852b314f9cc762e44c53b908290600401620003dd565b600060405180830381600087803b1580156200010557600080fd5b505af11580156200011a573d6000803e3d6000fd5b505050505062000491565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000546001600160a01b03163314620001ab5760405162461bcd60e51b8152600401620001a2906200040b565b60405180910390fd5b6001600160a01b038116620001d45760405162461bcd60e51b8152600401620001a29062000446565b620001df8162000125565b50565b634e487b7160e01b600052601160045260246000fd5b60ff9182169116600082821015620002145762000214620001e2565b500390565b80825b60018511156200025f578086048111156200023b576200023b620001e2565b60018516156200024a57908102905b8002620002578560011c90565b94506200021c565b94509492505050565b600082620002795750600162000343565b81620002885750600062000343565b8160018114620002a15760028114620002ac57620002e0565b600191505062000343565b60ff841115620002c057620002c0620001e2565b8360020a915084821115620002d957620002d9620001e2565b5062000343565b5060208310610133831016604e8410600b841016171562000318575081810a83811115620003125762000312620001e2565b62000343565b62000327848484600162000219565b92509050818404811115620003405762000340620001e2565b81025b9392505050565b60ff82169150600062000343600019848462000268565b60006001600160a01b0382165b92915050565b6200037f8162000361565b8114620001df57600080fd5b80516200036e8162000374565b600060208284031215620003af57620003af600080fd5b6000620003bd84846200038b565b949350505050565b620003d08162000361565b82525050565b80620003d0565b60608101620003ed8286620003c5565b620003fc6020830185620003d6565b620003bd6040830184620003c5565b60208082528181019081527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726040830152606082016200036e565b602080825281016200036e81602681527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160208201526564647265737360d01b604082015260600190565b6139e480620004a16000396000f3fe608060405234801561001057600080fd5b50600436106101a25760003560e01c80636bf301a4116100ee5780638da5cb5b11610097578063b6ecac5711610071578063b6ecac5714610432578063b8efff83146105b0578063e926e9af146105c3578063f2fde38b146105d657600080fd5b80638da5cb5b146103ee578063a27158d71461040c578063ac9cf4db1461041f57600080fd5b80637af26c1f116100c85780637af26c1f146102ce5780637e8400b2146102ee5780638349d6be1461030157600080fd5b80636bf301a4146102ab578063715018a6146102b35780637a0815c0146102bb57600080fd5b80633f58184811610150578063654ea0981161012a578063654ea0981461025657806366234ffa1461026957806367cec5a31461027e57600080fd5b80633f5818481461021d5780635ecd217314610230578063639542531461024357600080fd5b8063311f13c611610181578063311f13c6146101f857806337bb105c146102015780633b8174961461021457600080fd5b806223de29146101a757806310780bed146101bc578063300ed99b146101e5575b600080fd5b6101ba6101b536600461295d565b6105e9565b005b6101cf6101ca366004612a27565b610624565b6040516101dc9190612a50565b60405180910390f35b6101ba6101f3366004612a75565b6106b1565b6101cf60025481565b6101ba61020f366004612a96565b6107a8565b6101cf60015481565b6101ba61022b366004612a96565b610890565b6101cf61023e366004612a27565b610978565b6101cf610251366004612b02565b6109eb565b6101ba610264366004612bb5565b610e21565b610271600381565b6040516101dc9190612c0e565b60035461029e9073ffffffffffffffffffffffffffffffffffffffff1681565b6040516101dc9190612c25565b6101cf610ed3565b6101ba610ee2565b6101ba6102c9366004612a27565b610f3f565b60045461029e9073ffffffffffffffffffffffffffffffffffffffff1681565b6101ba6102fc366004612c33565b610ffc565b6103d761030f366004612a27565b600560205260009081526040902080546001820154600283015460039093015460ff8084169461010080860461ffff16956301000000810463ffffffff1695670100000000000000820464ffffffffff16956c010000000000000000000000009283900473ffffffffffffffffffffffffffffffffffffffff908116968316959483046affffffffffffffffffffff169493909204909116916fffffffffffffffffffffffffffffffff8082169270010000000000000000000000000000000090920416908b565b6040516101dc9b9a99989796959493929190612cc6565b60005473ffffffffffffffffffffffffffffffffffffffff1661029e565b6101ba61041a366004612a27565b61127d565b6101ba61042d366004612c33565b6115e2565b6105a3610440366004612a27565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915250600090815260056020908152604091829020825161016081018452815460ff8082161515835261010080830461ffff16958401959095526301000000820463ffffffff1695830195909552670100000000000000810464ffffffffff1660608301526c010000000000000000000000009081900473ffffffffffffffffffffffffffffffffffffffff90811660808401526001840154958616151560a08401528486046affffffffffffffffffffff1660c0840152940490931660e084015260028101546fffffffffffffffffffffffffffffffff8082169385019390935270010000000000000000000000000000000090049091166101208301526003015461014082015290565b6040516101dc9190612e3f565b6101ba6105be366004612e4e565b6118ac565b6101cf6105d1366004612a27565b612373565b6101ba6105e4366004612a96565b61243a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612efa565b60405180910390fd5b6000818152600560205260408120805464ffffffffff6701000000000000008204169060ff1680610653575080155b15610662575060009392505050565b600282015482546106a99170010000000000000000000000000000000081046fffffffffffffffffffffffffffffffff90811692859261010090910461ffff1691166124e4565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610702576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b61070e60026003612f79565b61071990600a6130ac565b6107249060056130df565b8163ffffffff161115610763576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061314e565b63ffffffff81166001556040517f5318780da42901eb551b3beab1953fa2673bf9592c023ed47f8929cfd705a4269061079d90839061315e565b60405180910390a150565b60005473ffffffffffffffffffffffffffffffffffffffff1633146107f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b60045473ffffffffffffffffffffffffffffffffffffffff1615610849576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061319e565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff1633146108e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b60035473ffffffffffffffffffffffffffffffffffffffff1615610931576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061319e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008181526005602052604081208054670100000000000000900464ffffffffff16806109d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906131e0565b81546106a99082906301000000900463ffffffff166131f0565b600063ffffffff8316610a2a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061323a565b6fffffffffffffffffffffffffffffffff8516610a73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061327c565b60035473ffffffffffffffffffffffffffffffffffffffff89811691161415610ac8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906132be565b60045473ffffffffffffffffffffffffffffffffffffffff89811691161415610b1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613300565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8916906323b872dd90610b7390339030908e90600401613310565b600060405180830381600087803b158015610b8d57600080fd5b505af1158015610ba1573d6000803e3d6000fd5b50505050600660008154809291906001019190505590506000600560008381526020019081526020016000209050868160010160006101000a81548160ff0219169083151502179055506001548160010160016101000a8154816affffffffffffffffffffff02191690836affffffffffffffffffffff1602179055508481600101600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550858160020160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508981600301819055508881600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550878160000160016101000a81548161ffff021916908361ffff160217905550838160000160036101000a81548163ffffffff021916908363ffffffff160217905550600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1984846040518363ffffffff1660e01b8152600401610d87929190613338565b600060405180830381600087803b158015610da157600080fd5b505af1158015610db5573d6000803e3d6000fd5b505050503373ffffffffffffffffffffffffffffffffffffffff16827f7c227a124a9e9096681f1f99e084a9a4223cf0b62d37c03fe22fdb55b8ad2cdb8c8c8c8a8d8d8c604051610e0c97969594939291906133b1565b60405180910390a35098975050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610e72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b610e9373ffffffffffffffffffffffffffffffffffffffff8416828461254d565b7fa8790deb319345e298343f10ed7d6a75b74909da42818501958de9e08f73869e838383604051610ec693929190613419565b60405180910390a1505050565b610edf6003600a6130ac565b81565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b610f3d60006125ea565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b80610fc7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613473565b60028190556040517f955a84aca3e56ae377e1e799c430fec3709dda2c19da07f13e6c1a33df3cbf229061079d908390612a50565b600082815260056020526040902054829060ff1615611047576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906134b5565b600480546040517f6352211e000000000000000000000000000000000000000000000000000000008152339273ffffffffffffffffffffffffffffffffffffffff90921691636352211e9161109e91889101612a50565b602060405180830381865afa1580156110bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110df91906134d0565b73ffffffffffffffffffffffffffffffffffffffff161461112c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613523565b60008381526005602052604090208054670100000000000000900464ffffffffff1615611185576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613565565b805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161780825560038201546040517f23b872dd0000000000000000000000000000000000000000000000000000000081526c0100000000000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16916323b872dd9161121a9130918891600401613310565b600060405180830381600087803b15801561123457600080fd5b505af1158015611248573d6000803e3d6000fd5b50506040518692507fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf9150600090a250505050565b600081815260056020526040902054819060ff16156112c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906134b5565b600082815260056020526040812060028101548154919270010000000000000000000000000000000082046fffffffffffffffffffffffffffffffff908116939192611334928592670100000000000000820464ffffffffff169261010090920461ffff1691166124e4565b6003546040517f6352211e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690636352211e90611390908990600401612a50565b602060405180830381865afa1580156113ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d191906134d0565b84547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001178555905061143e338261140b86866131f0565b60018801546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1692919061265f565b8354600480546040517f6352211e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009094048416936323b872dd93309390911691636352211e916114b1918d9101612a50565b602060405180830381865afa1580156114ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f291906134d0565b87600301546040518463ffffffff1660e01b815260040161151593929190613310565b600060405180830381600087803b15801561152f57600080fd5b505af1158015611543573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16877f9181b2981704b7cf4448130f29cb5da1f41e0418d000e7f8880000b09bcbea4585876040516115a7929190613575565b60405180910390a460405186907fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf90600090a2505050505050565b600082815260056020526040902054829060ff161561162d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906134b5565b6003546040517f6352211e000000000000000000000000000000000000000000000000000000008152339173ffffffffffffffffffffffffffffffffffffffff1690636352211e90611683908790600401612a50565b602060405180830381865afa1580156116a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c491906134d0565b73ffffffffffffffffffffffffffffffffffffffff1614611711576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906135b5565b6000838152600560205260409020805461174a90670100000000000000810464ffffffffff16906301000000900463ffffffff166135c5565b64ffffffffff164211611789576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613624565b805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161780825560038201546040517f23b872dd0000000000000000000000000000000000000000000000000000000081526c0100000000000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16916323b872dd9161181e9130918891600401613310565b600060405180830381600087803b15801561183857600080fd5b505af115801561184c573d6000803e3d6000fd5b50506040518692507f19f0d220035b967365e70d19ca7093af2e75a9741c08ef27c5017d6f463febd99150600090a260405184907fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf90600090a250505050565b600085815260056020526040902054859060ff16156118f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906134b5565b60008681526005602052604090208054670100000000000000900464ffffffffff16611d945760018101546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16803b611980576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613666565b815461ffff610100909104811690881611156119c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906136a8565b815463ffffffff630100000090910481169086161015611a14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906136ea565b600182015460ff1615611a8e5760028201546fffffffffffffffffffffffffffffffff70010000000000000000000000000000000090910481169087161015611a89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061372c565b611af4565b60028201546fffffffffffffffffffffffffffffffff8781167001000000000000000000000000000000009092041614611af4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061376e565b81547fffffffffffffffffffffffffffffffffffffffff0000000000ffffffff0000ff1661010061ffff8916027fffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffff16176701000000000000004264ffffffffff1602177fffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffff16630100000063ffffffff8716021782556002820180546fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000918916919091021790556000611bcd6003600a6130ac565b6001840154611c009061010090046affffffffffffffffffffff166fffffffffffffffffffffffffffffffff8a166130df565b611c0a91906137ad565b9050611c2e73ffffffffffffffffffffffffffffffffffffffff831633308461265f565b600480546040517f6352211e000000000000000000000000000000000000000000000000000000008152611d0392339273ffffffffffffffffffffffffffffffffffffffff1691636352211e91611c87918f9101612a50565b602060405180830381865afa158015611ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc891906134d0565b611ce4846fffffffffffffffffffffffffffffffff8c166137c1565b73ffffffffffffffffffffffffffffffffffffffff861692919061265f565b6003546040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906340c10f1990611d5b9088908d90600401613338565b600060405180830381600087803b158015611d7557600080fd5b505af1158015611d89573d6000803e3d6000fd5b505050505050612317565b60028101546fffffffffffffffffffffffffffffffff700100000000000000000000000000000000909104811690600090611dd290839089166137c1565b600184015490915060ff16611e19578015611e19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906137f9565b825460009061ffff610100820481169163ffffffff630100000090910416908b16821015611e73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906136a8565b808963ffffffff161015611eb3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906136ea565b83611ed660025487611ec591906130df565b611ed16003600a6130ac565b612719565b111580611f0357508863ffffffff16611ef660025483611ec591906130df565b611f0090836131f0565b11155b80611f3657508115801590611f3657508a61ffff16611f2960025484611ec591906130df565b611f3390846137c1565b10155b611f6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061383b565b85546002870154611fa691879167010000000000000090910464ffffffffff169085906fffffffffffffffffffffffffffffffff166124e4565b925050507001000000000000000000000000000000008110611ff4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061387d565b83547fffffffffffffffffffffffffffffffffffffffff0000000000ffffffff0000ff1661010061ffff8b16027fffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffff16176701000000000000004264ffffffffff1602177fffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffff16630100000063ffffffff8916021784557fffffffffffffffffffffffffffffffff000000000000000000000000000000007001000000000000000000000000000000006fffffffffffffffffffffffffffffffff8a811691909102919091169082161760028501556003546040517f6352211e00000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff1690636352211e90612138908e90600401612a50565b602060405180830381865afa158015612155573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217991906134d0565b9050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a236897a82898e6040518463ffffffff1660e01b81526004016121da93929190613310565b600060405180830381600087803b1580156121f457600080fd5b505af1158015612208573d6000803e3d6000fd5b505050506000831115612268576001850154612263908c906c01000000000000000000000000810473ffffffffffffffffffffffffffffffffffffffff1690869061010090046affffffffffffffffffffff1685878a612754565b6122aa565b6122aa338261227787866131f0565b60018901546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1692919061265f565b8073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff168c7f060231091bad585835f99d8cadcc3ff7fa49943bd1b52cde44a74762102aba44858860405161230a929190613575565b60405180910390a4505050505b3373ffffffffffffffffffffffffffffffffffffffff16877f5f20982d2196b477a67cf9eec22865b0093715235a896e9202a55d2acb85dba38888886040516123629392919061388d565b60405180910390a350505050505050565b6000818152600560205260408120805464ffffffffff6701000000000000008204169060ff16806123a2575080155b156123b1575060009392505050565b600282015482546123f89170010000000000000000000000000000000081046fffffffffffffffffffffffffffffffff90811692859261010090910461ffff1691166124e4565b6000858152600560205260409020600201546106a9919070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166131f0565b60005473ffffffffffffffffffffffffffffffffffffffff16331461248b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b73ffffffffffffffffffffffffffffffffffffffff81166124d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906138b5565b6124e1816125ea565b50565b600081683635c9adc5dea000006301e1338061250886670de0b6b3a76400006130df565b61251291906137ad565b61251c87426137c1565b61252690896130df565b61253091906130df565b61253a91906137ad565b61254491906131f0565b95945050505050565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201528260248201526000806044836000895af19150506125ae81612876565b6125e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613948565b50505050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff8416602482015282604482015260008060648360008a5af19150506126dc81612876565b612712576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061398a565b5050505050565b6000612725828461399a565b15612731576001612734565b60005b60ff1661274183856137ad565b61274b91906131f0565b90505b92915050565b60006127626003600a6130ac565b61276c86886130df565b61277691906137ad565b905061279a73ffffffffffffffffffffffffffffffffffffffff881633308461265f565b6127c833856127a985876131f0565b73ffffffffffffffffffffffffffffffffffffffff8b1692919061265f565b600480546040517f6352211e00000000000000000000000000000000000000000000000000000000815261286c92339273ffffffffffffffffffffffffffffffffffffffff1691636352211e91612821918e9101612a50565b602060405180830381865afa15801561283e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286291906134d0565b6127a9848a6137c1565b5050505050505050565b60003d8261288857806000803e806000fd5b80602081146128a05780156128b157600092506128b6565b816000803e600051151592506128b6565b600192505b5050919050565b600073ffffffffffffffffffffffffffffffffffffffff821661274e565b6128e4816128bd565b81146124e157600080fd5b803561274e816128db565b806128e4565b803561274e816128fa565b60008083601f84011261292057612920600080fd5b50813567ffffffffffffffff81111561293b5761293b600080fd5b60208301915083600182028301111561295657612956600080fd5b9250929050565b60008060008060008060008060c0898b03121561297c5761297c600080fd5b60006129888b8b6128ef565b98505060206129998b828c016128ef565b97505060406129aa8b828c016128ef565b96505060606129bb8b828c01612900565b955050608089013567ffffffffffffffff8111156129db576129db600080fd5b6129e78b828c0161290b565b945094505060a089013567ffffffffffffffff811115612a0957612a09600080fd5b612a158b828c0161290b565b92509250509295985092959890939650565b600060208284031215612a3c57612a3c600080fd5b60006106a98484612900565b805b82525050565b6020810161274e8284612a48565b63ffffffff81166128e4565b803561274e81612a5e565b600060208284031215612a8a57612a8a600080fd5b60006106a98484612a6a565b600060208284031215612aab57612aab600080fd5b60006106a984846128ef565b61ffff81166128e4565b803561274e81612ab7565b8015156128e4565b803561274e81612acc565b6fffffffffffffffffffffffffffffffff81166128e4565b803561274e81612adf565b600080600080600080600080610100898b031215612b2257612b22600080fd5b6000612b2e8b8b612900565b9850506020612b3f8b828c016128ef565b9750506040612b508b828c01612ac1565b9650506060612b618b828c01612ad4565b9550506080612b728b828c01612af7565b94505060a0612b838b828c016128ef565b93505060c0612b948b828c01612a6a565b92505060e0612ba58b828c016128ef565b9150509295985092959890939650565b600080600060608486031215612bcd57612bcd600080fd5b6000612bd986866128ef565b9350506020612bea86828701612900565b9250506040612bfb868287016128ef565b9150509250925092565b60ff8116612a4a565b6020810161274e8284612c05565b612a4a816128bd565b6020810161274e8284612c1c565b60008060408385031215612c4957612c49600080fd5b6000612c558585612900565b9250506020612c66858286016128ef565b9150509250929050565b801515612a4a565b61ffff8116612a4a565b63ffffffff8116612a4a565b64ffffffffff8116612a4a565b6affffffffffffffffffffff8116612a4a565b6fffffffffffffffffffffffffffffffff8116612a4a565b6101608101612cd5828e612c70565b612ce2602083018d612c78565b612cef604083018c612c82565b612cfc606083018b612c8e565b612d09608083018a612c1c565b612d1660a0830189612c70565b612d2360c0830188612c9b565b612d3060e0830187612c1c565b612d3e610100830186612cae565b612d4c610120830185612cae565b612d5a610140830184612a48565b9c9b505050505050505050505050565b8051612d768382612c70565b506020810151612d896020840182612c78565b506040810151612d9c6040840182612c82565b506060810151612daf6060840182612c8e565b506080810151612dc26080840182612c1c565b5060a0810151612dd560a0840182612c70565b5060c0810151612de860c0840182612c9b565b5060e0810151612dfb60e0840182612c1c565b50610100810151612e10610100840182612cae565b50610120810151612e25610120840182612cae565b50610140810151612e3a610140840182612a48565b505050565b610160810161274e8284612d6a565b600080600080600060a08688031215612e6957612e69600080fd5b6000612e758888612900565b9550506020612e8688828901612ac1565b9450506040612e9788828901612af7565b9350506060612ea888828901612a6a565b9250506080612eb9888289016128ef565b9150509295509295909350565b60128152602081017f45524337373720756e737570706f727465640000000000000000000000000000815290505b60200190565b6020808252810161274e81612ec6565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65729101908152612ef4565b6020808252810161274e81612f0a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff9081169082165b9150600082821015612f9657612f96612f4a565b500390565b80825b6001851115612fda57808604811115612fb957612fb9612f4a565b6001851615612fc757908102905b8002612fd38560011c90565b9450612f9e565b94509492505050565b600082612ff2575060016130a5565b81612fff575060006130a5565b8160018114613015576002811461301f5761304c565b60019150506130a5565b60ff84111561303057613030612f4a565b8360020a91508482111561304657613046612f4a565b506130a5565b5060208310610133831016604e8410600b841016171561307f575081810a8381111561307a5761307a612f4a565b6130a5565b61308c8484846001612f9b565b925090508184048111156130a2576130a2612f4a565b81025b9392505050565b60ff82169150600061274b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484612fe3565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561311757613117612f4a565b500290565b600a8152602081017f6d6178206665652035250000000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e8161311c565b6020810161274e8284612c82565b600b8152602081017f616c72656164792073657400000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e8161316c565b60128152602081017f6c6f616e20686173206e6f206c656e646572000000000000000000000000000081529050612ef4565b6020808252810161274e816131ae565b6000821982111561320357613203612f4a565b500190565b600a8152602081017f30206475726174696f6e0000000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613208565b600d8152602081017f30206c6f616e20616d6f756e740000000000000000000000000000000000000081529050612ef4565b6020808252810161274e8161324a565b60168152602081017f6c656e64207469636b657420636f6c6c61746572616c0000000000000000000081529050612ef4565b6020808252810161274e8161328c565b60188152602081017f626f72726f77207469636b657420636f6c6c61746572616c000000000000000081529050612ef4565b6020808252810161274e816132ce565b6060810161331e8286612c1c565b61332b6020830185612c1c565b6106a96040830184612a48565b604081016133468285612c1c565b6130a56020830184612a48565b600061274e61336361ffff841681565b90565b612a4a81613353565b600061274e6133636fffffffffffffffffffffffffffffffff841681565b612a4a8161336f565b600061274e61336363ffffffff841681565b612a4a81613396565b60e081016133bf828a612a48565b6133cc6020830189612c1c565b6133d96040830188613366565b6133e66060830187612c1c565b6133f36080830186612c70565b61340060a083018561338d565b61340d60c08301846133a8565b98975050505050505050565b606081016134278286612c1c565b6134346020830185612a48565b6106a96040830184612c1c565b60128152602081017f3020696d70726f76656d656e742072617465000000000000000000000000000081529050612ef4565b6020808252810161274e81613441565b600b8152602081017f6c6f616e20636c6f73656400000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613483565b805161274e816128db565b6000602082840312156134e5576134e5600080fd5b60006106a984846134c5565b60198152602081017f626f72726f77207469636b657420686f6c646572206f6e6c790000000000000081529050612ef4565b6020808252810161274e816134f1565b600a8152602081017f686173206c656e6465720000000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613533565b604081016133468285612a48565b60178152602081017f6c656e64207469636b657420686f6c646572206f6e6c7900000000000000000081529050612ef4565b6020808252810161274e81613583565b64ffffffffff8116905064ffffffffff8216915060008264ffffffffff0382111561320357613203612f4a565b60138152602081017f7061796d656e74206973206e6f74206c6174650000000000000000000000000081529050612ef4565b6020808252810161274e816135f2565b600c8152602081017f696e76616c6964206c6f616e000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613634565b600d8152602081017f7261746520746f6f20686967680000000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613676565b60108152602081017f6475726174696f6e20746f6f206c6f770000000000000000000000000000000081529050612ef4565b6020808252810161274e816136b8565b600e8152602081017f616d6f756e7420746f6f206c6f7700000000000000000000000000000000000081529050612ef4565b6020808252810161274e816136fa565b600e8152602081017f696e76616c696420616d6f756e7400000000000000000000000000000000000081529050612ef4565b6020808252810161274e8161373c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826137bc576137bc61377e565b500490565b81612f82565b601b8152602081017f616d6f756e7420696e637265617365206e6f7420616c6c6f776564000000000081529050612ef4565b6020808252810161274e816137c7565b60188152602081017f696e73756666696369656e7420696d70726f76656d656e74000000000000000081529050612ef4565b6020808252810161274e81613809565b60188152602081017f696e74657265737420657863656564732075696e74313238000000000000000081529050612ef4565b6020808252810161274e8161384b565b6060810161389b8286613366565b6138a8602083018561338d565b6106a960408301846133a8565b6020808252810161274e81602681527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160208201527f6464726573730000000000000000000000000000000000000000000000000000604082015260600190565b600f8152602081017f5452414e534645525f4641494c4544000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613916565b60148152602081017f5452414e534645525f46524f4d5f4641494c454400000000000000000000000081529050612ef4565b6020808252810161274e81613958565b6000826139a9576139a961377e565b50069056fea2646970667358221220cd745515142c5d9eb4ef99a1771080c6f3da0e0c98490fe315c26b8ed1710d5e64736f6c634300080c0033000000000000000000000000bac4edfab0ffbd3344b163fad587f07261c6cd7e
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101a25760003560e01c80636bf301a4116100ee5780638da5cb5b11610097578063b6ecac5711610071578063b6ecac5714610432578063b8efff83146105b0578063e926e9af146105c3578063f2fde38b146105d657600080fd5b80638da5cb5b146103ee578063a27158d71461040c578063ac9cf4db1461041f57600080fd5b80637af26c1f116100c85780637af26c1f146102ce5780637e8400b2146102ee5780638349d6be1461030157600080fd5b80636bf301a4146102ab578063715018a6146102b35780637a0815c0146102bb57600080fd5b80633f58184811610150578063654ea0981161012a578063654ea0981461025657806366234ffa1461026957806367cec5a31461027e57600080fd5b80633f5818481461021d5780635ecd217314610230578063639542531461024357600080fd5b8063311f13c611610181578063311f13c6146101f857806337bb105c146102015780633b8174961461021457600080fd5b806223de29146101a757806310780bed146101bc578063300ed99b146101e5575b600080fd5b6101ba6101b536600461295d565b6105e9565b005b6101cf6101ca366004612a27565b610624565b6040516101dc9190612a50565b60405180910390f35b6101ba6101f3366004612a75565b6106b1565b6101cf60025481565b6101ba61020f366004612a96565b6107a8565b6101cf60015481565b6101ba61022b366004612a96565b610890565b6101cf61023e366004612a27565b610978565b6101cf610251366004612b02565b6109eb565b6101ba610264366004612bb5565b610e21565b610271600381565b6040516101dc9190612c0e565b60035461029e9073ffffffffffffffffffffffffffffffffffffffff1681565b6040516101dc9190612c25565b6101cf610ed3565b6101ba610ee2565b6101ba6102c9366004612a27565b610f3f565b60045461029e9073ffffffffffffffffffffffffffffffffffffffff1681565b6101ba6102fc366004612c33565b610ffc565b6103d761030f366004612a27565b600560205260009081526040902080546001820154600283015460039093015460ff8084169461010080860461ffff16956301000000810463ffffffff1695670100000000000000820464ffffffffff16956c010000000000000000000000009283900473ffffffffffffffffffffffffffffffffffffffff908116968316959483046affffffffffffffffffffff169493909204909116916fffffffffffffffffffffffffffffffff8082169270010000000000000000000000000000000090920416908b565b6040516101dc9b9a99989796959493929190612cc6565b60005473ffffffffffffffffffffffffffffffffffffffff1661029e565b6101ba61041a366004612a27565b61127d565b6101ba61042d366004612c33565b6115e2565b6105a3610440366004612a27565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915250600090815260056020908152604091829020825161016081018452815460ff8082161515835261010080830461ffff16958401959095526301000000820463ffffffff1695830195909552670100000000000000810464ffffffffff1660608301526c010000000000000000000000009081900473ffffffffffffffffffffffffffffffffffffffff90811660808401526001840154958616151560a08401528486046affffffffffffffffffffff1660c0840152940490931660e084015260028101546fffffffffffffffffffffffffffffffff8082169385019390935270010000000000000000000000000000000090049091166101208301526003015461014082015290565b6040516101dc9190612e3f565b6101ba6105be366004612e4e565b6118ac565b6101cf6105d1366004612a27565b612373565b6101ba6105e4366004612a96565b61243a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612efa565b60405180910390fd5b6000818152600560205260408120805464ffffffffff6701000000000000008204169060ff1680610653575080155b15610662575060009392505050565b600282015482546106a99170010000000000000000000000000000000081046fffffffffffffffffffffffffffffffff90811692859261010090910461ffff1691166124e4565b949350505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610702576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b61070e60026003612f79565b61071990600a6130ac565b6107249060056130df565b8163ffffffff161115610763576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061314e565b63ffffffff81166001556040517f5318780da42901eb551b3beab1953fa2673bf9592c023ed47f8929cfd705a4269061079d90839061315e565b60405180910390a150565b60005473ffffffffffffffffffffffffffffffffffffffff1633146107f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b60045473ffffffffffffffffffffffffffffffffffffffff1615610849576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061319e565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff1633146108e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b60035473ffffffffffffffffffffffffffffffffffffffff1615610931576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061319e565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008181526005602052604081208054670100000000000000900464ffffffffff16806109d1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906131e0565b81546106a99082906301000000900463ffffffff166131f0565b600063ffffffff8316610a2a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061323a565b6fffffffffffffffffffffffffffffffff8516610a73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061327c565b60035473ffffffffffffffffffffffffffffffffffffffff89811691161415610ac8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906132be565b60045473ffffffffffffffffffffffffffffffffffffffff89811691161415610b1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613300565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8916906323b872dd90610b7390339030908e90600401613310565b600060405180830381600087803b158015610b8d57600080fd5b505af1158015610ba1573d6000803e3d6000fd5b50505050600660008154809291906001019190505590506000600560008381526020019081526020016000209050868160010160006101000a81548160ff0219169083151502179055506001548160010160016101000a8154816affffffffffffffffffffff02191690836affffffffffffffffffffff1602179055508481600101600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550858160020160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508981600301819055508881600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550878160000160016101000a81548161ffff021916908361ffff160217905550838160000160036101000a81548163ffffffff021916908363ffffffff160217905550600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1984846040518363ffffffff1660e01b8152600401610d87929190613338565b600060405180830381600087803b158015610da157600080fd5b505af1158015610db5573d6000803e3d6000fd5b505050503373ffffffffffffffffffffffffffffffffffffffff16827f7c227a124a9e9096681f1f99e084a9a4223cf0b62d37c03fe22fdb55b8ad2cdb8c8c8c8a8d8d8c604051610e0c97969594939291906133b1565b60405180910390a35098975050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610e72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b610e9373ffffffffffffffffffffffffffffffffffffffff8416828461254d565b7fa8790deb319345e298343f10ed7d6a75b74909da42818501958de9e08f73869e838383604051610ec693929190613419565b60405180910390a1505050565b610edf6003600a6130ac565b81565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f33576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b610f3d60006125ea565b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b80610fc7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613473565b60028190556040517f955a84aca3e56ae377e1e799c430fec3709dda2c19da07f13e6c1a33df3cbf229061079d908390612a50565b600082815260056020526040902054829060ff1615611047576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906134b5565b600480546040517f6352211e000000000000000000000000000000000000000000000000000000008152339273ffffffffffffffffffffffffffffffffffffffff90921691636352211e9161109e91889101612a50565b602060405180830381865afa1580156110bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110df91906134d0565b73ffffffffffffffffffffffffffffffffffffffff161461112c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613523565b60008381526005602052604090208054670100000000000000900464ffffffffff1615611185576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613565565b805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161780825560038201546040517f23b872dd0000000000000000000000000000000000000000000000000000000081526c0100000000000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16916323b872dd9161121a9130918891600401613310565b600060405180830381600087803b15801561123457600080fd5b505af1158015611248573d6000803e3d6000fd5b50506040518692507fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf9150600090a250505050565b600081815260056020526040902054819060ff16156112c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906134b5565b600082815260056020526040812060028101548154919270010000000000000000000000000000000082046fffffffffffffffffffffffffffffffff908116939192611334928592670100000000000000820464ffffffffff169261010090920461ffff1691166124e4565b6003546040517f6352211e00000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff90911690636352211e90611390908990600401612a50565b602060405180830381865afa1580156113ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113d191906134d0565b84547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001178555905061143e338261140b86866131f0565b60018801546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1692919061265f565b8354600480546040517f6352211e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009094048416936323b872dd93309390911691636352211e916114b1918d9101612a50565b602060405180830381865afa1580156114ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f291906134d0565b87600301546040518463ffffffff1660e01b815260040161151593929190613310565b600060405180830381600087803b15801561152f57600080fd5b505af1158015611543573d6000803e3d6000fd5b505050508073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16877f9181b2981704b7cf4448130f29cb5da1f41e0418d000e7f8880000b09bcbea4585876040516115a7929190613575565b60405180910390a460405186907fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf90600090a2505050505050565b600082815260056020526040902054829060ff161561162d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906134b5565b6003546040517f6352211e000000000000000000000000000000000000000000000000000000008152339173ffffffffffffffffffffffffffffffffffffffff1690636352211e90611683908790600401612a50565b602060405180830381865afa1580156116a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116c491906134d0565b73ffffffffffffffffffffffffffffffffffffffff1614611711576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906135b5565b6000838152600560205260409020805461174a90670100000000000000810464ffffffffff16906301000000900463ffffffff166135c5565b64ffffffffff164211611789576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613624565b805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009091161780825560038201546040517f23b872dd0000000000000000000000000000000000000000000000000000000081526c0100000000000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16916323b872dd9161181e9130918891600401613310565b600060405180830381600087803b15801561183857600080fd5b505af115801561184c573d6000803e3d6000fd5b50506040518692507f19f0d220035b967365e70d19ca7093af2e75a9741c08ef27c5017d6f463febd99150600090a260405184907fbf67515a38ee520223d32c1266d52101c30d936ed1f3e436c8caeb0a43cb06bf90600090a250505050565b600085815260056020526040902054859060ff16156118f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906134b5565b60008681526005602052604090208054670100000000000000900464ffffffffff16611d945760018101546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16803b611980576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613666565b815461ffff610100909104811690881611156119c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906136a8565b815463ffffffff630100000090910481169086161015611a14576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906136ea565b600182015460ff1615611a8e5760028201546fffffffffffffffffffffffffffffffff70010000000000000000000000000000000090910481169087161015611a89576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061372c565b611af4565b60028201546fffffffffffffffffffffffffffffffff8781167001000000000000000000000000000000009092041614611af4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061376e565b81547fffffffffffffffffffffffffffffffffffffffff0000000000ffffffff0000ff1661010061ffff8916027fffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffff16176701000000000000004264ffffffffff1602177fffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffff16630100000063ffffffff8716021782556002820180546fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000918916919091021790556000611bcd6003600a6130ac565b6001840154611c009061010090046affffffffffffffffffffff166fffffffffffffffffffffffffffffffff8a166130df565b611c0a91906137ad565b9050611c2e73ffffffffffffffffffffffffffffffffffffffff831633308461265f565b600480546040517f6352211e000000000000000000000000000000000000000000000000000000008152611d0392339273ffffffffffffffffffffffffffffffffffffffff1691636352211e91611c87918f9101612a50565b602060405180830381865afa158015611ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc891906134d0565b611ce4846fffffffffffffffffffffffffffffffff8c166137c1565b73ffffffffffffffffffffffffffffffffffffffff861692919061265f565b6003546040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff909116906340c10f1990611d5b9088908d90600401613338565b600060405180830381600087803b158015611d7557600080fd5b505af1158015611d89573d6000803e3d6000fd5b505050505050612317565b60028101546fffffffffffffffffffffffffffffffff700100000000000000000000000000000000909104811690600090611dd290839089166137c1565b600184015490915060ff16611e19578015611e19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906137f9565b825460009061ffff610100820481169163ffffffff630100000090910416908b16821015611e73576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906136a8565b808963ffffffff161015611eb3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906136ea565b83611ed660025487611ec591906130df565b611ed16003600a6130ac565b612719565b111580611f0357508863ffffffff16611ef660025483611ec591906130df565b611f0090836131f0565b11155b80611f3657508115801590611f3657508a61ffff16611f2960025484611ec591906130df565b611f3390846137c1565b10155b611f6c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061383b565b85546002870154611fa691879167010000000000000090910464ffffffffff169085906fffffffffffffffffffffffffffffffff166124e4565b925050507001000000000000000000000000000000008110611ff4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061387d565b83547fffffffffffffffffffffffffffffffffffffffff0000000000ffffffff0000ff1661010061ffff8b16027fffffffffffffffffffffffffffffffffffffffff0000000000ffffffffffffff16176701000000000000004264ffffffffff1602177fffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffff16630100000063ffffffff8916021784557fffffffffffffffffffffffffffffffff000000000000000000000000000000007001000000000000000000000000000000006fffffffffffffffffffffffffffffffff8a811691909102919091169082161760028501556003546040517f6352211e00000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff1690636352211e90612138908e90600401612a50565b602060405180830381865afa158015612155573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217991906134d0565b9050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a236897a82898e6040518463ffffffff1660e01b81526004016121da93929190613310565b600060405180830381600087803b1580156121f457600080fd5b505af1158015612208573d6000803e3d6000fd5b505050506000831115612268576001850154612263908c906c01000000000000000000000000810473ffffffffffffffffffffffffffffffffffffffff1690869061010090046affffffffffffffffffffff1685878a612754565b6122aa565b6122aa338261227787866131f0565b60018901546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1692919061265f565b8073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff168c7f060231091bad585835f99d8cadcc3ff7fa49943bd1b52cde44a74762102aba44858860405161230a929190613575565b60405180910390a4505050505b3373ffffffffffffffffffffffffffffffffffffffff16877f5f20982d2196b477a67cf9eec22865b0093715235a896e9202a55d2acb85dba38888886040516123629392919061388d565b60405180910390a350505050505050565b6000818152600560205260408120805464ffffffffff6701000000000000008204169060ff16806123a2575080155b156123b1575060009392505050565b600282015482546123f89170010000000000000000000000000000000081046fffffffffffffffffffffffffffffffff90811692859261010090910461ffff1691166124e4565b6000858152600560205260409020600201546106a9919070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166131f0565b60005473ffffffffffffffffffffffffffffffffffffffff16331461248b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90612f3a565b73ffffffffffffffffffffffffffffffffffffffff81166124d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b906138b5565b6124e1816125ea565b50565b600081683635c9adc5dea000006301e1338061250886670de0b6b3a76400006130df565b61251291906137ad565b61251c87426137c1565b61252690896130df565b61253091906130df565b61253a91906137ad565b61254491906131f0565b95945050505050565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201528260248201526000806044836000895af19150506125ae81612876565b6125e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b90613948565b50505050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff8416602482015282604482015260008060648360008a5af19150506126dc81612876565b612712576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061b9061398a565b5050505050565b6000612725828461399a565b15612731576001612734565b60005b60ff1661274183856137ad565b61274b91906131f0565b90505b92915050565b60006127626003600a6130ac565b61276c86886130df565b61277691906137ad565b905061279a73ffffffffffffffffffffffffffffffffffffffff881633308461265f565b6127c833856127a985876131f0565b73ffffffffffffffffffffffffffffffffffffffff8b1692919061265f565b600480546040517f6352211e00000000000000000000000000000000000000000000000000000000815261286c92339273ffffffffffffffffffffffffffffffffffffffff1691636352211e91612821918e9101612a50565b602060405180830381865afa15801561283e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061286291906134d0565b6127a9848a6137c1565b5050505050505050565b60003d8261288857806000803e806000fd5b80602081146128a05780156128b157600092506128b6565b816000803e600051151592506128b6565b600192505b5050919050565b600073ffffffffffffffffffffffffffffffffffffffff821661274e565b6128e4816128bd565b81146124e157600080fd5b803561274e816128db565b806128e4565b803561274e816128fa565b60008083601f84011261292057612920600080fd5b50813567ffffffffffffffff81111561293b5761293b600080fd5b60208301915083600182028301111561295657612956600080fd5b9250929050565b60008060008060008060008060c0898b03121561297c5761297c600080fd5b60006129888b8b6128ef565b98505060206129998b828c016128ef565b97505060406129aa8b828c016128ef565b96505060606129bb8b828c01612900565b955050608089013567ffffffffffffffff8111156129db576129db600080fd5b6129e78b828c0161290b565b945094505060a089013567ffffffffffffffff811115612a0957612a09600080fd5b612a158b828c0161290b565b92509250509295985092959890939650565b600060208284031215612a3c57612a3c600080fd5b60006106a98484612900565b805b82525050565b6020810161274e8284612a48565b63ffffffff81166128e4565b803561274e81612a5e565b600060208284031215612a8a57612a8a600080fd5b60006106a98484612a6a565b600060208284031215612aab57612aab600080fd5b60006106a984846128ef565b61ffff81166128e4565b803561274e81612ab7565b8015156128e4565b803561274e81612acc565b6fffffffffffffffffffffffffffffffff81166128e4565b803561274e81612adf565b600080600080600080600080610100898b031215612b2257612b22600080fd5b6000612b2e8b8b612900565b9850506020612b3f8b828c016128ef565b9750506040612b508b828c01612ac1565b9650506060612b618b828c01612ad4565b9550506080612b728b828c01612af7565b94505060a0612b838b828c016128ef565b93505060c0612b948b828c01612a6a565b92505060e0612ba58b828c016128ef565b9150509295985092959890939650565b600080600060608486031215612bcd57612bcd600080fd5b6000612bd986866128ef565b9350506020612bea86828701612900565b9250506040612bfb868287016128ef565b9150509250925092565b60ff8116612a4a565b6020810161274e8284612c05565b612a4a816128bd565b6020810161274e8284612c1c565b60008060408385031215612c4957612c49600080fd5b6000612c558585612900565b9250506020612c66858286016128ef565b9150509250929050565b801515612a4a565b61ffff8116612a4a565b63ffffffff8116612a4a565b64ffffffffff8116612a4a565b6affffffffffffffffffffff8116612a4a565b6fffffffffffffffffffffffffffffffff8116612a4a565b6101608101612cd5828e612c70565b612ce2602083018d612c78565b612cef604083018c612c82565b612cfc606083018b612c8e565b612d09608083018a612c1c565b612d1660a0830189612c70565b612d2360c0830188612c9b565b612d3060e0830187612c1c565b612d3e610100830186612cae565b612d4c610120830185612cae565b612d5a610140830184612a48565b9c9b505050505050505050505050565b8051612d768382612c70565b506020810151612d896020840182612c78565b506040810151612d9c6040840182612c82565b506060810151612daf6060840182612c8e565b506080810151612dc26080840182612c1c565b5060a0810151612dd560a0840182612c70565b5060c0810151612de860c0840182612c9b565b5060e0810151612dfb60e0840182612c1c565b50610100810151612e10610100840182612cae565b50610120810151612e25610120840182612cae565b50610140810151612e3a610140840182612a48565b505050565b610160810161274e8284612d6a565b600080600080600060a08688031215612e6957612e69600080fd5b6000612e758888612900565b9550506020612e8688828901612ac1565b9450506040612e9788828901612af7565b9350506060612ea888828901612a6a565b9250506080612eb9888289016128ef565b9150509295509295909350565b60128152602081017f45524337373720756e737570706f727465640000000000000000000000000000815290505b60200190565b6020808252810161274e81612ec6565b60208082527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65729101908152612ef4565b6020808252810161274e81612f0a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff9081169082165b9150600082821015612f9657612f96612f4a565b500390565b80825b6001851115612fda57808604811115612fb957612fb9612f4a565b6001851615612fc757908102905b8002612fd38560011c90565b9450612f9e565b94509492505050565b600082612ff2575060016130a5565b81612fff575060006130a5565b8160018114613015576002811461301f5761304c565b60019150506130a5565b60ff84111561303057613030612f4a565b8360020a91508482111561304657613046612f4a565b506130a5565b5060208310610133831016604e8410600b841016171561307f575081810a8381111561307a5761307a612f4a565b6130a5565b61308c8484846001612f9b565b925090508184048111156130a2576130a2612f4a565b81025b9392505050565b60ff82169150600061274b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484612fe3565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561311757613117612f4a565b500290565b600a8152602081017f6d6178206665652035250000000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e8161311c565b6020810161274e8284612c82565b600b8152602081017f616c72656164792073657400000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e8161316c565b60128152602081017f6c6f616e20686173206e6f206c656e646572000000000000000000000000000081529050612ef4565b6020808252810161274e816131ae565b6000821982111561320357613203612f4a565b500190565b600a8152602081017f30206475726174696f6e0000000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613208565b600d8152602081017f30206c6f616e20616d6f756e740000000000000000000000000000000000000081529050612ef4565b6020808252810161274e8161324a565b60168152602081017f6c656e64207469636b657420636f6c6c61746572616c0000000000000000000081529050612ef4565b6020808252810161274e8161328c565b60188152602081017f626f72726f77207469636b657420636f6c6c61746572616c000000000000000081529050612ef4565b6020808252810161274e816132ce565b6060810161331e8286612c1c565b61332b6020830185612c1c565b6106a96040830184612a48565b604081016133468285612c1c565b6130a56020830184612a48565b600061274e61336361ffff841681565b90565b612a4a81613353565b600061274e6133636fffffffffffffffffffffffffffffffff841681565b612a4a8161336f565b600061274e61336363ffffffff841681565b612a4a81613396565b60e081016133bf828a612a48565b6133cc6020830189612c1c565b6133d96040830188613366565b6133e66060830187612c1c565b6133f36080830186612c70565b61340060a083018561338d565b61340d60c08301846133a8565b98975050505050505050565b606081016134278286612c1c565b6134346020830185612a48565b6106a96040830184612c1c565b60128152602081017f3020696d70726f76656d656e742072617465000000000000000000000000000081529050612ef4565b6020808252810161274e81613441565b600b8152602081017f6c6f616e20636c6f73656400000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613483565b805161274e816128db565b6000602082840312156134e5576134e5600080fd5b60006106a984846134c5565b60198152602081017f626f72726f77207469636b657420686f6c646572206f6e6c790000000000000081529050612ef4565b6020808252810161274e816134f1565b600a8152602081017f686173206c656e6465720000000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613533565b604081016133468285612a48565b60178152602081017f6c656e64207469636b657420686f6c646572206f6e6c7900000000000000000081529050612ef4565b6020808252810161274e81613583565b64ffffffffff8116905064ffffffffff8216915060008264ffffffffff0382111561320357613203612f4a565b60138152602081017f7061796d656e74206973206e6f74206c6174650000000000000000000000000081529050612ef4565b6020808252810161274e816135f2565b600c8152602081017f696e76616c6964206c6f616e000000000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613634565b600d8152602081017f7261746520746f6f20686967680000000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613676565b60108152602081017f6475726174696f6e20746f6f206c6f770000000000000000000000000000000081529050612ef4565b6020808252810161274e816136b8565b600e8152602081017f616d6f756e7420746f6f206c6f7700000000000000000000000000000000000081529050612ef4565b6020808252810161274e816136fa565b600e8152602081017f696e76616c696420616d6f756e7400000000000000000000000000000000000081529050612ef4565b6020808252810161274e8161373c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826137bc576137bc61377e565b500490565b81612f82565b601b8152602081017f616d6f756e7420696e637265617365206e6f7420616c6c6f776564000000000081529050612ef4565b6020808252810161274e816137c7565b60188152602081017f696e73756666696369656e7420696d70726f76656d656e74000000000000000081529050612ef4565b6020808252810161274e81613809565b60188152602081017f696e74657265737420657863656564732075696e74313238000000000000000081529050612ef4565b6020808252810161274e8161384b565b6060810161389b8286613366565b6138a8602083018561338d565b6106a960408301846133a8565b6020808252810161274e81602681527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160208201527f6464726573730000000000000000000000000000000000000000000000000000604082015260600190565b600f8152602081017f5452414e534645525f4641494c4544000000000000000000000000000000000081529050612ef4565b6020808252810161274e81613916565b60148152602081017f5452414e534645525f46524f4d5f4641494c454400000000000000000000000081529050612ef4565b6020808252810161274e81613958565b6000826139a9576139a961377e565b50069056fea2646970667358221220cd745515142c5d9eb4ef99a1771080c6f3da0e0c98490fe315c26b8ed1710d5e64736f6c634300080c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000bac4edfab0ffbd3344b163fad587f07261c6cd7e
-----Decoded View---------------
Arg [0] : _manager (address): 0xbac4edFAB0FFBD3344B163fAd587F07261c6CD7E
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000bac4edfab0ffbd3344b163fad587f07261c6cd7e
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.