This nametag was submitted by Kleros Curate.
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 11,940 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Admin Claim Erc7... | 19738506 | 93 days ago | IN | 0 ETH | 0.00061298 | ||||
Admin Claim Erc7... | 19738040 | 93 days ago | IN | 0 ETH | 0.00022886 | ||||
Admin Claim Erc7... | 19737951 | 93 days ago | IN | 0 ETH | 0.00022712 | ||||
Repay | 19635062 | 108 days ago | IN | 0 ETH | 0.00044995 | ||||
Liquidate | 17826678 | 361 days ago | IN | 0 ETH | 0.00368609 | ||||
Liquidate | 17826676 | 361 days ago | IN | 0 ETH | 0.002965 | ||||
Liquidate | 17795038 | 365 days ago | IN | 0 ETH | 0.00308141 | ||||
Liquidate | 17795033 | 365 days ago | IN | 0 ETH | 0.00282115 | ||||
Liquidate | 17795032 | 365 days ago | IN | 0 ETH | 0.00296176 | ||||
Repay | 17731478 | 374 days ago | IN | 0 ETH | 0.00330131 | ||||
Liquidate | 17673845 | 382 days ago | IN | 0 ETH | 0.00213703 | ||||
Repay | 17642942 | 387 days ago | IN | 0 ETH | 0.00583623 | ||||
Repay | 17624505 | 389 days ago | IN | 0 ETH | 0.00929995 | ||||
Repay | 17615661 | 391 days ago | IN | 0 ETH | 0.00321123 | ||||
Repay | 17615444 | 391 days ago | IN | 0 ETH | 0.00581606 | ||||
Repay | 17615439 | 391 days ago | IN | 0 ETH | 0.00587201 | ||||
Repay | 17603654 | 392 days ago | IN | 0 ETH | 0.0026799 | ||||
Liquidate | 17582203 | 395 days ago | IN | 0 ETH | 0.00321463 | ||||
Repay | 17566644 | 398 days ago | IN | 0 ETH | 0.00289046 | ||||
Repay | 17561193 | 398 days ago | IN | 0 ETH | 0.00377569 | ||||
Repay | 17558737 | 399 days ago | IN | 0 ETH | 0.00306355 | ||||
Repay | 17557051 | 399 days ago | IN | 0 ETH | 0.002607 | ||||
Liquidate | 17554448 | 399 days ago | IN | 0 ETH | 0.00204616 | ||||
Repay | 17550765 | 400 days ago | IN | 0 ETH | 0.0031756 | ||||
Repay | 17531418 | 402 days ago | IN | 0 ETH | 0.00289797 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
XY3
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 99 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import "./interfaces/IXY3.sol"; import "./interfaces/IDelegateV3.sol"; import "./interfaces/IAddressProvider.sol"; import "./interfaces/IServiceFee.sol"; import {IFlashExecPermits} from "./interfaces/IFlashExecPermits.sol"; import "./DataTypes.sol"; import "./LoanStatus.sol"; import "./Config.sol"; import "./utils/SigningUtils.sol"; import {InterceptorManager} from "./InterceptorManager.sol"; import {SIGNER_ROLE} from "./Roles.sol"; /** * @title XY3 * @author XY3 * @notice Main contract for XY3 lending. */ contract XY3 is IXY3, Config, LoanStatus, InterceptorManager, ERC721Holder, ERC1155Holder { using SafeERC20 for IERC20; /** * @notice A mapping from a loan's identifier to the loan's terms, represted by the LoanTerms struct. */ mapping(uint32 => LoanDetail) public override loanDetails; /** * @notice A mapping, (collection address, token Id) -> loan ID. */ mapping(address => mapping(uint256 => uint32)) public override loanIds; /** * @notice A mapping, (user address , nonce) -> boolean. */ mapping(address => mapping(uint256 => bool)) internal _invalidNonce; /** * @notice A mapping that takes a user's address and a cancel timestamp. * */ mapping(address => uint256) internal _offerCancelTimestamp; /** * modifier */ modifier loanIsOpen(uint32 _loanId) { require( getLoanState(_loanId).status == StatusType.NEW, "Loan is not open" ); _; } /** * @dev Init contract * * @param _admin - Initial admin of this contract. * @param _addressProvider - AddressProvider contract */ constructor( address _admin, address _addressProvider ) Config(_admin, _addressProvider) LoanStatus() InterceptorManager() { } /** PUBLIC FUNCTIONS */ /** * @dev The borrower accept a lender's offer to create a loan. * * @param _offer - The offer made by the lender. * @param _nftId - The ID * @param _isCollectionOffer - Wether the offer is a collection offer. * @param _lenderSignature - The lender's signature. * @param _brokerSignature - The broker's signature. * @param _extraDeal - Create a new loan by getting a NFT colleteral from external contract call. * The external contract can be lending market or deal market, specially included the restricted repay of myself. * But should not be the Xy3Nft.mint, though this contract maybe have the permission. */ function borrow( Offer calldata _offer, uint256 _nftId, bool _isCollectionOffer, Signature calldata _lenderSignature, Signature calldata _brokerSignature, CallData calldata _extraDeal ) external override whenNotPaused nonReentrant returns (uint32) { _loanSanityChecks(_offer); address nftAsset = _offer.nftAsset; beforeBorrow(nftAsset, _nftId); LoanDetail memory _loanDetail = _createLoanDetail( _offer, _nftId, _isCollectionOffer ); _checkBorrow( _offer, _nftId, _isCollectionOffer, _lenderSignature, _brokerSignature ); IAddressProvider addressProvider = getAddressProvider(); IDelegateV3(addressProvider.getTransferDelegate()).erc20Transfer( _lenderSignature.signer, msg.sender, _offer.borrowAsset, _offer.borrowAmount ); if (_extraDeal.target != address(0)) { require(getAgentPermit(_extraDeal.target, _extraDeal.selector), "Not valide agent"); bytes memory data = abi.encodeWithSelector( _extraDeal.selector, msg.sender, _extraDeal.data ); (bool succ, ) = _extraDeal.target.call(data); require(succ, "Borrow extra call failed"); } IDelegateV3(addressProvider.getTransferDelegate()).erc721Transfer( msg.sender, address(this), nftAsset, _nftId ); uint32 loanId = _createBorrowNote( _lenderSignature.signer, msg.sender, _loanDetail, _lenderSignature, _extraDeal ); _serviceFee(_offer, loanId, _extraDeal.target); loanIds[nftAsset][_nftId] = loanId; afterBorrow(nftAsset, _nftId); emit BorrowRefferal(loanId, msg.sender, _extraDeal.referral); return loanId; } /** * @dev Restricted function, only called by self from borrow with target. * @param _sender The borrow's msg.sender. * @param _param The borrow CallData's data, encode loadId only. */ function repay(address _sender, bytes calldata _param) external { require(msg.sender == address(this), "Invalide caller"); uint32 loanId = abi.decode(_param, (uint32)); _repay(_sender, loanId); } /** * @dev Public function for anyone to repay a loan, and return the NFT token to origin borrower. * @param _loanId The loan Id. */ function repay(uint32 _loanId) public override nonReentrant { _repay(msg.sender, _loanId); } /** * @dev Lender ended the load which not paid by borrow and expired. * * @param _loanId The loan Id. */ function liquidate( uint32 _loanId ) external override nonReentrant loanIsOpen(_loanId) { ( address borrower, address lender, LoanDetail memory loan ) = _getPartiesAndData(_loanId); address nftAsset = loan.nftAsset; uint nftId = loan.nftTokenId; beforeLiquidate(nftAsset, nftId); uint256 loanMaturityDate = _loanMaturityDate(loan); require(block.timestamp > loanMaturityDate, "Loan is not overdue yet"); require(msg.sender == lender, "Only lender can liquidate"); // Emit an event with all relevant details from this transaction. emit LoanLiquidated( _loanId, borrower, lender, loan.borrowAmount, nftId, loanMaturityDate, block.timestamp, nftAsset ); // nft to lender IERC721(nftAsset).safeTransferFrom(address(this), lender, nftId); _resolveLoanNote(_loanId); delete loanIds[nftAsset][nftId]; afterLiquidate(nftAsset, nftId); } /** * @dev Flash out the colleteral NFT. * * @param _loanId The loan Id. * @param _target The target contract. * @param _selector The callback selector. * @param _data The callback data. */ function flashExecute( uint32 _loanId, address _target, bytes4 _selector, bytes memory _data ) external { (address borrower, , LoanDetail memory loan) = _getPartiesAndData( _loanId ); IAddressProvider addressProvider = getAddressProvider(); require( IFlashExecPermits(addressProvider.getFlashExecPermits()) .isPermitted(_target, _selector), "Invalid airdrop target" ); require(block.timestamp <= _loanMaturityDate(loan), "Loan is expired"); require(msg.sender == borrower, "Only borrower"); IERC721(loan.nftAsset).safeTransferFrom( address(this), _target, loan.nftTokenId ); (bool succ, ) = _target.call( abi.encodeWithSelector(_selector, msg.sender, _data) ); require(succ, "External call failed"); address owner = IERC721(loan.nftAsset).ownerOf(loan.nftTokenId); require(owner == address(this), "Nft not returned"); emit FlashExecute(_loanId, loan.nftAsset, loan.nftTokenId, _target); } /** * @dev A lender or a borrower to cancel all off-chain orders signed that contain this nonce. * @param _nonce - User nonce */ function cancelByNonce(uint256 _nonce) external override { require(!_invalidNonce[msg.sender][_nonce], "Invalid nonce"); _invalidNonce[msg.sender][_nonce] = true; emit NonceCancelled(msg.sender, _nonce); } /** * @dev A borrower cancel all offers with timestamp before the _timestamp parameter. * @param _timestamp - cancelled timestamp */ function cancelByTimestamp(uint256 _timestamp) external override { require(_timestamp < block.timestamp, "Invalid timestamp"); if (_timestamp > _offerCancelTimestamp[msg.sender]) { _offerCancelTimestamp[msg.sender] = _timestamp; emit TimeStampCancelled(msg.sender, _timestamp); } } /** * @dev The amount of ERC20 currency for the loan. * * @param _loanId loan Id. * @return The amount of ERC20 currency. */ function getRepayAmount( uint32 _loanId ) external view override returns (uint256) { LoanDetail storage loan = loanDetails[_loanId]; return loan.repayAmount; } /** * @notice Check a nonce has been used or not * @param _user - The user address. * @param _nonce - The order Id. * * @return A bool for used or not. */ function getNonceUsed( address _user, uint256 _nonce ) external view override returns (bool) { return _invalidNonce[_user][_nonce]; } /** * @dev This function can be used to view the last cancel timestamp a borrower has set. * @param _user User address * @return The cancel timestamp */ function getTimestampCancelled( address _user ) external view override returns (uint256) { return _offerCancelTimestamp[_user]; } /** * @dev Claim the ERC20 airdrop by admin timelock. * @param _to - Receiver address * @param tokens - Claimed token list * @param amounts - Clamined amount list */ function adminClaimErc20( address _to, address[] memory tokens, uint256[] memory amounts ) external override onlyRole(DEFAULT_ADMIN_ROLE) { require(_to != address(0x0), "Invalid address"); for (uint i = 0; i < tokens.length; i++) { address token = tokens[i]; IERC20(token).safeTransfer(_to, amounts[i]); } } /** * @dev Claim the ERC721 airdrop by admin timelock. * @param _to - Receiver address * @param tokens - Claimed token list * @param tokenIds - Clamined ID list */ function adminClaimErc721( address _to, address[] memory tokens, uint256[] memory tokenIds ) external override onlyRole(DEFAULT_ADMIN_ROLE) { for (uint i = 0; i < tokens.length; i++) { address token = tokens[i]; uint256 tokenId = tokenIds[i]; uint32 loanId = loanIds[token][tokenId]; if (loanId == 0) { IERC721(token).safeTransferFrom( address(this), _to, tokenIds[i] ); } } } /** * @dev Claim the ERC1155 airdrop by admin timelock. * @param _to - Receiver address * @param tokens - Claimed token list * @param tokenIds - Clamined ID list * @param amounts - Clamined amount list */ function adminClaimErc1155( address _to, address[] memory tokens, uint256[] memory tokenIds, uint256[] memory amounts ) external override onlyRole(DEFAULT_ADMIN_ROLE) { for (uint i = 0; i < tokens.length; i++) { address token = tokens[i]; IERC1155(token).safeTransferFrom( address(this), _to, tokenIds[i], amounts[i], "" ); } } /** * @dev ERC165 support */ function supportsInterface( bytes4 interfaceId ) public view virtual override(AccessControl, ERC1155Receiver) returns (bool) { return interfaceId == type(IERC721Receiver).interfaceId || super.supportsInterface(interfaceId); } /** * @param _loanId Load Id. */ function _resolveLoanNote(uint32 _loanId) internal { resolveLoan(_loanId); delete loanDetails[_loanId]; } /** * @dev Check loan parameters validation * */ function _loanSanityChecks(Offer memory _offer) internal view { require(getERC20Permit(_offer.borrowAsset), "Invalid currency"); require(getERC721Permit(_offer.nftAsset), "Invalid ERC721 token"); require( uint256(_offer.borrowDuration) <= maxBorrowDuration, "Invalid maximum duration" ); require( uint256(_offer.borrowDuration) >= minBorrowDuration, "Invalid minimum duration" ); require( _offer.repayAmount >= _offer.borrowAmount, "Invalid interest rate" ); } function _getPartiesAndData( uint32 _loanId ) internal view returns (address borrower, address lender, LoanDetail memory loan) { uint256 xy3NftId = getLoanState(_loanId).xy3NftId; loan = loanDetails[_loanId]; borrower = IERC721(getAddressProvider().getBorrowerNote()).ownerOf(xy3NftId); lender = IERC721(getAddressProvider().getLenderNote()).ownerOf(xy3NftId); } /** * @dev Get the payoff amount and admin fee * @param _loanDetail - Loan parameters */ function _payoffAndFee( LoanDetail memory _loanDetail ) internal pure returns (uint256 adminFee, uint256 payoffAmount) { uint256 interestDue = _loanDetail.repayAmount - _loanDetail.borrowAmount; adminFee = (interestDue * _loanDetail.adminShare) / HUNDRED_PERCENT; payoffAmount = _loanDetail.repayAmount - adminFee; } /** * @param _offer - Offer parameters * @param _nftId - NFI ID * @param _isCollection - is collection or not * @param _lenderSignature - lender signature * @param _brokerSignature - broker signature */ function _checkBorrow( Offer memory _offer, uint256 _nftId, bool _isCollection, Signature memory _lenderSignature, Signature memory _brokerSignature ) internal view { address _lender = _lenderSignature.signer; require( !_invalidNonce[_lender][_lenderSignature.nonce], "Lender nonce invalid" ); require( hasRole(SIGNER_ROLE, _brokerSignature.signer), "Invalid broker signer" ); require( _offerCancelTimestamp[_lender] < _offer.timestamp, "Offer cancelled" ); _checkSignatures( _offer, _nftId, _isCollection, _lenderSignature, _brokerSignature ); } function _createBorrowNote( address _lender, address _borrower, LoanDetail memory _loanDetail, Signature memory _lenderSignature, CallData memory _extraDeal ) internal returns (uint32) { _invalidNonce[_lender][_lenderSignature.nonce] = true; // Mint ERC721 note to the lender and borrower uint32 loanId = createLoan(_lender, _borrower); // Record loanDetails[loanId] = _loanDetail; emit LoanStarted( loanId, msg.sender, _lenderSignature.signer, _lenderSignature.nonce, _loanDetail, _extraDeal.target, _extraDeal.selector ); return loanId; } function _repay( address payer, uint32 _loanId ) internal loanIsOpen(_loanId) { ( address borrower, address lender, LoanDetail memory loan ) = _getPartiesAndData(_loanId); require(block.timestamp <= _loanMaturityDate(loan), "Loan is expired"); address nftAsset = loan.nftAsset; uint nftId = loan.nftTokenId; beforeRepay(nftAsset, nftId); IERC721(nftAsset).safeTransferFrom(address(this), borrower, nftId); // pay from the payer _repayAsset(payer, borrower, lender, _loanId, loan); _resolveLoanNote(_loanId); delete loanIds[nftAsset][nftId]; afterRepay(nftAsset, nftId); } function _repayAsset( address payer, address borrower, address lender, uint32 _loanId, LoanDetail memory loan ) internal { (uint256 adminFee, uint256 payoffAmount) = _payoffAndFee(loan); IAddressProvider addressProvider = getAddressProvider(); // Paid back to lender IDelegateV3(addressProvider.getTransferDelegate()).erc20Transfer( payer, lender, loan.borrowAsset, payoffAmount ); // Transfer admin fee IDelegateV3(addressProvider.getTransferDelegate()).erc20Transfer( payer, adminFeeReceiver, loan.borrowAsset, adminFee ); emit LoanRepaid( _loanId, borrower, lender, loan.borrowAmount, loan.nftTokenId, payoffAmount, adminFee, loan.nftAsset, loan.borrowAsset ); } /** * @param _offer - Offer parameters * @param _nftId - NFI ID * @param _isCollection - is collection or not * @param _lenderSignature - lender signature * @param _brokerSignature - broker signature */ function _checkSignatures( Offer memory _offer, uint256 _nftId, bool _isCollection, Signature memory _lenderSignature, Signature memory _brokerSignature ) private view { if (_isCollection) { require( SigningUtils.offerSignatureIsValid(_offer, _lenderSignature), "Lender signature is invalid" ); } else { require( SigningUtils.offerSignatureIsValid( _offer, _nftId, _lenderSignature ), "Lender signature is invalid" ); } require( SigningUtils.offerSignatureIsValid( _offer, _nftId, _brokerSignature ), "Signer signature is invalid" ); } /** * @param _offer - Offer parameters * @param _nftId - NFI ID * @param _isCollection - is collection or not */ function _createLoanDetail( Offer memory _offer, uint256 _nftId, bool _isCollection ) internal view returns (LoanDetail memory) { return LoanDetail({ borrowAsset: _offer.borrowAsset, borrowAmount: _offer.borrowAmount, repayAmount: _offer.repayAmount, nftAsset: _offer.nftAsset, nftTokenId: _nftId, loanStart: uint64(block.timestamp), loanDuration: _offer.borrowDuration, adminShare: adminShare, isCollection: _isCollection }); } /** * @param loan - Loan parameters */ function _loanMaturityDate( LoanDetail memory loan ) private pure returns (uint256) { return uint256(loan.loanStart) + uint256(loan.loanDuration); } function _serviceFee(Offer memory offer, uint32 loanId, address target) internal { if (target != address(0)) { IAddressProvider addressProvider = getAddressProvider(); address nftAsset = offer.nftAsset; uint256 borrowAmount = offer.borrowAmount; address borrowAsset = offer.borrowAsset; address serviceFeeAddr = addressProvider.getServiceFee(); uint16 serviceFeeRate = 0; uint256 fee = 0; if(serviceFeeAddr != address(0)) { serviceFeeRate = IServiceFee(serviceFeeAddr).getServiceFee( target, msg.sender, nftAsset ); if(serviceFeeRate > 0) { fee = borrowAmount * serviceFeeRate / HUNDRED_PERCENT; IDelegateV3(addressProvider.getTransferDelegate()).erc20Transfer( msg.sender, adminFeeReceiver, borrowAsset, fee ); } emit ServiceFee(loanId, target, serviceFeeRate, fee); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. * * _Available since v4.1._ */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with _data */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev _Available since v3.1._ */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol) pragma solidity ^0.8.0; import "./ERC1155Receiver.sol"; /** * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. * * @dev _Available since v3.1._ */ contract ERC1155Holder is ERC1155Receiver { function onERC1155Received( address, address, uint256, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol) pragma solidity ^0.8.0; import "../IERC1155Receiver.sol"; import "../../../utils/introspection/ERC165.sol"; /** * @dev _Available since v3.1._ */ abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol) pragma solidity ^0.8.0; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "./extensions/IERC721Metadata.sol"; import "../../utils/Address.sol"; import "../../utils/Context.sol"; import "../../utils/Strings.sol"; import "../../utils/introspection/ERC165.sol"; /** * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including * the Metadata extension, but not including the Enumerable extension, which is available separately as * {ERC721Enumerable}. */ contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { using Address for address; using Strings for uint256; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to owner address mapping(uint256 => address) private _owners; // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from token ID to approved address mapping(uint256 => address) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; /** * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || interfaceId == type(IERC721Metadata).interfaceId || super.supportsInterface(interfaceId); } /** * @dev See {IERC721-balanceOf}. */ function balanceOf(address owner) public view virtual override returns (uint256) { require(owner != address(0), "ERC721: address zero is not a valid owner"); return _balances[owner]; } /** * @dev See {IERC721-ownerOf}. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { address owner = _owners[tokenId]; require(owner != address(0), "ERC721: invalid token ID"); return owner; } /** * @dev See {IERC721Metadata-name}. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev See {IERC721Metadata-symbol}. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev See {IERC721Metadata-tokenURI}. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { _requireMinted(tokenId); string memory baseURI = _baseURI(); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ""; } /** * @dev See {IERC721-approve}. */ function approve(address to, uint256 tokenId) public virtual override { address owner = ERC721.ownerOf(tokenId); require(to != owner, "ERC721: approval to current owner"); require( _msgSender() == owner || isApprovedForAll(owner, _msgSender()), "ERC721: approve caller is not token owner nor approved for all" ); _approve(to, tokenId); } /** * @dev See {IERC721-getApproved}. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { _requireMinted(tokenId); return _tokenApprovals[tokenId]; } /** * @dev See {IERC721-setApprovalForAll}. */ function setApprovalForAll(address operator, bool approved) public virtual override { _setApprovalForAll(_msgSender(), operator, approved); } /** * @dev See {IERC721-isApprovedForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev See {IERC721-transferFrom}. */ function transferFrom( address from, address to, uint256 tokenId ) public virtual override { //solhint-disable-next-line max-line-length require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved"); _transfer(from, to, tokenId); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public virtual override { safeTransferFrom(from, to, tokenId, ""); } /** * @dev See {IERC721-safeTransferFrom}. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory data ) public virtual override { require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner nor approved"); _safeTransfer(from, to, tokenId, data); } /** * @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. * * `data` is additional data, it has no specified format and it is sent in call to `to`. * * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. * implement alternative mechanisms to perform token transfer, such as signature-based. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeTransfer( address from, address to, uint256 tokenId, bytes memory data ) internal virtual { _transfer(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted (`_mint`), * and stop existing when they are burned (`_burn`). */ function _exists(uint256 tokenId) internal view virtual returns (bool) { return _owners[tokenId] != address(0); } /** * @dev Returns whether `spender` is allowed to manage `tokenId`. * * Requirements: * * - `tokenId` must exist. */ function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { address owner = ERC721.ownerOf(tokenId); return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); } /** * @dev Safely mints `tokenId` and transfers it to `to`. * * Requirements: * * - `tokenId` must not exist. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } /** * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. */ function _safeMint( address to, uint256 tokenId, bytes memory data ) internal virtual { _mint(to, tokenId); require( _checkOnERC721Received(address(0), to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer" ); } /** * @dev Mints `tokenId` and transfers it to `to`. * * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible * * Requirements: * * - `tokenId` must not exist. * - `to` cannot be the zero address. * * Emits a {Transfer} event. */ function _mint(address to, uint256 tokenId) internal virtual { require(to != address(0), "ERC721: mint to the zero address"); require(!_exists(tokenId), "ERC721: token already minted"); _beforeTokenTransfer(address(0), to, tokenId); _balances[to] += 1; _owners[tokenId] = to; emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId) internal virtual { address owner = ERC721.ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); // Clear approvals _approve(address(0), tokenId); _balances[owner] -= 1; delete _owners[tokenId]; emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId); } /** * @dev Transfers `tokenId` from `from` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * * Emits a {Transfer} event. */ function _transfer( address from, address to, uint256 tokenId ) internal virtual { require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); _beforeTokenTransfer(from, to, tokenId); // Clear approvals from the previous owner _approve(address(0), tokenId); _balances[from] -= 1; _balances[to] += 1; _owners[tokenId] = to; emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId); } /** * @dev Approve `to` to operate on `tokenId` * * Emits an {Approval} event. */ function _approve(address to, uint256 tokenId) internal virtual { _tokenApprovals[tokenId] = to; emit Approval(ERC721.ownerOf(tokenId), to, tokenId); } /** * @dev Approve `operator` to operate on all of `owner` tokens * * Emits an {ApprovalForAll} event. */ function _setApprovalForAll( address owner, address operator, bool approved ) internal virtual { require(owner != operator, "ERC721: approve to caller"); _operatorApprovals[owner][operator] = approved; emit ApprovalForAll(owner, operator, approved); } /** * @dev Reverts if the `tokenId` has not been minted yet. */ function _requireMinted(uint256 tokenId) internal view virtual { require(_exists(tokenId), "ERC721: invalid token ID"); } /** * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. * The call is not executed if the target address is not a contract. * * @param from address representing the previous owner of the given token ID * @param to target address that will receive the tokens * @param tokenId uint256 ID of the token to be transferred * @param data bytes optional data to send along with the call * @return bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) private returns (bool) { if (to.isContract()) { try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { return retval == IERC721Receiver.onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { revert("ERC721: transfer to non ERC721Receiver implementer"); } else { /// @solidity memory-safe-assembly assembly { revert(add(32, reason), mload(reason)) } } } } else { return true; } } /** * @dev Hook that is called before any token transfer. This includes minting * and burning. * * Calling conditions: * * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, ``from``'s `tokenId` will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: 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 Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.0; import "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address, address, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.3) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } else if (error == RecoverError.InvalidSignatureV) { revert("ECDSA: invalid signature 'v' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } if (v != 27 && v != 28) { return (address(0), RecoverError.InvalidSignatureV); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.1) (utils/cryptography/SignatureChecker.sol) pragma solidity ^0.8.0; import "./ECDSA.sol"; import "../Address.sol"; import "../../interfaces/IERC1271.sol"; /** * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like * Argent and Gnosis Safe. * * _Available since v4.1._ */ library SignatureChecker { /** * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`. * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidSignatureNow( address signer, bytes32 hash, bytes memory signature ) internal view returns (bool) { (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature); if (error == ECDSA.RecoverError.NoError && recovered == signer) { return true; } (bool success, bytes memory result) = signer.staticcall( abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature) ); return (success && result.length == 32 && abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// 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: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "./interfaces/IConfig.sol"; import {MANAGER_ROLE, SIGNER_ROLE} from "./Roles.sol"; bytes32 constant PERMIT_MANAGER_ROLE = keccak256("PERMIT_MANAGER"); /** * @title Configurations for both ERC721 token and ERC20 currency. * @author XY3 g * @dev Implements token and currency management and security functions. */ abstract contract Config is AccessControl, Pausable, ReentrancyGuard, IConfig { /** * @dev Admin fee receiver, can be updated by admin. */ address public adminFeeReceiver; /** * @dev Borrow durations, can be updated by admin. */ uint256 public override maxBorrowDuration = 365 days; uint256 public override minBorrowDuration = 1 days; /** * @dev The fee percentage is taken by the contract admin's as a * fee, which is from the the percentage of lender earned. * Unit is hundreths of percent, like adminShare/10000. */ uint16 public override adminShare = 25; uint16 public constant HUNDRED_PERCENT = 10000; /** * @dev The permitted ERC20 currency for this contract. */ mapping(address => bool) private erc20Permits; /** * @dev The permitted ERC721 token or collections for this contract. */ mapping(address => bool) private erc721Permits; /** * @dev The permitted agent for this contract, index is target + selector; */ mapping(address => mapping(bytes4 => bool)) private agentPermits; /** * @dev Address Provider */ address private addressProvider; /** * @dev Init the contract admin. * @param _admin - Initial admin of this contract and fee receiver. */ constructor(address _admin, address _addressProvider) { _grantRole(DEFAULT_ADMIN_ROLE, _admin); _setRoleAdmin(MANAGER_ROLE, DEFAULT_ADMIN_ROLE); _setRoleAdmin(SIGNER_ROLE, DEFAULT_ADMIN_ROLE); adminFeeReceiver = _admin; addressProvider = _addressProvider; } /** * @dev Sets contract to be stopped state. */ function pause() external onlyRole(MANAGER_ROLE) { _pause(); } /** * @dev Restore the contract from stopped state. */ function unpause() external onlyRole(MANAGER_ROLE) { _unpause(); } /** * @dev Update the maxBorrowDuration by manger role. * @param _newMaxBorrowDuration - The new max borrow duration, measured in seconds. */ function updateMaxBorrowDuration( uint256 _newMaxBorrowDuration ) external override onlyRole(MANAGER_ROLE) { require(_newMaxBorrowDuration >= minBorrowDuration, "Invalid duration"); if (maxBorrowDuration != _newMaxBorrowDuration) { maxBorrowDuration = _newMaxBorrowDuration; emit MaxBorrowDurationUpdated(_newMaxBorrowDuration); } } /** * @dev Update the minBorrowDuration by manger role. * @param _newMinBorrowDuration - The new min borrow duration, measured in seconds. */ function updateMinBorrowDuration( uint256 _newMinBorrowDuration ) external override onlyRole(MANAGER_ROLE) { require(_newMinBorrowDuration <= maxBorrowDuration, "Invalid duration"); if (minBorrowDuration != _newMinBorrowDuration) { minBorrowDuration = _newMinBorrowDuration; emit MinBorrowDurationUpdated(_newMinBorrowDuration); } } /** * @notice Update the adminShaer by manger role. The newAdminFee can be bigger than 10,000. * @param _newAdminShare - The new admin fee measured in basis points. */ function updateAdminShare( uint16 _newAdminShare ) external override onlyRole(MANAGER_ROLE) { require(_newAdminShare <= HUNDRED_PERCENT, "basis points > 10000"); if (adminShare != _newAdminShare) { adminShare = _newAdminShare; emit AdminFeeUpdated(_newAdminShare); } } /** * @dev Update the adminFeeReceiver by manger role. * @param _newAdminFeeReceiver - The new admin fee receiver address. */ function updateAdminFeeReceiver( address _newAdminFeeReceiver ) external override onlyRole(MANAGER_ROLE) { require(_newAdminFeeReceiver != address(0), "Invalid receiver address"); if (adminFeeReceiver != _newAdminFeeReceiver) { adminFeeReceiver = _newAdminFeeReceiver; emit AdminFeeReceiverUpdated(adminFeeReceiver); } } /** * @dev Set or remove the ERC20 currency permit by manger role. * @param _erc20s - The addresses of the ERC20 currencies. * @param _permits - The new statuses of the currencies. */ function setERC20Permits( address[] memory _erc20s, bool[] memory _permits ) external override onlyRole(MANAGER_ROLE) { require( _erc20s.length == _permits.length, "address and permits length mismatch" ); for (uint256 i = 0; i < _erc20s.length; i++) { _setERC20Permit(_erc20s[i], _permits[i]); } } /** * @dev Set or remove the ERC721 token permit by manger role. * @param _erc721s - The addresses of the ERC721 collection. * @param _permits - The new statuses of the collection. */ function setERC721Permits( address[] memory _erc721s, bool[] memory _permits ) external override onlyRole(MANAGER_ROLE) { require( _erc721s.length == _permits.length, "address and permits length mismatch" ); for (uint256 i = 0; i < _erc721s.length; i++) { _setERC721Permit(_erc721s[i], _permits[i]); } } /** * @dev Set or remove the ERC721 token permit by manger role. * @param _agents - The addresses of the ERC721 collection. * @param _permits - The new statuses of the collection. */ function setAgentPermits( address[] memory _agents, bytes4[] memory _selectors, bool[] memory _permits ) external override onlyRole(PERMIT_MANAGER_ROLE) { require( _agents.length == _permits.length && _selectors.length == _permits.length, "address and permits length mismatch" ); for (uint256 i = 0; i < _agents.length; i++) { _setAgentPermit(_agents[i], _selectors[i], _permits[i]); } } /** * @dev Get the permit of the ERC20 token, public reading. * @param _erc20 - The address of the ERC20 token. * @return The ERC20 permit boolean value */ function getERC20Permit( address _erc20 ) public view override returns (bool) { return erc20Permits[_erc20]; } /** * @dev Get the permit of the ERC721 collection, public reading. * @param _erc721 - The address of the ERC721 collection. * @return The ERC721 collection permit boolean value */ function getERC721Permit( address _erc721 ) public view override returns (bool) { return erc721Permits[_erc721]; } /** * @dev Get the permit of agent, public reading. * @param _agent - The address of the agent. * @return The agent permit boolean value */ function getAgentPermit( address _agent, bytes4 _selector ) public view override returns (bool) { return agentPermits[_agent][_selector]; } function getAddressProvider() public view override returns (IAddressProvider) { return IAddressProvider(addressProvider); } /** * @dev Permit or remove ERC20 currency. * @param _erc20 - The operated ERC20 currency address. * @param _permit - The currency new status, permitted or not. */ function _setERC20Permit(address _erc20, bool _permit) internal { require(_erc20 != address(0), "erc20 is zero address"); erc20Permits[_erc20] = _permit; emit ERC20Permit(_erc20, _permit); } /** * @dev Permit or remove ERC721 token. * @param _erc721 - The operated ERC721 token address. * @param _permit - The token new status, permitted or not. */ function _setERC721Permit(address _erc721, bool _permit) internal { require(_erc721 != address(0), "erc721 is zero address"); erc721Permits[_erc721] = _permit; emit ERC721Permit(_erc721, _permit); } /** * @dev Permit or remove ERC721 token. * @param _agent - The operated ERC721 token address. * @param _permit - The token new status, permitted or not. */ function _setAgentPermit(address _agent, bytes4 _selector, bool _permit) internal { require(_agent != address(0) && _selector != bytes4(0), "agent is zero address"); agentPermits[_agent][_selector] = _permit; emit AgentPermit(_agent, _selector, _permit); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; /** * @title Loan data types * @author XY3 */ /** * @dev Signature data for both lender & broker. * @param signer - The address of the signer. * @param nonce User offer nonce. * @param expiry The signature expires date. * @param signature The ECDSA signature, singed off-chain. */ struct Signature { uint256 nonce; uint256 expiry; address signer; bytes signature; } /** * @dev Saved the loan related data. * * @param borrowAmount - The original amount of money transferred from lender to borrower. * @param repayAmount - The maximum amount of money that the borrower would be required to retrieve their collateral. * @param nftTokenId - The ID within the Xy3 NFT. * @param borrowAsset - The ERC20 currency address. * @param loanDuration - The alive time of loan in seconds. * @param adminShare - The admin fee percent from paid loan. * @param loanStart - The block.timestamp the loan start in seconds. * @param nftAsset - The address of the the Xy3 NFT contract. * @param isCollection - The accepted offer is a collection or not. */ struct LoanDetail { uint256 borrowAmount; uint256 repayAmount; uint256 nftTokenId; address borrowAsset; uint32 loanDuration; uint16 adminShare; uint64 loanStart; address nftAsset; bool isCollection; } /** * @dev The offer made by the lender. Used as parameter on borrow. * * @param borrowAsset - The address of the ERC20 currency. * @param borrowAmount - The original amount of money transferred from lender to borrower. * @param repayAmount - The maximum amount of money that the borrower would be required to retrieve their collateral. * @param nftAsset - The address of the the Xy3 NFT contract. * @param borrowDuration - The alive time of borrow in seconds. * @param timestamp - For timestamp cancel * @param extra - Extra bytes for only signed check */ struct Offer { uint256 borrowAmount; uint256 repayAmount; address nftAsset; uint32 borrowDuration; address borrowAsset; uint256 timestamp; bytes extra; } /** * @dev The data for borrow external call. * * @param target - The target contract address. * @param selector - The target called function. * @param data - The target function call data with parameters only. * @param referral - The referral code for borrower. * */ struct CallData { address target; bytes4 selector; bytes data; uint256 referral; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; import "@openzeppelin/contracts/access/AccessControl.sol"; import {INTERCEPTOR_ROLE, MANAGER_ROLE} from "./Roles.sol"; uint constant BORROW_QUEUE = 0; uint constant REPAY_QUEUE = 1; uint constant LIQUIDATE_QUEUE = 2; uint constant QUEUE_LEN = 3; interface IInterceptor { function beforeEvent( uint _eventId, address _nftAsset, uint _tokenId ) external; function afterEvent( uint _eventId, address _nftAsset, uint _tokenId ) external; } abstract contract InterceptorManager is AccessControl { event UpdageInterceptor(uint256 indexed queueId, address indexed nftAsset, uint256 tokenId, address interceptor, bool add); event ExecuteInterceptor(uint256 indexed queueId, address indexed nftAsset, uint256 tokenId, address interceptor, bool before); mapping(address => mapping(uint256 => address[]))[QUEUE_LEN] private _interceptors; function addInterceptor( uint _queueId, address _nftAsset, uint _tokenId ) external onlyRole(INTERCEPTOR_ROLE) { require(_queueId < QUEUE_LEN, "Invalid queueId"); address interceptor = msg.sender; address[] storage interceptors = _interceptors[_queueId][_nftAsset][ _tokenId ]; for (uint i = 0; i < interceptors.length; i++) { if (interceptors[i] == interceptor) { return; } } interceptors.push(interceptor); emit UpdageInterceptor(_queueId, _nftAsset, _tokenId, interceptor, true); } function deleteInterceptor( uint _queueId, address _nftAsset, uint _tokenId ) external onlyRole(INTERCEPTOR_ROLE) { address interceptor = msg.sender; address[] storage interceptors = _interceptors[_queueId][_nftAsset][ _tokenId ]; uint256 findIndex = 0; for (; findIndex < interceptors.length; findIndex++) { if (interceptors[findIndex] == interceptor) { break; } } if (findIndex != _interceptors.length) { _deleteInterceptor(_queueId, _nftAsset, _tokenId, findIndex); } } function purgeInterceptor( uint256 _queueId, address nftAsset, uint256[] calldata tokenIds, address interceptor ) public onlyRole(MANAGER_ROLE) { for (uint256 i = 0; i < tokenIds.length; i++) { address[] storage interceptors = _interceptors[_queueId][nftAsset][ tokenIds[i] ]; for ( uint256 findIndex = 0; findIndex < interceptors.length; findIndex++ ) { if (interceptors[findIndex] == interceptor) { _deleteInterceptor( _queueId, nftAsset, tokenIds[i], findIndex ); break; } } } } function getInterceptors( uint _queueId, address nftAsset, uint256 tokenId ) public view returns (address[] memory) { return _interceptors[_queueId][nftAsset][tokenId]; } function _deleteInterceptor( uint queueId, address nftAsset, uint256 tokenId, uint256 findIndex ) internal { address[] storage interceptors = _interceptors[queueId][nftAsset][ tokenId ]; address findInterceptor = interceptors[findIndex]; uint256 lastInterceptorIndex = interceptors.length - 1; // When the token to delete is the last item, the swap operation is unnecessary. // Move the last interceptor to the slot of the to-delete interceptor if (findIndex < lastInterceptorIndex) { address lastInterceptorAddr = interceptors[lastInterceptorIndex]; interceptors[findIndex] = lastInterceptorAddr; } interceptors.pop(); emit UpdageInterceptor(queueId, nftAsset, tokenId, findInterceptor, false); } function executeInterceptors( uint queueId, bool before, address nftAsset, uint tokenId ) internal { address[] memory interceptors = _interceptors[queueId][nftAsset][ tokenId ]; for (uint i = 0; i < interceptors.length; i++) { if (before) { IInterceptor(interceptors[i]).beforeEvent( queueId, nftAsset, tokenId ); } else { IInterceptor(interceptors[i]).afterEvent( queueId, nftAsset, tokenId ); } emit ExecuteInterceptor(queueId, nftAsset, tokenId, interceptors[i], before); } } function beforeBorrow(address nftAsset, uint tokenId) internal { executeInterceptors(BORROW_QUEUE, true, nftAsset, tokenId); } function beforeRepay(address nftAsset, uint tokenId) internal { executeInterceptors(REPAY_QUEUE, true, nftAsset, tokenId); } function beforeLiquidate(address nftAsset, uint tokenId) internal { executeInterceptors(LIQUIDATE_QUEUE, true, nftAsset, tokenId); } function afterBorrow(address nftAsset, uint tokenId) internal { executeInterceptors(BORROW_QUEUE, false, nftAsset, tokenId); } function afterRepay(address nftAsset, uint tokenId) internal { executeInterceptors(REPAY_QUEUE, false, nftAsset, tokenId); } function afterLiquidate(address nftAsset, uint tokenId) internal { executeInterceptors(LIQUIDATE_QUEUE, false, nftAsset, tokenId); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; bytes32 constant ADDR_LENDER_NOTE = "LENDER_NOTE"; bytes32 constant ADDR_BORROWER_NOTE = "BORROWER_NOTE"; bytes32 constant ADDR_FLASH_EXEC_PERMITS = "FLASH_EXEC_PERMITS"; bytes32 constant ADDR_TRANSFER_DELEGATE = "TRANSFER_DELEGATE"; bytes32 constant ADDR_SERVICE_FEE = "SERVICE_FEE"; bytes32 constant ADDR_XY3 = "XY3"; interface IAddressProvider { function getAddress(bytes32 id) external view returns (address); function getXY3() external view returns (address); function getLenderNote() external view returns (address); function getBorrowerNote() external view returns (address); function getFlashExecPermits() external view returns (address); function getTransferDelegate() external view returns (address); function getServiceFee() external view returns (address); function setAddress(bytes32 id, address newAddress) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; import {IAddressProvider} from "./IAddressProvider.sol"; interface IConfig { /** * @notice This event is emitted when admin fee percent changed. * @param newAdminFee - The new admin fee measured in basis points. */ event AdminFeeUpdated(uint16 newAdminFee); /** * @notice This event is emitted when the max duration of all borrows. * @param newMaxBorrowDuration - The new max duration in seconds. */ event MaxBorrowDurationUpdated(uint256 newMaxBorrowDuration); /** * @notice This event is emitted when the min duration of all borrows. * @param newMinBorrowDuration - The new min duration. */ event MinBorrowDurationUpdated(uint256 newMinBorrowDuration); /** * @notice This event is emitted when the ERC20 permit is set. * @param erc20Contract - Address of the ERC20 token. * @param isPermitted - ERC20 permit bool value. */ event ERC20Permit(address indexed erc20Contract, bool isPermitted); /** * @notice This event is emitted when the ERC721 permit is set. * @param erc721Contract - Address of the ERC721 collection address. * @param isPermitted - ERC721 permit bool value. */ event ERC721Permit(address indexed erc721Contract, bool isPermitted); /** * @notice This event is emitted when the agent permit is set. * @param agent - Address of the agent. * @param isPermitted - Agent permit bool value. */ event AgentPermit(address indexed agent, bytes4 selector, bool isPermitted); /** * @notice This event is emitted when the ERC20 approved to user. * @param user - User account. * @param erc20Contract - Address of the ERC20 token. * @param amount - ERC20 amount. */ event ERC20Approve(address indexed user, address indexed erc20Contract, uint256 amount); /** * @notice This event is emitted when the ERC721 permit is set. * @param user - User account. * @param erc721Contract - Address of the ERC721 collection address. * @param isPermitted - ERC721 permit bool value. */ event ERC721Approve(address indexed user, address indexed erc721Contract, bool isPermitted); /** * @notice This event is emitted when the admin fee receiver address is changed. */ event AdminFeeReceiverUpdated(address); /** * @notice Get the current max allowed borrow duration. */ function maxBorrowDuration() external view returns (uint256); /** * @notice Get the current min allowed borrow duration. */ function minBorrowDuration() external view returns (uint256); /** * @notice Get percent of admin fee charged from lender earned. */ function adminShare() external view returns (uint16); /** * @notice Update max borrow duration * @param _newMaxBorrowDuration - The new max duration. */ function updateMaxBorrowDuration(uint256 _newMaxBorrowDuration) external; /** * @notice Update min borrow duration * @param _newMinBorrowDuration - The new min duration. */ function updateMinBorrowDuration(uint256 _newMinBorrowDuration) external; /** * @notice Update admin fee. * @param _newAdminShare - The new admin fee. */ function updateAdminShare(uint16 _newAdminShare) external; /** * @notice Update admin fee receiver. * @param _newAdminFeeReceiver - The new admin fee receiver address. */ function updateAdminFeeReceiver(address _newAdminFeeReceiver) external; /** * @notice Get the erc20 token permitted status. * @param _erc20 - The address of the ERC20 token. * @return The ERC20 permit boolean value */ function getERC20Permit(address _erc20) external view returns (bool); /** * @notice Get the erc721 token permitted status. * @param _erc721 - The address of the ERC721 collection. * @return The ERC721 collection permit boolean value */ function getERC721Permit(address _erc721) external view returns (bool); /** * @dev Get the permit of agent, public reading. * @param _agent - The address of the agent. * @return The agent permit boolean value */ function getAgentPermit(address _agent, bytes4 _selector) external view returns (bool); /** * @notice Update a set of the ERC20 tokens permitted status. * @param _erc20s - The addresses of the ERC20 currencies. * @param _permits - The new statuses of the currencies. */ function setERC20Permits(address[] memory _erc20s, bool[] memory _permits) external; /** * @notice Update a set of the ERC721 collection permitted status. * @param _erc721s - The addresses of the ERC721 collection. * @param _permits - The new statuses of the collection. */ function setERC721Permits(address[] memory _erc721s, bool[] memory _permits) external; function setAgentPermits(address[] memory _agents, bytes4[] memory _selectors, bool[] memory _permits) external; function getAddressProvider() external view returns (IAddressProvider); }
// SPDX-License-Identifier: Unlicensed pragma solidity 0.8.4; pragma abicoder v2; interface IDelegateV3 { function erc20Transfer( address sender, address receiver, address token, uint256 amount ) external; function erc721Transfer( address sender, address receiver, address token, uint256 tokenId )external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; interface IFlashExecPermits { event AddPermit(address indexed target, bytes4 indexed selector); event RemovePermit(address indexed target, bytes4 indexed selector); function isPermitted(address target, bytes4 selector) external returns (bool); function addPermit(address target, bytes4 selector) external; function removePermit(address target, bytes4 selector) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; interface ILoanStatus { /** * @dev loan status */ enum StatusType { NOT_EXISTS, NEW, RESOLVED } /** * @dev load status record structure */ struct LoanState { uint64 xy3NftId; StatusType status; } /** * @dev get load status * @param _loanId load ID */ function getLoanState(uint32 _loanId) external view returns (LoanState memory); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; interface IServiceFee { function setServiceFee( address _target, address _sender, address _nftAsset, uint16 _fee ) external; function clearServiceFee( address _target, address _sender, address _nftAsset ) external; function getServiceFee( address _target, address _sender, address _nftAsset ) external view returns (uint16); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; import "../DataTypes.sol"; interface IXY3 { /** * @dev This event is emitted when calling acceptOffer(), need both the lender and borrower to approve their ERC721 and ERC20 contracts to XY3. * * @param loanId - A unique identifier for the loan. * @param borrower - The address of the borrower. * @param lender - The address of the lender. * @param nonce - nonce of the lender's offer signature */ event LoanStarted( uint32 indexed loanId, address indexed borrower, address indexed lender, uint256 nonce, LoanDetail loanDetail, address target, bytes4 selector ); /** * @dev This event is emitted when a borrower successfully repaid the loan. * * @param loanId - A unique identifier for the loan. * @param borrower - The address of the borrower. * @param lender - The address of the lender. * @param borrowAmount - The original amount of money transferred from lender to borrower. * @param nftTokenId - The ID of the borrowd. * @param repayAmount The amount of ERC20 that the borrower paid back. * @param adminFee The amount of interest paid to the contract admins. * @param nftAsset - The ERC721 contract of the NFT collateral * @param borrowAsset - The ERC20 currency token. */ event LoanRepaid( uint32 indexed loanId, address indexed borrower, address indexed lender, uint256 borrowAmount, uint256 nftTokenId, uint256 repayAmount, uint256 adminFee, address nftAsset, address borrowAsset ); /** * @dev This event is emitted when cancelByNonce called. * @param lender - The address of the lender. * @param nonce - nonce of the lender's offer signature */ event NonceCancelled(address lender, uint256 nonce); /** * @dev This event is emitted when cancelByTimestamp called * @param lender - The address of the lender. * @param timestamp - cancelled timestamp */ event TimeStampCancelled(address lender, uint256 timestamp); /** * @dev This event is emitted when liquidates happened * @param loanId - A unique identifier for this particular loan. * @param borrower - The address of the borrower. * @param lender - The address of the lender. * @param borrowAmount - The original amount of money transferred from lender to borrower. * @param nftTokenId - The ID of the borrowd. * @param loanMaturityDate - The unix time (measured in seconds) that the loan became due and was eligible for liquidation. * @param loanLiquidationDate - The unix time (measured in seconds) that liquidation occurred. * @param nftAsset - The ERC721 contract of the NFT collateral */ event LoanLiquidated( uint32 indexed loanId, address indexed borrower, address indexed lender, uint256 borrowAmount, uint256 nftTokenId, uint256 loanMaturityDate, uint256 loanLiquidationDate, address nftAsset ); event BorrowRefferal( uint32 indexed loanId, address indexed borrower, uint256 referral ); event FlashExecute( uint32 indexed loanId, address nft, uint256 nftTokenId, address flashTarget ); event ServiceFee(uint32 indexed loanId, address indexed target, uint16 serviceFeeRate, uint256 feeAmount); /** * @dev Get the load info by loadId */ function loanDetails( uint32 ) external view returns ( uint256, uint256, uint256, address, uint32, uint16, uint64, address, bool ); function loanIds( address collection, uint256 tokenId ) external view returns (uint32); /** * @dev The borrower accept a lender's offer to create a loan. * * @param _offer - The offer made by the lender. * @param _nftId - The ID * @param _isCollectionOffer - Wether the offer is a collection offer. * @param _lenderSignature - The lender's signature. * @param _brokerSignature - The broker's signature. * @param _extraDeal - Create a new loan by getting a NFT colleteral from external contract call. * The external contract can be lending market or deal market, specially included the restricted repay of myself. * But should not be the Xy3Nft.mint, though this contract maybe have the permission. */ function borrow( Offer memory _offer, uint256 _nftId, bool _isCollectionOffer, Signature memory _lenderSignature, Signature memory _brokerSignature, CallData memory _extraDeal ) external returns (uint32); /** * @dev A lender or a borrower to cancel all off-chain orders signed that contain this nonce. * @param _nonce - User nonce */ function cancelByNonce(uint256 _nonce) external; /** * @dev A borrower cancel all offers with timestamp before the _timestamp parameter. * @param _timestamp - cancelled timestamp */ function cancelByTimestamp(uint256 _timestamp) external; /** * @notice Check a nonce has been used or not * @param _user - The user address. * @param _nonce - The order Id * * @return A bool for used or not. */ function getNonceUsed( address _user, uint256 _nonce ) external view returns (bool); /** * @dev This function can be used to view the last cancel timestamp a borrower has set. * @param _user User address * @return The cancel timestamp */ function getTimestampCancelled( address _user ) external view returns (uint256); /** * @dev Public function for anyone to repay a loan, and return the NFT token to origin borrower. * @param _loanId The loan Id. */ function repay(uint32 _loanId) external; /** * @dev Lender ended the load which not paid by borrow and expired. * @param _loanId The loan Id. */ function liquidate(uint32 _loanId) external; /** * @dev Allow admin to claim airdroped erc20 tokens */ function adminClaimErc20( address _to, address[] memory tokens, uint256[] memory amounts ) external; /** * @dev Allow admin to claim airdroped erc721 tokens */ function adminClaimErc721( address _to, address[] memory tokens, uint256[] memory tokenIds ) external; /** * @dev Allow admin to claim airdroped erc1155 tokens */ function adminClaimErc1155( address _to, address[] memory tokens, uint256[] memory tokenIds, uint256[] memory amounts ) external; /** * @dev The amount of ERC20 currency for the loan. * @param _loanId A unique identifier for this particular loan. * @return The amount of ERC20 currency. */ function getRepayAmount(uint32 _loanId) external returns (uint256); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; import "./Xy3Nft.sol"; import "./interfaces/ILoanStatus.sol"; import "./interfaces/IConfig.sol"; /** * @title LoanStatus * @author XY3 */ contract LoanStatus is ILoanStatus { event UpdateStatus( uint32 indexed loanId, uint64 indexed xy3NftId, StatusType newStatus ); uint32 public totalNumLoans = 10000; mapping(uint32 => LoanState) private loanStatus; /** * @dev XY3 mint a NFT to the lender as a ticket for collateral * @param _lender Lender address * @param _borrower Borrower address */ function createLoan(address _lender, address _borrower) internal returns (uint32) { // skip 0, loanIds start from 1 totalNumLoans += 1; uint64 xy3NftId = uint64( uint256(keccak256(abi.encodePacked(address(this), totalNumLoans))) ); LoanState memory newLoan = LoanState({ status: StatusType.NEW, xy3NftId: xy3NftId }); (Xy3Nft borrowerNote, Xy3Nft lenderNote) = getNotes(); // Mint an ERC721 to the lender as the ticket for the collateral lenderNote.mint( _lender, xy3NftId, abi.encode(totalNumLoans) ); // Mint an ERC721 to the borrower as the ticket for the collateral borrowerNote.mint( _borrower, xy3NftId, abi.encode(totalNumLoans) ); loanStatus[totalNumLoans] = newLoan; emit UpdateStatus(totalNumLoans, xy3NftId, StatusType.NEW); return totalNumLoans; } /** * @dev XY3 close the loan when load paid * Update the loan status to be RESOLVED and burns Xy3Nft token. * @param _loanId - Id of loan */ function resolveLoan(uint32 _loanId) internal { LoanState storage loan = loanStatus[_loanId]; require(loan.status == StatusType.NEW, "Loan is not a new one"); loan.status = StatusType.RESOLVED; (Xy3Nft borrowerNote, Xy3Nft lenderNote) = getNotes(); lenderNote.burn(loan.xy3NftId); borrowerNote.burn(loan.xy3NftId); emit UpdateStatus(_loanId, loan.xy3NftId, StatusType.RESOLVED); delete loanStatus[_loanId]; } /** * @dev Get loan state for a given id. * @param _loanId The given load Id. */ function getLoanState(uint32 _loanId) public view override returns (LoanState memory) { return loanStatus[_loanId]; } function getNotes() private view returns(Xy3Nft borrowerNote, Xy3Nft lenderNote) { IAddressProvider addressProvider = IConfig(address(this)).getAddressProvider(); borrowerNote = Xy3Nft(addressProvider.getBorrowerNote()); lenderNote = Xy3Nft(addressProvider.getLenderNote()); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; /** * @dev Role for interceptor contracts */ bytes32 constant INTERCEPTOR_ROLE = keccak256("INTERCEPTOR"); /** * @dev Role for configration management. */ bytes32 constant MANAGER_ROLE = keccak256("MANAGER"); /** * @dev Role for singed, used by the main contract. */ bytes32 constant SIGNER_ROLE = keccak256("SIGNER"); /** * @dev Role for calling transfer delegator */ bytes32 constant DELEGATION_CALLER_ROLE = keccak256("DELEGATION_CALLER"); /** * @dev Role for xy3nft minter */ bytes32 constant MINTER_ROLE = keccak256("MINTER"); /** * @dev Role for those can call exchange contracts */ bytes32 constant EXCHANGE_CALLER_ROLE = keccak256("EXCHANGE_CALLER"); /** * @dev Role for those can be called by FlashTrade */ bytes32 constant FLASH_TRADE_CALLEE_ROLE = keccak256("FLASH_TRADE_CALLEE");
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; import {Offer, Signature} from "../DataTypes.sol"; import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; /** * @title SigningUtils * @author XY3 * @notice Helper functions for signature. */ library SigningUtils { /** * @dev Get the current chain ID. */ function getChainID() internal view returns (uint256 id) { assembly { id := chainid() } } /** * @dev check signature without nftId. * @param _offer The offer data * @param _nftId The NFT Id * @param _signature The signature data */ function offerSignatureIsValid( Offer memory _offer, uint256 _nftId, Signature memory _signature ) public view returns(bool) { require(block.timestamp <= _signature.expiry, "Signature expired"); if (_signature.signer == address(0)) { return false; } else { bytes32 message = keccak256( abi.encodePacked(getEncodedOffer(_offer), _nftId, getEncodedSignature(_signature), address(this), getChainID()) ); return SignatureChecker.isValidSignatureNow( _signature.signer, ECDSA.toEthSignedMessageHash(message), _signature.signature ); } } /** * @dev check signature without nftId. * @param _offer The offer data * @param _signature - The signature data */ function offerSignatureIsValid( Offer memory _offer, Signature memory _signature ) public view returns (bool) { require(block.timestamp <= _signature.expiry, "Signature has expired"); if (_signature.signer == address(0)) { return false; } else { bytes32 message = keccak256( abi.encodePacked(getEncodedOffer(_offer), getEncodedSignature(_signature), address(this), getChainID()) ); return SignatureChecker.isValidSignatureNow( _signature.signer, ECDSA.toEthSignedMessageHash(message), _signature.signature ); } } /** * @dev Helper function. */ function getEncodedOffer(Offer memory _offer) internal pure returns (bytes memory data) { data = abi.encodePacked( _offer.borrowAsset, _offer.borrowAmount, _offer.repayAmount, _offer.nftAsset, _offer.borrowDuration, _offer.timestamp, _offer.extra ); } /** * @dev Helper function. */ function getEncodedSignature(Signature memory _signature) internal pure returns (bytes memory) { return abi.encodePacked(_signature.signer, _signature.nonce, _signature.expiry); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.4; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; /** * @title Xy3Nft * @author XY3 * @dev ERC721 token for promissory note. */ contract Xy3Nft is ERC721, AccessControl { using Strings for uint256; /** * @dev Record the data for findig the loan linked to a Xy3. */ struct Ticket { uint256 loanId; address minter; } /** * @dev base URI for token */ string public baseURI; /* * @dev map Xy3Id to Ticket */ mapping(uint256 => Ticket) public tickets; /** * @dev Role for token URI and mint */ bytes32 public constant MINTER_ROLE = keccak256("MINTER"); bytes32 public constant MANAGER_ROLE = keccak256("MANAGER"); /** * @dev Init the contract and set the default admin role. * * @param _admin Admin role account * @param _name Xy3NFT name * @param _symbol Xy3NFT symbol * @param _customBaseURI Xy3NFT Base URI */ constructor( address _admin, string memory _name, string memory _symbol, string memory _customBaseURI ) ERC721(_name, _symbol) { _setupRole(DEFAULT_ADMIN_ROLE, _admin); _setBaseURI(_customBaseURI); } /** * @dev Burn token by minter. * @param _tokenId The ERC721 token Id */ function burn(uint256 _tokenId) external onlyRole(MINTER_ROLE) { delete tickets[_tokenId]; _burn(_tokenId); } /** * @dev Mint a new token and assigned to receiver * * @param _to The receiver address * @param _tokenId The token ID of the Xy3 * @param _data The first 32 bytes is an integer for the loanId in Xy3 */ function mint( address _to, uint256 _tokenId, bytes calldata _data ) external onlyRole(MINTER_ROLE) { require(_data.length > 0, "no data"); uint256 loanId = abi.decode(_data, (uint256)); tickets[_tokenId] = Ticket({loanId: loanId, minter: msg.sender}); _safeMint(_to, _tokenId, _data); } /** * @dev Set baseURI by URI manager * @param _customBaseURI - Base URI for the Xy3NFT */ function setBaseURI(string memory _customBaseURI) external onlyRole(MANAGER_ROLE) { _setBaseURI(_customBaseURI); } /** * @dev Defined by IERC165 * @param _interfaceId The queried selector Id */ function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC721, AccessControl) returns (bool) { return super.supportsInterface(_interfaceId); } /** * @dev Check the token exist or not. * @param _tokenId The ERC721 token id */ function exists(uint256 _tokenId) external view returns (bool) { return _exists(_tokenId); } /** * @dev Get the current chain ID. */ function _getChainID() internal view returns (uint256 id) { assembly { id := chainid() } } /** * @dev Base URI for concat {tokenURI} by `baseURI` and `tokenId`. */ function _baseURI() internal view virtual override returns (string memory) { return baseURI; } /** * @dev Set baseURI, internal used. * @param _customBaseURI The new URI. */ function _setBaseURI(string memory _customBaseURI) internal virtual { baseURI = bytes(_customBaseURI).length > 0 ? string(abi.encodePacked(_customBaseURI, _getChainID().toString(), "/")) : ""; } }
{ "optimizer": { "enabled": true, "runs": 99 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": { "contracts/utils/SigningUtils.sol": { "SigningUtils": "0x6a7acf3feb58fcf15f74b73391c78a879f7c9e35" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_addressProvider","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"AdminFeeReceiverUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"newAdminFee","type":"uint16"}],"name":"AdminFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"agent","type":"address"},{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bool","name":"isPermitted","type":"bool"}],"name":"AgentPermit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"loanId","type":"uint32"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"referral","type":"uint256"}],"name":"BorrowRefferal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"erc20Contract","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20Approve","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"erc20Contract","type":"address"},{"indexed":false,"internalType":"bool","name":"isPermitted","type":"bool"}],"name":"ERC20Permit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"erc721Contract","type":"address"},{"indexed":false,"internalType":"bool","name":"isPermitted","type":"bool"}],"name":"ERC721Approve","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"erc721Contract","type":"address"},{"indexed":false,"internalType":"bool","name":"isPermitted","type":"bool"}],"name":"ERC721Permit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"queueId","type":"uint256"},{"indexed":true,"internalType":"address","name":"nftAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"interceptor","type":"address"},{"indexed":false,"internalType":"bool","name":"before","type":"bool"}],"name":"ExecuteInterceptor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"loanId","type":"uint32"},{"indexed":false,"internalType":"address","name":"nft","type":"address"},{"indexed":false,"internalType":"uint256","name":"nftTokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"flashTarget","type":"address"}],"name":"FlashExecute","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"loanId","type":"uint32"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nftTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loanMaturityDate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loanLiquidationDate","type":"uint256"},{"indexed":false,"internalType":"address","name":"nftAsset","type":"address"}],"name":"LoanLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"loanId","type":"uint32"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nftTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"repayAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"adminFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"nftAsset","type":"address"},{"indexed":false,"internalType":"address","name":"borrowAsset","type":"address"}],"name":"LoanRepaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"loanId","type":"uint32"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"components":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"uint256","name":"nftTokenId","type":"uint256"},{"internalType":"address","name":"borrowAsset","type":"address"},{"internalType":"uint32","name":"loanDuration","type":"uint32"},{"internalType":"uint16","name":"adminShare","type":"uint16"},{"internalType":"uint64","name":"loanStart","type":"uint64"},{"internalType":"address","name":"nftAsset","type":"address"},{"internalType":"bool","name":"isCollection","type":"bool"}],"indexed":false,"internalType":"struct LoanDetail","name":"loanDetail","type":"tuple"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"LoanStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxBorrowDuration","type":"uint256"}],"name":"MaxBorrowDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMinBorrowDuration","type":"uint256"}],"name":"MinBorrowDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"NonceCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"loanId","type":"uint32"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint16","name":"serviceFeeRate","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"ServiceFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"lender","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"TimeStampCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"queueId","type":"uint256"},{"indexed":true,"internalType":"address","name":"nftAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"interceptor","type":"address"},{"indexed":false,"internalType":"bool","name":"add","type":"bool"}],"name":"UpdageInterceptor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"loanId","type":"uint32"},{"indexed":true,"internalType":"uint64","name":"xy3NftId","type":"uint64"},{"indexed":false,"internalType":"enum ILoanStatus.StatusType","name":"newStatus","type":"uint8"}],"name":"UpdateStatus","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HUNDRED_PERCENT","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueId","type":"uint256"},{"internalType":"address","name":"_nftAsset","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"addInterceptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"adminClaimErc1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"adminClaimErc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"adminClaimErc721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"adminFeeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"adminShare","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"address","name":"nftAsset","type":"address"},{"internalType":"uint32","name":"borrowDuration","type":"uint32"},{"internalType":"address","name":"borrowAsset","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"bytes","name":"extra","type":"bytes"}],"internalType":"struct Offer","name":"_offer","type":"tuple"},{"internalType":"uint256","name":"_nftId","type":"uint256"},{"internalType":"bool","name":"_isCollectionOffer","type":"bool"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Signature","name":"_lenderSignature","type":"tuple"},{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Signature","name":"_brokerSignature","type":"tuple"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"referral","type":"uint256"}],"internalType":"struct CallData","name":"_extraDeal","type":"tuple"}],"name":"borrow","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"cancelByNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"cancelByTimestamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueId","type":"uint256"},{"internalType":"address","name":"_nftAsset","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"deleteInterceptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"},{"internalType":"address","name":"_target","type":"address"},{"internalType":"bytes4","name":"_selector","type":"bytes4"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"flashExecute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAddressProvider","outputs":[{"internalType":"contract IAddressProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_agent","type":"address"},{"internalType":"bytes4","name":"_selector","type":"bytes4"}],"name":"getAgentPermit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_erc20","type":"address"}],"name":"getERC20Permit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_erc721","type":"address"}],"name":"getERC721Permit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueId","type":"uint256"},{"internalType":"address","name":"nftAsset","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getInterceptors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"}],"name":"getLoanState","outputs":[{"components":[{"internalType":"uint64","name":"xy3NftId","type":"uint64"},{"internalType":"enum ILoanStatus.StatusType","name":"status","type":"uint8"}],"internalType":"struct ILoanStatus.LoanState","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"getNonceUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"}],"name":"getRepayAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getTimestampCancelled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"loanDetails","outputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"uint256","name":"nftTokenId","type":"uint256"},{"internalType":"address","name":"borrowAsset","type":"address"},{"internalType":"uint32","name":"loanDuration","type":"uint32"},{"internalType":"uint16","name":"adminShare","type":"uint16"},{"internalType":"uint64","name":"loanStart","type":"uint64"},{"internalType":"address","name":"nftAsset","type":"address"},{"internalType":"bool","name":"isCollection","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"loanIds","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBorrowDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minBorrowDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueId","type":"uint256"},{"internalType":"address","name":"nftAsset","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"interceptor","type":"address"}],"name":"purgeInterceptor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bytes","name":"_param","type":"bytes"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_agents","type":"address[]"},{"internalType":"bytes4[]","name":"_selectors","type":"bytes4[]"},{"internalType":"bool[]","name":"_permits","type":"bool[]"}],"name":"setAgentPermits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_erc20s","type":"address[]"},{"internalType":"bool[]","name":"_permits","type":"bool[]"}],"name":"setERC20Permits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_erc721s","type":"address[]"},{"internalType":"bool[]","name":"_permits","type":"bool[]"}],"name":"setERC721Permits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalNumLoans","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newAdminFeeReceiver","type":"address"}],"name":"updateAdminFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_newAdminShare","type":"uint16"}],"name":"updateAdminShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMaxBorrowDuration","type":"uint256"}],"name":"updateMaxBorrowDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMinBorrowDuration","type":"uint256"}],"name":"updateMinBorrowDuration","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040526301e13380600455620151806005556006805461ffff19166019179055600a805461027160a41b63ffffffff60a01b199091161790553480156200004757600080fd5b5060405162005ffe38038062005ffe8339810160408190526200006a916200021e565b6001805460ff1916815560025581816200008660008362000115565b620000b37faf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02c6000620001b6565b620000e07f2aeb38be3df14d720aeb10a2de6df09b0fb3cd5c5ec256283a22d4593110ca406000620001b6565b600380546001600160a01b039384166001600160a01b031991821617909155600a805492909316911617905550620002559050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620001b2576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620001713390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600082815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b80516001600160a01b03811681146200021957600080fd5b919050565b6000806040838503121562000231578182fd5b6200023c8362000201565b91506200024c6020840162000201565b90509250929050565b615d9980620002656000396000f3fe608060405234801561001057600080fd5b50600436106102b65760003560e01c80638456cb5911610172578063aa3c8079116100d9578063d547741f11610092578063d547741f146107d2578063e3930249146107e5578063e7610eb114610816578063eeb1b06114610829578063f23a6e611461083c578063f8c689341461085b578063fbe6435e1461086357600080fd5b8063aa3c80791461072e578063b6f38a1e14610741578063b7c22cb814610754578063bc197c8114610799578063c0d39248146107ac578063c7008550146107bf57600080fd5b806396087a9f1161012b57806396087a9f146106d65780639ecdda21146106e4578063a041e076146106ed578063a217fddf14610700578063a35524be14610708578063a98250411461071b57600080fd5b80638456cb591461064a578063872873be1461065257806391d148541461067e57806393aa284514610691578063940cbffa1461069a57806395277dd5146106ad57600080fd5b80633f4ba83a116102215780635c975abb116101da5780635c975abb146104e7578063639b2b4d146104f257806363dada33146105055780636ed93dd01461052557806370ba25fc146105415780637284ae931461055457806379b640401461063757600080fd5b80633f4ba83a14610437578063500153501461043f57806354cc4a781461045f578063552f023e1461047f5780635794fefc146104a85780635b5b121d146104d457600080fd5b8063248a9ca311610273578063248a9ca31461038e5780632959203b146103bf5780632f2ff15d146103d2578063320907b8146103e5578063359f62e4146103f857806336568abe1461042457600080fd5b806301ffc9a7146102bb5780630263952a146102e35780630a9c7563146102f85780630fcc660c1461030b578063117c12151461031e578063150b7a0214610357575b600080fd5b6102ce6102c936600461518e565b610876565b60405190151581526020015b60405180910390f35b6102f66102f1366004614ff3565b6108a1565b005b6102f6610306366004615147565b61095f565b6102f6610319366004615392565b6109e0565b6102ce61032c366004614fc8565b6001600160a01b03919091166000908152601160209081526040808320938352929052205460ff1690565b610375610365366004614d4a565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016102da565b6103b161039c366004615147565b60009081526020819052604090206001015490565b6040519081526020016102da565b6102f66103cd366004615341565b610e40565b6102f66103e036600461515f565b610fda565b6102f66103f3366004614f49565b611004565b6102ce610406366004614c69565b6001600160a01b031660009081526008602052604090205460ff1690565b6102f661043236600461515f565b61105f565b6102f66110d9565b61045261044d366004615378565b6110fc565b6040516102da919061580f565b600354610472906001600160a01b031681565b6040516102da9190615561565b6103b161048d366004614c69565b6001600160a01b031660009081526012602052604090205490565b600a546104bf90600160a01b900463ffffffff1681565b60405163ffffffff90911681526020016102da565b6102f66104e2366004615378565b611195565b60015460ff166102ce565b6102f6610500366004615147565b6113f6565b610518610513366004615341565b61146e565b6040516102da9190615673565b61052e61271081565b60405161ffff90911681526020016102da565b6102f661054f366004614c69565b611510565b6105d6610562366004615378565b600f60205260009081526040902080546001820154600283015460038401546004909401549293919290916001600160a01b0380821692600160a01b830463ffffffff1692600160c01b900461ffff16916001600160401b03821691600160401b810490911690600160e01b900460ff1689565b60408051998a5260208a0198909852968801959095526001600160a01b03938416606088015263ffffffff909216608087015261ffff1660a08601526001600160401b031660c08501521660e08301521515610100820152610120016102da565b6102f6610645366004614ff3565b6115da565b6102f6611689565b6102ce610660366004614c69565b6001600160a01b031660009081526007602052604090205460ff1690565b6102ce61068c36600461515f565b6116a9565b6103b160045481565b6102f66106a8366004614e8b565b6116d2565b6103b16106bb366004615378565b63ffffffff166000908152600f602052604090206001015490565b60065461052e9061ffff1681565b6103b160055481565b6102f66106fb366004615341565b61180f565b6103b1600081565b6102f6610716366004615268565b611905565b6102f6610729366004615147565b6119be565b6102f661073c366004614e19565b611a65565b6102f661074f366004615147565b611b4f565b6102ce610762366004614f15565b6001600160a01b03821660009081526009602090815260408083206001600160e01b03198516845290915290205460ff1692915050565b6103756107a7366004614ca1565b611bff565b6104bf6107ba3660046151a8565b611c11565b6102f66107cd366004614e19565b612107565b6102f66107e036600461515f565b612249565b6104bf6107f3366004614fc8565b601060209081526000928352604080842090915290825290205463ffffffff1681565b6102f6610824366004615378565b61226e565b6102f6610837366004615053565b6122a6565b61037561084a366004614db3565b63f23a6e6160e01b95945050505050565b61047261239c565b6102f66108713660046152a0565b6123ab565b60006001600160e01b03198216630a85bd0160e11b148061089b575061089b826124f0565b92915050565b600080516020615d448339815191526108b981612515565b81518351146108e35760405162461bcd60e51b81526004016108da90615742565b60405180910390fd5b60005b83518110156109595761094784828151811061091257634e487b7160e01b600052603260045260246000fd5b602002602001015184838151811061093a57634e487b7160e01b600052603260045260246000fd5b602002602001015161251f565b8061095181615cc9565b9150506108e6565b50505050565b600080516020615d4483398151915261097781612515565b6004548211156109995760405162461bcd60e51b81526004016108da90615718565b81600554146109dc5760058290556040518281527fada00761622e18474ad9efbe0dfbbcfdad01ffb7c67e8d41edce1369f8e66f28906020015b60405180910390a15b5050565b6000806109ec866125ce565b925050915060006109fb61239c565b9050806001600160a01b031663f25b27e66040518163ffffffff1660e01b815260040160206040518083038186803b158015610a3657600080fd5b505afa158015610a4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6e9190614c85565b604051635d90c70b60e01b81526001600160a01b0388811660048301526001600160e01b0319881660248301529190911690635d90c70b90604401602060405180830381600087803b158015610ac357600080fd5b505af1158015610ad7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610afb919061512b565b610b405760405162461bcd60e51b8152602060048201526016602482015275125b9d985b1a5908185a5c991c9bdc081d185c99d95d60521b60448201526064016108da565b610b498261288a565b421115610b685760405162461bcd60e51b81526004016108da906157af565b336001600160a01b03841614610bb05760405162461bcd60e51b815260206004820152600d60248201526c27b7363c903137b93937bbb2b960991b60448201526064016108da565b8160e001516001600160a01b03166342842e0e308885604001516040518463ffffffff1660e01b8152600401610be89392919061559f565b600060405180830381600087803b158015610c0257600080fd5b505af1158015610c16573d6000803e3d6000fd5b505050506000866001600160a01b0316863387604051602401610c3a929190615603565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610c7891906154d6565b6000604051808303816000865af19150503d8060008114610cb5576040519150601f19603f3d011682016040523d82523d6000602084013e610cba565b606091505b5050905080610d025760405162461bcd60e51b8152602060048201526014602482015273115e1d195c9b985b0818d85b1b0819985a5b195960621b60448201526064016108da565b60008360e001516001600160a01b0316636352211e85604001516040518263ffffffff1660e01b8152600401610d3a91815260200190565b60206040518083038186803b158015610d5257600080fd5b505afa158015610d66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8a9190614c85565b90506001600160a01b0381163014610dd75760405162461bcd60e51b815260206004820152601060248201526f13999d081b9bdd081c995d1d5c9b995960821b60448201526064016108da565b60e084015160408086015181516001600160a01b0393841681526020810191909152918a169082015263ffffffff8a16907f0e4d608dd57d6ca7a07003c7307510df5d1a09141df82f3098e84525b87fb6159060600160405180910390a2505050505050505050565b7fc0bedf1ca774403872f60c2c5e429f68debcebd3902ee9f76b76f43ac063d413610e6a81612515565b60038410610eac5760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a59081c5d595d595259608a1b60448201526064016108da565b336000600c8660038110610ed057634e487b7160e01b600052603260045260246000fd5b6001600160a01b0387166000908152910160209081526040808320878452909152812091505b8154811015610f5e57826001600160a01b0316828281548110610f2957634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b03161415610f4c57505050610959565b80610f5681615cc9565b915050610ef6565b5080546001808201835560008381526020902090910180546001600160a01b0319166001600160a01b03858116919091179091556040519087169188917ff67353fc70998a6f08087eae9321c87523ad583c1f248f11c4db223cd381be6791610fca9189918891615894565b60405180910390a3505050505050565b600082815260208190526040902060010154610ff581612515565b610fff83836128af565b505050565b3330146110455760405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b2329031b0b63632b960891b60448201526064016108da565b600061105382840184615378565b90506109598482612933565b6001600160a01b03811633146110cf5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016108da565b6109dc8282612a89565b600080516020615d448339815191526110f181612515565b6110f9612aee565b50565b604080518082019091526000808252602082015263ffffffff82166000908152600b6020908152604091829020825180840190935280546001600160401b03811684529091830190600160401b900460ff16600281111561116d57634e487b7160e01b600052602160045260246000fd5b600281111561118c57634e487b7160e01b600052602160045260246000fd5b90525092915050565b6002805414156111b75760405162461bcd60e51b81526004016108da906157d8565b600280558060016111c7826110fc565b6020015160028111156111ea57634e487b7160e01b600052602160045260246000fd5b146112075760405162461bcd60e51b81526004016108da90615785565b6000806000611215856125ce565b60e081015160408201519396509194509250906112328282612b3a565b600061123d8461288a565b90508042116112885760405162461bcd60e51b8152602060048201526017602482015276131bd85b881a5cc81b9bdd081bdd995c991d59481e595d604a1b60448201526064016108da565b336001600160a01b038616146112dc5760405162461bcd60e51b81526020600482015260196024820152784f6e6c79206c656e6465722063616e206c697175696461746560381b60448201526064016108da565b8351604080519182526020820184905281018290524260608201526001600160a01b038481166080830152808716919088169063ffffffff8b16907f4fac0ff43299a330bce57d0579985305af580acf256a6d7977083ede81be13269060a00160405180910390a4604051632142170760e11b81526001600160a01b038416906342842e0e906113749030908990879060040161559f565b600060405180830381600087803b15801561138e57600080fd5b505af11580156113a2573d6000803e3d6000fd5b505050506113af88612b48565b6001600160a01b03831660009081526010602090815260408083208584529091529020805463ffffffff191690556113e78383612b9c565b50506001600255505050505050565b600080516020615d4483398151915261140e81612515565b6005548210156114305760405162461bcd60e51b81526004016108da90615718565b81600454146109dc5760048290556040518281527f78e13060dd5049aaff2eee249c07301476e6e5b5a60c65116c3fd872c288e453906020016109d3565b6060600c846003811061149157634e487b7160e01b600052603260045260246000fd5b6001600160a01b03851660009081529101602090815260408083208584528252918290208054835181840281018401909452808452909183018282801561150157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116114e3575b505050505090505b9392505050565b600080516020615d4483398151915261152881612515565b6001600160a01b0382166115795760405162461bcd60e51b8152602060048201526018602482015277496e76616c6964207265636569766572206164647265737360401b60448201526064016108da565b6003546001600160a01b038381169116146109dc57600380546001600160a01b0319166001600160a01b0384169081179091556040517fb390a6eece33fc2616d0250e8cd5d72a2b7e0d6cb889791d36ec8892a045b094916109d391615561565b600080516020615d448339815191526115f281612515565b81518351146116135760405162461bcd60e51b81526004016108da90615742565b60005b83518110156109595761167784828151811061164257634e487b7160e01b600052603260045260246000fd5b602002602001015184838151811061166a57634e487b7160e01b600052603260045260246000fd5b6020026020010151612baa565b8061168181615cc9565b915050611616565b600080516020615d448339815191526116a181612515565b6110f9612c50565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60006116dd81612515565b60005b845181101561180757600085828151811061170b57634e487b7160e01b600052603260045260246000fd5b60200260200101519050806001600160a01b031663f242432a308988868151811061174657634e487b7160e01b600052603260045260246000fd5b602002602001015188878151811061176e57634e487b7160e01b600052603260045260246000fd5b60209081029190910101516040516001600160e01b031960e087901b1681526001600160a01b0394851660048201529390921660248401526044830152606482015260a06084820152600060a482015260c401600060405180830381600087803b1580156117db57600080fd5b505af11580156117ef573d6000803e3d6000fd5b505050505080806117ff90615cc9565b9150506116e0565b505050505050565b7fc0bedf1ca774403872f60c2c5e429f68debcebd3902ee9f76b76f43ac063d41361183981612515565b336000600c866003811061185d57634e487b7160e01b600052603260045260246000fd5b6001600160a01b0387166000908152910160209081526040808320878452909152812091505b81548110156118e857826001600160a01b03168282815481106118b657634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031614156118d6576118e8565b806118e081615cc9565b915050611883565b600381146118fc576118fc87878784612c8b565b50505050505050565b600080516020615d4483398151915261191d81612515565b61271061ffff8316111561196a5760405162461bcd60e51b81526020600482015260146024820152730626173697320706f696e7473203e2031303030360641b60448201526064016108da565b60065461ffff8381169116146109dc576006805461ffff191661ffff84169081179091556040519081527f03017365bbe16943b524030df07e7689168ab63e854d27417498e6f9dc584dab906020016109d3565b428110611a015760405162461bcd60e51b81526020600482015260116024820152700496e76616c69642074696d657374616d7607c1b60448201526064016108da565b336000908152601260205260409020548111156110f9573360008181526012602052604090819020839055517fe7258d55b23f4902343add21f328e6d35c5d58bff7fe8bda6f1df7851f04d36a91611a5a918490615627565b60405180910390a150565b6000611a7081612515565b6001600160a01b038416611ab85760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016108da565b60005b8351811015611b48576000848281518110611ae657634e487b7160e01b600052603260045260246000fd5b60200260200101519050611b3586858481518110611b1457634e487b7160e01b600052603260045260246000fd5b6020026020010151836001600160a01b0316612e4f9092919063ffffffff16565b5080611b4081615cc9565b915050611abb565b5050505050565b33600090815260116020908152604080832084845290915290205460ff1615611baa5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b60448201526064016108da565b33600081815260116020908152604080832085845290915290819020805460ff19166001179055517f26ccf9904b9b2fb069d347553978928fd2fc65efb2638dcbeb8d142e974479f091611a5a918490615627565b63bc197c8160e01b5b95945050505050565b6000611c1b612ea5565b600280541415611c3d5760405162461bcd60e51b81526004016108da906157d8565b60028055611c52611c4d88615b88565b612eed565b6000611c646060890160408a01614c69565b9050611c7081886130a8565b6000611c85611c7e8a615b88565b89896130b6565b9050611cac611c938a615b88565b8989611c9e8a615c1c565b611ca78a615c1c565b61313b565b6000611cb661239c565b9050806001600160a01b0316630b0bba1e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611cf157600080fd5b505afa158015611d05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d299190614c85565b6001600160a01b031663df777835611d4760608a0160408b01614c69565b338d6080016020810190611d5b9190614c69565b8e600001356040518563ffffffff1660e01b8152600401611d7f9493929190615575565b600060405180830381600087803b158015611d9957600080fd5b505af1158015611dad573d6000803e3d6000fd5b5060009250611dc29150506020870187614c69565b6001600160a01b031614611f4d57611df0611de06020870187614c69565b610762604088016020890161518e565b611e2f5760405162461bcd60e51b815260206004820152601060248201526f139bdd081d985b1a5919481859d95b9d60821b60448201526064016108da565b6000611e41604087016020880161518e565b33611e4f6040890189615998565b604051602401611e61939291906155c3565b60408051601f19818403018152919052602080820180516001600160e01b03166001600160e01b0319909416939093179092529150600090611ea590880188614c69565b6001600160a01b031682604051611ebc91906154d6565b6000604051808303816000865af19150503d8060008114611ef9576040519150601f19603f3d011682016040523d82523d6000602084013e611efe565b606091505b5050905080611f4a5760405162461bcd60e51b8152602060048201526018602482015277109bdc9c9bddc8195e1d1c984818d85b1b0819985a5b195960421b60448201526064016108da565b50505b806001600160a01b0316630b0bba1e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f8657600080fd5b505afa158015611f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fbe9190614c85565b6001600160a01b03166342f1a2563330868d6040518563ffffffff1660e01b8152600401611fef9493929190615575565b600060405180830381600087803b15801561200957600080fd5b505af115801561201d573d6000803e3d6000fd5b5050505060006120528860400160208101906120399190614c69565b33856120448c615c1c565b61204d8b615b16565b613288565b90506120736120608c615b88565b8261206e60208a018a614c69565b6133f3565b6001600160a01b03841660009081526010602090815260408083208d84529091529020805463ffffffff191663ffffffff83161790556120b3848b613699565b60405160608701358152339063ffffffff8316907ff7b9c21907a3ce171a12296161a29b2ba931964bb680f1b61cebd8ab251cec989060200160405180910390a360016002559a9950505050505050505050565b600061211281612515565b60005b8351811015611b4857600084828151811061214057634e487b7160e01b600052603260045260246000fd5b60200260200101519050600084838151811061216c57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b0384166000908152601083526040808220838352909352919091205490915063ffffffff168061223357826001600160a01b03166342842e0e308a8988815181106121da57634e487b7160e01b600052603260045260246000fd5b60200260200101516040518463ffffffff1660e01b81526004016122009392919061559f565b600060405180830381600087803b15801561221a57600080fd5b505af115801561222e573d6000803e3d6000fd5b505050505b505050808061224190615cc9565b915050612115565b60008281526020819052604090206001015461226481612515565b610fff8383612a89565b6002805414156122905760405162461bcd60e51b81526004016108da906157d8565b6002805561229e3382612933565b506001600255565b7f37442f0e5201d32aba04d9e4c019aaed797c0adefd44367a782d9bb1c3a244386122d081612515565b815184511480156122e2575081518351145b6122fe5760405162461bcd60e51b81526004016108da90615742565b60005b8451811015611b485761238a85828151811061232d57634e487b7160e01b600052603260045260246000fd5b602002602001015185838151811061235557634e487b7160e01b600052603260045260246000fd5b602002602001015185848151811061237d57634e487b7160e01b600052603260045260246000fd5b60200260200101516136a6565b8061239481615cc9565b915050612301565b600a546001600160a01b031690565b600080516020615d448339815191526123c381612515565b60005b838110156118fc576000600c88600381106123f157634e487b7160e01b600052603260045260246000fd5b6001600160a01b03891660009081529101602052604081209087878581811061242a57634e487b7160e01b600052603260045260246000fd5b905060200201358152602001908152602001600020905060005b81548110156124db57846001600160a01b031682828154811061247757634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031614156124c9576124c489898989878181106124b757634e487b7160e01b600052603260045260246000fd5b9050602002013584612c8b565b6124db565b806124d381615cc9565b915050612444565b505080806124e890615cc9565b9150506123c6565b60006001600160e01b03198216630271189760e51b148061089b575061089b82613786565b6110f981336137bb565b6001600160a01b03821661256e5760405162461bcd60e51b8152602060048201526016602482015275657263373231206973207a65726f206164647265737360501b60448201526064016108da565b6001600160a01b038216600081815260086020908152604091829020805460ff191685151590811790915591519182527f3e0c443872dd01e15f6ca1f8ee12f284a44836f46012e421d74611bf80eda7c191015b60405180910390a25050565b6000806125d9614a09565b60006125e4856110fc565b5163ffffffff8681166000908152600f60209081526040918290208251610120810184528154815260018201549281019290925260028101549282019290925260038201546001600160a01b038082166060840152600160a01b82049094166080830152600160c01b900461ffff1660a08201526004909101546001600160401b0380821660c0840152600160401b820490931660e0830152600160e01b900460ff161515610100820152935016905061269c61239c565b6001600160a01b031663681dee566040518163ffffffff1660e01b815260040160206040518083038186803b1580156126d457600080fd5b505afa1580156126e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061270c9190614c85565b6001600160a01b0316636352211e826040518263ffffffff1660e01b815260040161273991815260200190565b60206040518083038186803b15801561275157600080fd5b505afa158015612765573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127899190614c85565b935061279361239c565b6001600160a01b031663d1d261d06040518163ffffffff1660e01b815260040160206040518083038186803b1580156127cb57600080fd5b505afa1580156127df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128039190614c85565b6001600160a01b0316636352211e826040518263ffffffff1660e01b815260040161283091815260200190565b60206040518083038186803b15801561284857600080fd5b505afa15801561285c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128809190614c85565b9250509193909250565b6000816080015163ffffffff168260c001516001600160401b031661089b9190615a80565b6128b982826116a9565b6109dc576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556128ef3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b80600161293f826110fc565b60200151600281111561296257634e487b7160e01b600052602160045260246000fd5b1461297f5760405162461bcd60e51b81526004016108da90615785565b600080600061298d856125ce565b92509250925061299c8161288a565b4211156129bb5760405162461bcd60e51b81526004016108da906157af565b60e081015160408201516129cf828261381f565b604051632142170760e11b81526001600160a01b038316906342842e0e906129ff9030908990869060040161559f565b600060405180830381600087803b158015612a1957600080fd5b505af1158015612a2d573d6000803e3d6000fd5b50505050612a3e8886868a8761382c565b612a4787612b48565b6001600160a01b03821660009081526010602090815260408083208484529091529020805463ffffffff19169055612a7f8282613a88565b5050505050505050565b612a9382826116a9565b156109dc576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b612af6613a96565b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b604051612b309190615561565b60405180910390a1565b6109dc600260018484613adf565b612b5181613d22565b63ffffffff166000908152600f602052604081208181556001810182905560028101919091556003810180546001600160d01b031916905560040180546001600160e81b0319169055565b6109dc600260008484613adf565b6001600160a01b038216612bf85760405162461bcd60e51b81526020600482015260156024820152746572633230206973207a65726f206164647265737360581b60448201526064016108da565b6001600160a01b038216600081815260076020908152604091829020805460ff191685151590811790915591519182527ff100355be652ecc881568750e6a98c0713e4316f75d5314ebc9039e0acb52f2491016125c2565b612c58612ea5565b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833612b23565b6000600c8560038110612cae57634e487b7160e01b600052603260045260246000fd5b6001600160a01b038616600090815291016020908152604080832086845290915281208054909250829084908110612cf657634e487b7160e01b600052603260045260246000fd5b600091825260208220015483546001600160a01b039091169250612d1c90600190615aff565b905080841015612db9576000838281548110612d4857634e487b7160e01b600052603260045260246000fd5b9060005260206000200160009054906101000a90046001600160a01b0316905080848681548110612d8957634e487b7160e01b600052603260045260246000fd5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505b82805480612dd757634e487b7160e01b600052603160045260246000fd5b6001900381819060005260206000200160006101000a8154906001600160a01b0302191690559055856001600160a01b0316877ff67353fc70998a6f08087eae9321c87523ad583c1f248f11c4db223cd381be6787856000604051612e3e93929190615894565b60405180910390a350505050505050565b610fff8363a9059cbb60e01b8484604051602401612e6e929190615627565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613f0c565b60015460ff1615612eeb5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108da565b565b60808101516001600160a01b031660009081526007602052604090205460ff16612f4c5760405162461bcd60e51b815260206004820152601060248201526f496e76616c69642063757272656e637960801b60448201526064016108da565b6040808201516001600160a01b031660009081526008602052205460ff16612fad5760405162461bcd60e51b815260206004820152601460248201527324b73b30b634b21022a9219b9918903a37b5b2b760611b60448201526064016108da565b600454816060015163ffffffff1611156130045760405162461bcd60e51b815260206004820152601860248201527724b73b30b634b21036b0bc34b6bab690323ab930ba34b7b760411b60448201526064016108da565b600554816060015163ffffffff16101561305b5760405162461bcd60e51b815260206004820152601860248201527724b73b30b634b21036b4b734b6bab690323ab930ba34b7b760411b60448201526064016108da565b8051602082015110156110f95760405162461bcd60e51b8152602060048201526015602482015274496e76616c696420696e746572657374207261746560581b60448201526064016108da565b6109dc600060018484613adf565b6130be614a09565b5060408051610120810182528451815260208086015190820152808201939093526080808501516001600160a01b0390811660608087019190915286015163ffffffff169185019190915260065461ffff1660a0850152426001600160401b031660c085015293015190921660e082015290151561010082015290565b6040808301516001600160a01b038116600090815260116020908152838220865183529052919091205460ff16156131ac5760405162461bcd60e51b815260206004820152601460248201527313195b99195c881b9bdb98d9481a5b9d985b1a5960621b60448201526064016108da565b6131da7f2aeb38be3df14d720aeb10a2de6df09b0fb3cd5c5ec256283a22d4593110ca4083604001516116a9565b61321e5760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b210313937b5b2b91039b4b3b732b960591b60448201526064016108da565b60a08601516001600160a01b0382166000908152601260205260409020541061327b5760405162461bcd60e51b815260206004820152600f60248201526e13d999995c8818d85b98d95b1b1959608a1b60448201526064016108da565b6118078686868686613fde565b6001600160a01b0385166000908152601160209081526040808320855184529091528120805460ff19166001179055806132c2878761420c565b63ffffffff8082166000818152600f60209081526040918290208a518155818b01516001820155828b0151600282015560608b015160038201805460808e015160a08f015161ffff16600160c01b0261ffff60c01b1991909916600160a01b026001600160c01b03199092166001600160a01b039485161791909117169690961790955560c08b01516004909101805460e08d01516101008e01511515600160e01b0260ff60e01b19918916600160401b026001600160e01b03199093166001600160401b039095169490941791909117169190911790558882015189518951928a0151935196975094169433947ff2605177b2b695bc687a0fb9ac9e447ba4b6a02145b2f335fb749308678cb1cb936133e19391928d9291906158d4565b60405180910390a49695505050505050565b6001600160a01b03811615610fff57600061340c61239c565b90506000846040015190506000856000015190506000866080015190506000846001600160a01b03166311a1933c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561346457600080fd5b505afa158015613478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349c9190614c85565b90506000806001600160a01b0383161561368d576040516315ee833560e21b81526001600160a01b03898116600483015233602483015287811660448301528416906357ba0cd49060640160206040518083038186803b1580156134ff57600080fd5b505afa158015613513573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135379190615284565b915061ffff82161561363c5761271061355461ffff841687615ae0565b61355e9190615ac0565b9050866001600160a01b0316630b0bba1e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561359957600080fd5b505afa1580156135ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135d19190614c85565b60035460405163df77783560e01b81526001600160a01b039283169263df777835926136099233929091169089908790600401615575565b600060405180830381600087803b15801561362357600080fd5b505af1158015613637573d6000803e3d6000fd5b505050505b6040805161ffff84168152602081018390526001600160a01b038a169163ffffffff8c16917f6b0714b8faf060425ff50a36726d7dbfab63b9e3c17515f10290fd04ec946e27910160405180910390a35b50505050505050505050565b6109dc6000808484613adf565b6001600160a01b038316158015906136c757506001600160e01b0319821615155b61370b5760405162461bcd60e51b81526020600482015260156024820152746167656e74206973207a65726f206164647265737360581b60448201526064016108da565b6001600160a01b03831660008181526009602090815260408083206001600160e01b0319871680855290835292819020805460ff19168615159081179091558151938452918301919091527feef855269fc053a84572ea142b53ab4a0e276e2346315c1c1622587f971ee4a3910160405180910390a2505050565b60006001600160e01b03198216637965db0b60e01b148061089b57506301ffc9a760e01b6001600160e01b031983161461089b565b6137c582826116a9565b6109dc576137dd816001600160a01b031660146144ed565b6137e88360206144ed565b6040516020016137f99291906154f2565b60408051601f198184030181529082905262461bcd60e51b82526108da916004016156ce565b6109dc6001808484613adf565b600080613838836146ce565b91509150600061384661239c565b9050806001600160a01b0316630b0bba1e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561388157600080fd5b505afa158015613895573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138b99190614c85565b6001600160a01b031663df77783589888760600151866040518563ffffffff1660e01b81526004016138ee9493929190615575565b600060405180830381600087803b15801561390857600080fd5b505af115801561391c573d6000803e3d6000fd5b50505050806001600160a01b0316630b0bba1e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561395957600080fd5b505afa15801561396d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139919190614c85565b600354606086015160405163df77783560e01b81526001600160a01b039384169363df777835936139cd938e9392909116918990600401615575565b600060405180830381600087803b1580156139e757600080fd5b505af11580156139fb573d6000803e3d6000fd5b5050855160408088015160e08901516060808b0151845195865260208601939093529284018890529183018890526001600160a01b039182166080840152811660a0830152808a1693508a16915063ffffffff8816907f6ee3573bd905753c83bc1aaca3c15bfa36391db95b778bd825eb010645a7ee459060c00160405180910390a45050505050505050565b6109dc600160008484613adf565b60015460ff16612eeb5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016108da565b6000600c8560038110613b0257634e487b7160e01b600052603260045260246000fd5b6001600160a01b038516600090815291016020908152604080832085845282529182902080548351818402810184019094528084529091830182828015613b7257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613b54575b5050505050905060005b8151811015611807578415613c1957818181518110613bab57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031663619452ef8786866040518463ffffffff1660e01b8152600401613be2939291906158b5565b600060405180830381600087803b158015613bfc57600080fd5b505af1158015613c10573d6000803e3d6000fd5b50505050613ca3565b818181518110613c3957634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316634f297ecd8786866040518463ffffffff1660e01b8152600401613c70939291906158b5565b600060405180830381600087803b158015613c8a57600080fd5b505af1158015613c9e573d6000803e3d6000fd5b505050505b836001600160a01b0316867f9125866eb9cfb156e40aea5aea2cf396c4a72b7c8e86c7e8c7c091324bf6370085858581518110613cf057634e487b7160e01b600052603260045260246000fd5b602002602001015189604051613d0893929190615894565b60405180910390a380613d1a81615cc9565b915050613b7c565b63ffffffff81166000908152600b6020526040902060018154600160401b900460ff166002811115613d6457634e487b7160e01b600052602160045260246000fd5b14613da95760405162461bcd60e51b81526020600482015260156024820152744c6f616e206973206e6f742061206e6577206f6e6560581b60448201526064016108da565b805460ff60401b1916600160411b178155600080613dc5614725565b8454604051630852cd8d60e31b81526001600160401b03909116600482015291935091506001600160a01b038216906342966c6890602401600060405180830381600087803b158015613e1757600080fd5b505af1158015613e2b573d6000803e3d6000fd5b50508454604051630852cd8d60e31b81526001600160401b0390911660048201526001600160a01b03851692506342966c689150602401600060405180830381600087803b158015613e7c57600080fd5b505af1158015613e90573d6000803e3d6000fd5b505084546040516001600160401b03909116925063ffffffff871691507fa99afb24dca45e3cebef49cd6184255e4623c0bf6c5e87bb6738629ceefa2dac90613edb906002906156c0565b60405180910390a350505063ffffffff166000908152600b60205260409020805468ffffffffffffffffff19169055565b6000613f61826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166148889092919063ffffffff16565b805190915015610fff5780806020019051810190613f7f919061512b565b610fff5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108da565b821561408e5760405163dd90aba160e01b8152736a7acf3feb58fcf15f74b73391c78a879f7c9e359063dd90aba19061401d908890869060040161583a565b60206040518083038186803b15801561403557600080fd5b505af4158015614049573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061406d919061512b565b6140895760405162461bcd60e51b81526004016108da906156e1565b614135565b60405163a9170a7f60e01b8152736a7acf3feb58fcf15f74b73391c78a879f7c9e359063a9170a7f906140c99088908890879060040161585f565b60206040518083038186803b1580156140e157600080fd5b505af41580156140f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614119919061512b565b6141355760405162461bcd60e51b81526004016108da906156e1565b60405163a9170a7f60e01b8152736a7acf3feb58fcf15f74b73391c78a879f7c9e359063a9170a7f906141709088908890869060040161585f565b60206040518083038186803b15801561418857600080fd5b505af415801561419c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c0919061512b565b611b485760405162461bcd60e51b815260206004820152601b60248201527f5369676e6572207369676e617475726520697320696e76616c6964000000000060448201526064016108da565b60006001600a60148282829054906101000a900463ffffffff166142309190615a98565b82546101009290920a63ffffffff81810219909316919092169190910217905550600a546040513060601b6bffffffffffffffffffffffff19166020820152600160a01b90910460e01b6001600160e01b031916603482015260009060380160408051808303601f1901815282825280516020918201208383019092526001600160401b038216835260019083015291506000806142cc614725565b600a5460408051600160a01b90920463ffffffff1660208301529294509092506001600160a01b038316916394d008ef918a918891016040516020818303038152906040526040518463ffffffff1660e01b815260040161432f93929190615640565b600060405180830381600087803b15801561434957600080fd5b505af115801561435d573d6000803e3d6000fd5b5050600a5460408051600160a01b90920463ffffffff1660208301526001600160a01b03861693506394d008ef925089918891016040516020818303038152906040526040518463ffffffff1660e01b81526004016143be93929190615640565b600060405180830381600087803b1580156143d857600080fd5b505af11580156143ec573d6000803e3d6000fd5b5050600a5463ffffffff600160a01b909104166000908152600b60209081526040909120865181546001600160401b0390911667ffffffffffffffff19821681178355928801518895509193509091839168ffffffffffffffffff191617600160401b83600281111561446f57634e487b7160e01b600052602160045260246000fd5b0217905550905050836001600160401b0316600a60149054906101000a900463ffffffff1663ffffffff167fa99afb24dca45e3cebef49cd6184255e4623c0bf6c5e87bb6738629ceefa2dac60016040516144ca91906156c0565b60405180910390a35050600a54600160a01b900463ffffffff1695945050505050565b606060006144fc836002615ae0565b614507906002615a80565b6001600160401b0381111561452c57634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015614556576020820181803683370190505b509050600360fc1b8160008151811061457f57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106145bc57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060006145e0846002615ae0565b6145eb906001615a80565b90505b600181111561467f576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061462d57634e487b7160e01b600052603260045260246000fd5b1a60f81b82828151811061465157634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060049490941c9361467881615cb2565b90506145ee565b5083156115095760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016108da565b6000806000836000015184602001516146e79190615aff565b60a0850151909150612710906147019061ffff1683615ae0565b61470b9190615ac0565b925082846020015161471d9190615aff565b915050915091565b6000806000306001600160a01b031663f8c689346040518163ffffffff1660e01b815260040160206040518083038186803b15801561476357600080fd5b505afa158015614777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061479b9190614c85565b9050806001600160a01b031663681dee566040518163ffffffff1660e01b815260040160206040518083038186803b1580156147d657600080fd5b505afa1580156147ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061480e9190614c85565b9250806001600160a01b031663d1d261d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561484957600080fd5b505afa15801561485d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148819190614c85565b9150509091565b6060614897848460008561489f565b949350505050565b6060824710156149005760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016108da565b6001600160a01b0385163b6149575760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108da565b600080866001600160a01b0316858760405161497391906154d6565b60006040518083038185875af1925050503d80600081146149b0576040519150601f19603f3d011682016040523d82523d6000602084013e6149b5565b606091505b50915091506149c58282866149d0565b979650505050505050565b606083156149df575081611509565b8251156149ef5782518084602001fd5b8160405162461bcd60e51b81526004016108da91906156ce565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b8035614a6081615d10565b919050565b600082601f830112614a75578081fd5b81356020614a8a614a8583615a5d565b615a2d565b80838252828201915082860187848660051b8901011115614aa9578586fd5b855b85811015614ad0578135614abe81615d10565b84529284019290840190600101614aab565b5090979650505050505050565b600082601f830112614aed578081fd5b81356020614afd614a8583615a5d565b80838252828201915082860187848660051b8901011115614b1c578586fd5b855b85811015614ad0578135614b3181615d25565b84529284019290840190600101614b1e565b600082601f830112614b53578081fd5b81356020614b63614a8583615a5d565b80838252828201915082860187848660051b8901011115614b82578586fd5b855b85811015614ad057813584529284019290840190600101614b84565b8035614a6081615d25565b80356001600160e01b031981168114614a6057600080fd5b600082601f830112614bd3578081fd5b81356001600160401b03811115614bec57614bec615cfa565b614bff601f8201601f1916602001615a2d565b818152846020838601011115614c13578283fd5b816020850160208301379081016020019190915292915050565b600060808284031215614c3e578081fd5b50919050565b600060e08284031215614c3e578081fd5b803563ffffffff81168114614a6057600080fd5b600060208284031215614c7a578081fd5b813561150981615d10565b600060208284031215614c96578081fd5b815161150981615d10565b600080600080600060a08688031215614cb8578081fd5b8535614cc381615d10565b94506020860135614cd381615d10565b935060408601356001600160401b0380821115614cee578283fd5b614cfa89838a01614b43565b94506060880135915080821115614d0f578283fd5b614d1b89838a01614b43565b93506080880135915080821115614d30578283fd5b50614d3d88828901614bc3565b9150509295509295909350565b60008060008060808587031215614d5f578182fd5b8435614d6a81615d10565b93506020850135614d7a81615d10565b92506040850135915060608501356001600160401b03811115614d9b578182fd5b614da787828801614bc3565b91505092959194509250565b600080600080600060a08688031215614dca578283fd5b8535614dd581615d10565b94506020860135614de581615d10565b9350604086013592506060860135915060808601356001600160401b03811115614e0d578182fd5b614d3d88828901614bc3565b600080600060608486031215614e2d578081fd5b8335614e3881615d10565b925060208401356001600160401b0380821115614e53578283fd5b614e5f87838801614a65565b93506040860135915080821115614e74578283fd5b50614e8186828701614b43565b9150509250925092565b60008060008060808587031215614ea0578182fd5b8435614eab81615d10565b935060208501356001600160401b0380821115614ec6578384fd5b614ed288838901614a65565b94506040870135915080821115614ee7578384fd5b614ef388838901614b43565b93506060870135915080821115614f08578283fd5b50614da787828801614b43565b60008060408385031215614f27578182fd5b8235614f3281615d10565b9150614f4060208401614bab565b90509250929050565b600080600060408486031215614f5d578081fd5b8335614f6881615d10565b925060208401356001600160401b0380821115614f83578283fd5b818601915086601f830112614f96578283fd5b813581811115614fa4578384fd5b876020828501011115614fb5578384fd5b6020830194508093505050509250925092565b60008060408385031215614fda578182fd5b8235614fe581615d10565b946020939093013593505050565b60008060408385031215615005578182fd5b82356001600160401b038082111561501b578384fd5b61502786838701614a65565b9350602085013591508082111561503c578283fd5b5061504985828601614add565b9150509250929050565b600080600060608486031215615067578081fd5b83356001600160401b038082111561507d578283fd5b61508987838801614a65565b945060209150818601358181111561509f578384fd5b8601601f810188136150af578384fd5b80356150bd614a8582615a5d565b8082825285820191508584018b878560051b87010111156150dc578788fd5b8794505b83851015615105576150f181614bab565b8352600194909401939186019186016150e0565b509650505050604086013591508082111561511e578283fd5b50614e8186828701614add565b60006020828403121561513c578081fd5b815161150981615d25565b600060208284031215615158578081fd5b5035919050565b60008060408385031215615171578182fd5b82359150602083013561518381615d10565b809150509250929050565b60006020828403121561519f578081fd5b61150982614bab565b60008060008060008060c087890312156151c0578384fd5b86356001600160401b03808211156151d6578586fd5b6151e28a838b01614c44565b9750602089013596506151f760408a01614ba0565b9550606089013591508082111561520c578283fd5b6152188a838b01614c2d565b9450608089013591508082111561522d578283fd5b6152398a838b01614c2d565b935060a089013591508082111561524e578283fd5b5061525b89828a01614c2d565b9150509295509295509295565b600060208284031215615279578081fd5b813561150981615d33565b600060208284031215615295578081fd5b815161150981615d33565b6000806000806000608086880312156152b7578283fd5b8535945060208601356152c981615d10565b935060408601356001600160401b03808211156152e4578485fd5b818801915088601f8301126152f7578485fd5b813581811115615305578586fd5b8960208260051b8501011115615319578586fd5b602083019550809450505050606086013561533381615d10565b809150509295509295909350565b600080600060608486031215615355578081fd5b83359250602084013561536781615d10565b929592945050506040919091013590565b600060208284031215615389578081fd5b61150982614c55565b600080600080608085870312156153a7578182fd5b6153b085614c55565b935060208501356153c081615d10565b92506153ce60408601614bab565b915060608501356001600160401b03811115614d9b578182fd5b60008151808452615400816020860160208601615c86565b601f01601f19169290920160200192915050565b6003811061543257634e487b7160e01b600052602160045260246000fd5b9052565b80518252602081015160208301526000604082015160018060a01b03808216604086015263ffffffff6060850151166060860152806080850151166080860152505060a082015160a084015260c082015160e060c085015261489760e08501826153e8565b805182526020810151602083015260018060a01b036040820151166040830152600060608201516080606085015261489760808501826153e8565b600082516154e8818460208701615c86565b9190910192915050565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b815260008351615524816017850160208801615c86565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615555816028840160208801615c86565b01602801949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b6001600160a01b0383168152604060208201819052600090614897908301846153e8565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03841681526001600160401b0383166020820152606060408201819052600090611c08908301846153e8565b6020808252825182820181905260009190848201906040850190845b818110156156b45783516001600160a01b03168352928401929184019160010161568f565b50909695505050505050565b6020810161089b8284615414565b60208152600061150960208301846153e8565b6020808252601b908201527f4c656e646572207369676e617475726520697320696e76616c69640000000000604082015260600190565b60208082526010908201526f24b73b30b634b210323ab930ba34b7b760811b604082015260600190565b60208082526023908201527f6164647265737320616e64207065726d697473206c656e677468206d69736d616040820152620e8c6d60eb1b606082015260800190565b60208082526010908201526f2637b0b71034b9903737ba1037b832b760811b604082015260600190565b6020808252600f908201526e131bd85b881a5cc8195e1c1a5c9959608a1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b81516001600160401b03168152602080830151604083019161583390840182615414565b5092915050565b60408152600061584d6040830185615436565b8281036020840152611c08818561549b565b6060815260006158726060830186615436565b846020840152828103604084015261588a818561549b565b9695505050505050565b9283526001600160a01b039190911660208301521515604082015260600190565b9283526001600160a01b03919091166020830152604082015260600190565b60006101808201905085825284516020830152602085015160408301526040850151606083015260018060a01b036060860151166080830152608085015161592460a084018263ffffffff169052565b5060a085015161ffff811660c08401525060c08501516001600160401b03811660e08401525060e0850151610100615966818501836001600160a01b03169052565b8601511515610120840152506001600160a01b0384166101408301526001600160e01b03198316610160830152611c08565b6000808335601e198436030181126159ae578283fd5b8301803591506001600160401b038211156159c7578283fd5b6020019150368190038213156159dc57600080fd5b9250929050565b604051608081016001600160401b0381118282101715615a0557615a05615cfa565b60405290565b60405160e081016001600160401b0381118282101715615a0557615a05615cfa565b604051601f8201601f191681016001600160401b0381118282101715615a5557615a55615cfa565b604052919050565b60006001600160401b03821115615a7657615a76615cfa565b5060051b60200190565b60008219821115615a9357615a93615ce4565b500190565b600063ffffffff808316818516808303821115615ab757615ab7615ce4565b01949350505050565b600082615adb57634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615afa57615afa615ce4565b500290565b600082821015615b1157615b11615ce4565b500390565b600060808236031215615b27578081fd5b615b2f6159e3565b8235615b3a81615d10565b8152615b4860208401614bab565b602082015260408301356001600160401b03811115615b65578283fd5b615b7136828601614bc3565b604083015250606092830135928101929092525090565b600060e08236031215615b99578081fd5b615ba1615a0b565b8235815260208301356020820152615bbb60408401614a55565b6040820152615bcc60608401614c55565b6060820152615bdd60808401614a55565b608082015260a083013560a082015260c08301356001600160401b03811115615c04578283fd5b615c1036828601614bc3565b60c08301525092915050565b600060808236031215615c2d578081fd5b615c356159e3565b82358152602083013560208201526040830135615c5181615d10565b604082015260608301356001600160401b03811115615c6e578283fd5b615c7a36828601614bc3565b60608301525092915050565b60005b83811015615ca1578181015183820152602001615c89565b838111156109595750506000910152565b600081615cc157615cc1615ce4565b506000190190565b6000600019821415615cdd57615cdd615ce4565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146110f957600080fd5b80151581146110f957600080fd5b61ffff811681146110f957600080fdfeaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02ca2646970667358221220738ba32f118f5ccf85ded19a16c1e1b712bfadefc4b3f8ffe8a9304e9ce127bd64736f6c634300080400330000000000000000000000002087d218c030d47a564d336385ddffafaad5520800000000000000000000000021a619115f36de1a71b549e9081022fe84136f65
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102b65760003560e01c80638456cb5911610172578063aa3c8079116100d9578063d547741f11610092578063d547741f146107d2578063e3930249146107e5578063e7610eb114610816578063eeb1b06114610829578063f23a6e611461083c578063f8c689341461085b578063fbe6435e1461086357600080fd5b8063aa3c80791461072e578063b6f38a1e14610741578063b7c22cb814610754578063bc197c8114610799578063c0d39248146107ac578063c7008550146107bf57600080fd5b806396087a9f1161012b57806396087a9f146106d65780639ecdda21146106e4578063a041e076146106ed578063a217fddf14610700578063a35524be14610708578063a98250411461071b57600080fd5b80638456cb591461064a578063872873be1461065257806391d148541461067e57806393aa284514610691578063940cbffa1461069a57806395277dd5146106ad57600080fd5b80633f4ba83a116102215780635c975abb116101da5780635c975abb146104e7578063639b2b4d146104f257806363dada33146105055780636ed93dd01461052557806370ba25fc146105415780637284ae931461055457806379b640401461063757600080fd5b80633f4ba83a14610437578063500153501461043f57806354cc4a781461045f578063552f023e1461047f5780635794fefc146104a85780635b5b121d146104d457600080fd5b8063248a9ca311610273578063248a9ca31461038e5780632959203b146103bf5780632f2ff15d146103d2578063320907b8146103e5578063359f62e4146103f857806336568abe1461042457600080fd5b806301ffc9a7146102bb5780630263952a146102e35780630a9c7563146102f85780630fcc660c1461030b578063117c12151461031e578063150b7a0214610357575b600080fd5b6102ce6102c936600461518e565b610876565b60405190151581526020015b60405180910390f35b6102f66102f1366004614ff3565b6108a1565b005b6102f6610306366004615147565b61095f565b6102f6610319366004615392565b6109e0565b6102ce61032c366004614fc8565b6001600160a01b03919091166000908152601160209081526040808320938352929052205460ff1690565b610375610365366004614d4a565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020016102da565b6103b161039c366004615147565b60009081526020819052604090206001015490565b6040519081526020016102da565b6102f66103cd366004615341565b610e40565b6102f66103e036600461515f565b610fda565b6102f66103f3366004614f49565b611004565b6102ce610406366004614c69565b6001600160a01b031660009081526008602052604090205460ff1690565b6102f661043236600461515f565b61105f565b6102f66110d9565b61045261044d366004615378565b6110fc565b6040516102da919061580f565b600354610472906001600160a01b031681565b6040516102da9190615561565b6103b161048d366004614c69565b6001600160a01b031660009081526012602052604090205490565b600a546104bf90600160a01b900463ffffffff1681565b60405163ffffffff90911681526020016102da565b6102f66104e2366004615378565b611195565b60015460ff166102ce565b6102f6610500366004615147565b6113f6565b610518610513366004615341565b61146e565b6040516102da9190615673565b61052e61271081565b60405161ffff90911681526020016102da565b6102f661054f366004614c69565b611510565b6105d6610562366004615378565b600f60205260009081526040902080546001820154600283015460038401546004909401549293919290916001600160a01b0380821692600160a01b830463ffffffff1692600160c01b900461ffff16916001600160401b03821691600160401b810490911690600160e01b900460ff1689565b60408051998a5260208a0198909852968801959095526001600160a01b03938416606088015263ffffffff909216608087015261ffff1660a08601526001600160401b031660c08501521660e08301521515610100820152610120016102da565b6102f6610645366004614ff3565b6115da565b6102f6611689565b6102ce610660366004614c69565b6001600160a01b031660009081526007602052604090205460ff1690565b6102ce61068c36600461515f565b6116a9565b6103b160045481565b6102f66106a8366004614e8b565b6116d2565b6103b16106bb366004615378565b63ffffffff166000908152600f602052604090206001015490565b60065461052e9061ffff1681565b6103b160055481565b6102f66106fb366004615341565b61180f565b6103b1600081565b6102f6610716366004615268565b611905565b6102f6610729366004615147565b6119be565b6102f661073c366004614e19565b611a65565b6102f661074f366004615147565b611b4f565b6102ce610762366004614f15565b6001600160a01b03821660009081526009602090815260408083206001600160e01b03198516845290915290205460ff1692915050565b6103756107a7366004614ca1565b611bff565b6104bf6107ba3660046151a8565b611c11565b6102f66107cd366004614e19565b612107565b6102f66107e036600461515f565b612249565b6104bf6107f3366004614fc8565b601060209081526000928352604080842090915290825290205463ffffffff1681565b6102f6610824366004615378565b61226e565b6102f6610837366004615053565b6122a6565b61037561084a366004614db3565b63f23a6e6160e01b95945050505050565b61047261239c565b6102f66108713660046152a0565b6123ab565b60006001600160e01b03198216630a85bd0160e11b148061089b575061089b826124f0565b92915050565b600080516020615d448339815191526108b981612515565b81518351146108e35760405162461bcd60e51b81526004016108da90615742565b60405180910390fd5b60005b83518110156109595761094784828151811061091257634e487b7160e01b600052603260045260246000fd5b602002602001015184838151811061093a57634e487b7160e01b600052603260045260246000fd5b602002602001015161251f565b8061095181615cc9565b9150506108e6565b50505050565b600080516020615d4483398151915261097781612515565b6004548211156109995760405162461bcd60e51b81526004016108da90615718565b81600554146109dc5760058290556040518281527fada00761622e18474ad9efbe0dfbbcfdad01ffb7c67e8d41edce1369f8e66f28906020015b60405180910390a15b5050565b6000806109ec866125ce565b925050915060006109fb61239c565b9050806001600160a01b031663f25b27e66040518163ffffffff1660e01b815260040160206040518083038186803b158015610a3657600080fd5b505afa158015610a4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a6e9190614c85565b604051635d90c70b60e01b81526001600160a01b0388811660048301526001600160e01b0319881660248301529190911690635d90c70b90604401602060405180830381600087803b158015610ac357600080fd5b505af1158015610ad7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610afb919061512b565b610b405760405162461bcd60e51b8152602060048201526016602482015275125b9d985b1a5908185a5c991c9bdc081d185c99d95d60521b60448201526064016108da565b610b498261288a565b421115610b685760405162461bcd60e51b81526004016108da906157af565b336001600160a01b03841614610bb05760405162461bcd60e51b815260206004820152600d60248201526c27b7363c903137b93937bbb2b960991b60448201526064016108da565b8160e001516001600160a01b03166342842e0e308885604001516040518463ffffffff1660e01b8152600401610be89392919061559f565b600060405180830381600087803b158015610c0257600080fd5b505af1158015610c16573d6000803e3d6000fd5b505050506000866001600160a01b0316863387604051602401610c3a929190615603565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610c7891906154d6565b6000604051808303816000865af19150503d8060008114610cb5576040519150601f19603f3d011682016040523d82523d6000602084013e610cba565b606091505b5050905080610d025760405162461bcd60e51b8152602060048201526014602482015273115e1d195c9b985b0818d85b1b0819985a5b195960621b60448201526064016108da565b60008360e001516001600160a01b0316636352211e85604001516040518263ffffffff1660e01b8152600401610d3a91815260200190565b60206040518083038186803b158015610d5257600080fd5b505afa158015610d66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8a9190614c85565b90506001600160a01b0381163014610dd75760405162461bcd60e51b815260206004820152601060248201526f13999d081b9bdd081c995d1d5c9b995960821b60448201526064016108da565b60e084015160408086015181516001600160a01b0393841681526020810191909152918a169082015263ffffffff8a16907f0e4d608dd57d6ca7a07003c7307510df5d1a09141df82f3098e84525b87fb6159060600160405180910390a2505050505050505050565b7fc0bedf1ca774403872f60c2c5e429f68debcebd3902ee9f76b76f43ac063d413610e6a81612515565b60038410610eac5760405162461bcd60e51b815260206004820152600f60248201526e125b9d985b1a59081c5d595d595259608a1b60448201526064016108da565b336000600c8660038110610ed057634e487b7160e01b600052603260045260246000fd5b6001600160a01b0387166000908152910160209081526040808320878452909152812091505b8154811015610f5e57826001600160a01b0316828281548110610f2957634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b03161415610f4c57505050610959565b80610f5681615cc9565b915050610ef6565b5080546001808201835560008381526020902090910180546001600160a01b0319166001600160a01b03858116919091179091556040519087169188917ff67353fc70998a6f08087eae9321c87523ad583c1f248f11c4db223cd381be6791610fca9189918891615894565b60405180910390a3505050505050565b600082815260208190526040902060010154610ff581612515565b610fff83836128af565b505050565b3330146110455760405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b2329031b0b63632b960891b60448201526064016108da565b600061105382840184615378565b90506109598482612933565b6001600160a01b03811633146110cf5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016108da565b6109dc8282612a89565b600080516020615d448339815191526110f181612515565b6110f9612aee565b50565b604080518082019091526000808252602082015263ffffffff82166000908152600b6020908152604091829020825180840190935280546001600160401b03811684529091830190600160401b900460ff16600281111561116d57634e487b7160e01b600052602160045260246000fd5b600281111561118c57634e487b7160e01b600052602160045260246000fd5b90525092915050565b6002805414156111b75760405162461bcd60e51b81526004016108da906157d8565b600280558060016111c7826110fc565b6020015160028111156111ea57634e487b7160e01b600052602160045260246000fd5b146112075760405162461bcd60e51b81526004016108da90615785565b6000806000611215856125ce565b60e081015160408201519396509194509250906112328282612b3a565b600061123d8461288a565b90508042116112885760405162461bcd60e51b8152602060048201526017602482015276131bd85b881a5cc81b9bdd081bdd995c991d59481e595d604a1b60448201526064016108da565b336001600160a01b038616146112dc5760405162461bcd60e51b81526020600482015260196024820152784f6e6c79206c656e6465722063616e206c697175696461746560381b60448201526064016108da565b8351604080519182526020820184905281018290524260608201526001600160a01b038481166080830152808716919088169063ffffffff8b16907f4fac0ff43299a330bce57d0579985305af580acf256a6d7977083ede81be13269060a00160405180910390a4604051632142170760e11b81526001600160a01b038416906342842e0e906113749030908990879060040161559f565b600060405180830381600087803b15801561138e57600080fd5b505af11580156113a2573d6000803e3d6000fd5b505050506113af88612b48565b6001600160a01b03831660009081526010602090815260408083208584529091529020805463ffffffff191690556113e78383612b9c565b50506001600255505050505050565b600080516020615d4483398151915261140e81612515565b6005548210156114305760405162461bcd60e51b81526004016108da90615718565b81600454146109dc5760048290556040518281527f78e13060dd5049aaff2eee249c07301476e6e5b5a60c65116c3fd872c288e453906020016109d3565b6060600c846003811061149157634e487b7160e01b600052603260045260246000fd5b6001600160a01b03851660009081529101602090815260408083208584528252918290208054835181840281018401909452808452909183018282801561150157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116114e3575b505050505090505b9392505050565b600080516020615d4483398151915261152881612515565b6001600160a01b0382166115795760405162461bcd60e51b8152602060048201526018602482015277496e76616c6964207265636569766572206164647265737360401b60448201526064016108da565b6003546001600160a01b038381169116146109dc57600380546001600160a01b0319166001600160a01b0384169081179091556040517fb390a6eece33fc2616d0250e8cd5d72a2b7e0d6cb889791d36ec8892a045b094916109d391615561565b600080516020615d448339815191526115f281612515565b81518351146116135760405162461bcd60e51b81526004016108da90615742565b60005b83518110156109595761167784828151811061164257634e487b7160e01b600052603260045260246000fd5b602002602001015184838151811061166a57634e487b7160e01b600052603260045260246000fd5b6020026020010151612baa565b8061168181615cc9565b915050611616565b600080516020615d448339815191526116a181612515565b6110f9612c50565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60006116dd81612515565b60005b845181101561180757600085828151811061170b57634e487b7160e01b600052603260045260246000fd5b60200260200101519050806001600160a01b031663f242432a308988868151811061174657634e487b7160e01b600052603260045260246000fd5b602002602001015188878151811061176e57634e487b7160e01b600052603260045260246000fd5b60209081029190910101516040516001600160e01b031960e087901b1681526001600160a01b0394851660048201529390921660248401526044830152606482015260a06084820152600060a482015260c401600060405180830381600087803b1580156117db57600080fd5b505af11580156117ef573d6000803e3d6000fd5b505050505080806117ff90615cc9565b9150506116e0565b505050505050565b7fc0bedf1ca774403872f60c2c5e429f68debcebd3902ee9f76b76f43ac063d41361183981612515565b336000600c866003811061185d57634e487b7160e01b600052603260045260246000fd5b6001600160a01b0387166000908152910160209081526040808320878452909152812091505b81548110156118e857826001600160a01b03168282815481106118b657634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031614156118d6576118e8565b806118e081615cc9565b915050611883565b600381146118fc576118fc87878784612c8b565b50505050505050565b600080516020615d4483398151915261191d81612515565b61271061ffff8316111561196a5760405162461bcd60e51b81526020600482015260146024820152730626173697320706f696e7473203e2031303030360641b60448201526064016108da565b60065461ffff8381169116146109dc576006805461ffff191661ffff84169081179091556040519081527f03017365bbe16943b524030df07e7689168ab63e854d27417498e6f9dc584dab906020016109d3565b428110611a015760405162461bcd60e51b81526020600482015260116024820152700496e76616c69642074696d657374616d7607c1b60448201526064016108da565b336000908152601260205260409020548111156110f9573360008181526012602052604090819020839055517fe7258d55b23f4902343add21f328e6d35c5d58bff7fe8bda6f1df7851f04d36a91611a5a918490615627565b60405180910390a150565b6000611a7081612515565b6001600160a01b038416611ab85760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016108da565b60005b8351811015611b48576000848281518110611ae657634e487b7160e01b600052603260045260246000fd5b60200260200101519050611b3586858481518110611b1457634e487b7160e01b600052603260045260246000fd5b6020026020010151836001600160a01b0316612e4f9092919063ffffffff16565b5080611b4081615cc9565b915050611abb565b5050505050565b33600090815260116020908152604080832084845290915290205460ff1615611baa5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b60448201526064016108da565b33600081815260116020908152604080832085845290915290819020805460ff19166001179055517f26ccf9904b9b2fb069d347553978928fd2fc65efb2638dcbeb8d142e974479f091611a5a918490615627565b63bc197c8160e01b5b95945050505050565b6000611c1b612ea5565b600280541415611c3d5760405162461bcd60e51b81526004016108da906157d8565b60028055611c52611c4d88615b88565b612eed565b6000611c646060890160408a01614c69565b9050611c7081886130a8565b6000611c85611c7e8a615b88565b89896130b6565b9050611cac611c938a615b88565b8989611c9e8a615c1c565b611ca78a615c1c565b61313b565b6000611cb661239c565b9050806001600160a01b0316630b0bba1e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611cf157600080fd5b505afa158015611d05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d299190614c85565b6001600160a01b031663df777835611d4760608a0160408b01614c69565b338d6080016020810190611d5b9190614c69565b8e600001356040518563ffffffff1660e01b8152600401611d7f9493929190615575565b600060405180830381600087803b158015611d9957600080fd5b505af1158015611dad573d6000803e3d6000fd5b5060009250611dc29150506020870187614c69565b6001600160a01b031614611f4d57611df0611de06020870187614c69565b610762604088016020890161518e565b611e2f5760405162461bcd60e51b815260206004820152601060248201526f139bdd081d985b1a5919481859d95b9d60821b60448201526064016108da565b6000611e41604087016020880161518e565b33611e4f6040890189615998565b604051602401611e61939291906155c3565b60408051601f19818403018152919052602080820180516001600160e01b03166001600160e01b0319909416939093179092529150600090611ea590880188614c69565b6001600160a01b031682604051611ebc91906154d6565b6000604051808303816000865af19150503d8060008114611ef9576040519150601f19603f3d011682016040523d82523d6000602084013e611efe565b606091505b5050905080611f4a5760405162461bcd60e51b8152602060048201526018602482015277109bdc9c9bddc8195e1d1c984818d85b1b0819985a5b195960421b60448201526064016108da565b50505b806001600160a01b0316630b0bba1e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611f8657600080fd5b505afa158015611f9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fbe9190614c85565b6001600160a01b03166342f1a2563330868d6040518563ffffffff1660e01b8152600401611fef9493929190615575565b600060405180830381600087803b15801561200957600080fd5b505af115801561201d573d6000803e3d6000fd5b5050505060006120528860400160208101906120399190614c69565b33856120448c615c1c565b61204d8b615b16565b613288565b90506120736120608c615b88565b8261206e60208a018a614c69565b6133f3565b6001600160a01b03841660009081526010602090815260408083208d84529091529020805463ffffffff191663ffffffff83161790556120b3848b613699565b60405160608701358152339063ffffffff8316907ff7b9c21907a3ce171a12296161a29b2ba931964bb680f1b61cebd8ab251cec989060200160405180910390a360016002559a9950505050505050505050565b600061211281612515565b60005b8351811015611b4857600084828151811061214057634e487b7160e01b600052603260045260246000fd5b60200260200101519050600084838151811061216c57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b0384166000908152601083526040808220838352909352919091205490915063ffffffff168061223357826001600160a01b03166342842e0e308a8988815181106121da57634e487b7160e01b600052603260045260246000fd5b60200260200101516040518463ffffffff1660e01b81526004016122009392919061559f565b600060405180830381600087803b15801561221a57600080fd5b505af115801561222e573d6000803e3d6000fd5b505050505b505050808061224190615cc9565b915050612115565b60008281526020819052604090206001015461226481612515565b610fff8383612a89565b6002805414156122905760405162461bcd60e51b81526004016108da906157d8565b6002805561229e3382612933565b506001600255565b7f37442f0e5201d32aba04d9e4c019aaed797c0adefd44367a782d9bb1c3a244386122d081612515565b815184511480156122e2575081518351145b6122fe5760405162461bcd60e51b81526004016108da90615742565b60005b8451811015611b485761238a85828151811061232d57634e487b7160e01b600052603260045260246000fd5b602002602001015185838151811061235557634e487b7160e01b600052603260045260246000fd5b602002602001015185848151811061237d57634e487b7160e01b600052603260045260246000fd5b60200260200101516136a6565b8061239481615cc9565b915050612301565b600a546001600160a01b031690565b600080516020615d448339815191526123c381612515565b60005b838110156118fc576000600c88600381106123f157634e487b7160e01b600052603260045260246000fd5b6001600160a01b03891660009081529101602052604081209087878581811061242a57634e487b7160e01b600052603260045260246000fd5b905060200201358152602001908152602001600020905060005b81548110156124db57846001600160a01b031682828154811061247757634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031614156124c9576124c489898989878181106124b757634e487b7160e01b600052603260045260246000fd5b9050602002013584612c8b565b6124db565b806124d381615cc9565b915050612444565b505080806124e890615cc9565b9150506123c6565b60006001600160e01b03198216630271189760e51b148061089b575061089b82613786565b6110f981336137bb565b6001600160a01b03821661256e5760405162461bcd60e51b8152602060048201526016602482015275657263373231206973207a65726f206164647265737360501b60448201526064016108da565b6001600160a01b038216600081815260086020908152604091829020805460ff191685151590811790915591519182527f3e0c443872dd01e15f6ca1f8ee12f284a44836f46012e421d74611bf80eda7c191015b60405180910390a25050565b6000806125d9614a09565b60006125e4856110fc565b5163ffffffff8681166000908152600f60209081526040918290208251610120810184528154815260018201549281019290925260028101549282019290925260038201546001600160a01b038082166060840152600160a01b82049094166080830152600160c01b900461ffff1660a08201526004909101546001600160401b0380821660c0840152600160401b820490931660e0830152600160e01b900460ff161515610100820152935016905061269c61239c565b6001600160a01b031663681dee566040518163ffffffff1660e01b815260040160206040518083038186803b1580156126d457600080fd5b505afa1580156126e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061270c9190614c85565b6001600160a01b0316636352211e826040518263ffffffff1660e01b815260040161273991815260200190565b60206040518083038186803b15801561275157600080fd5b505afa158015612765573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127899190614c85565b935061279361239c565b6001600160a01b031663d1d261d06040518163ffffffff1660e01b815260040160206040518083038186803b1580156127cb57600080fd5b505afa1580156127df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128039190614c85565b6001600160a01b0316636352211e826040518263ffffffff1660e01b815260040161283091815260200190565b60206040518083038186803b15801561284857600080fd5b505afa15801561285c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128809190614c85565b9250509193909250565b6000816080015163ffffffff168260c001516001600160401b031661089b9190615a80565b6128b982826116a9565b6109dc576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556128ef3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b80600161293f826110fc565b60200151600281111561296257634e487b7160e01b600052602160045260246000fd5b1461297f5760405162461bcd60e51b81526004016108da90615785565b600080600061298d856125ce565b92509250925061299c8161288a565b4211156129bb5760405162461bcd60e51b81526004016108da906157af565b60e081015160408201516129cf828261381f565b604051632142170760e11b81526001600160a01b038316906342842e0e906129ff9030908990869060040161559f565b600060405180830381600087803b158015612a1957600080fd5b505af1158015612a2d573d6000803e3d6000fd5b50505050612a3e8886868a8761382c565b612a4787612b48565b6001600160a01b03821660009081526010602090815260408083208484529091529020805463ffffffff19169055612a7f8282613a88565b5050505050505050565b612a9382826116a9565b156109dc576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b612af6613a96565b6001805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b604051612b309190615561565b60405180910390a1565b6109dc600260018484613adf565b612b5181613d22565b63ffffffff166000908152600f602052604081208181556001810182905560028101919091556003810180546001600160d01b031916905560040180546001600160e81b0319169055565b6109dc600260008484613adf565b6001600160a01b038216612bf85760405162461bcd60e51b81526020600482015260156024820152746572633230206973207a65726f206164647265737360581b60448201526064016108da565b6001600160a01b038216600081815260076020908152604091829020805460ff191685151590811790915591519182527ff100355be652ecc881568750e6a98c0713e4316f75d5314ebc9039e0acb52f2491016125c2565b612c58612ea5565b6001805460ff1916811790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833612b23565b6000600c8560038110612cae57634e487b7160e01b600052603260045260246000fd5b6001600160a01b038616600090815291016020908152604080832086845290915281208054909250829084908110612cf657634e487b7160e01b600052603260045260246000fd5b600091825260208220015483546001600160a01b039091169250612d1c90600190615aff565b905080841015612db9576000838281548110612d4857634e487b7160e01b600052603260045260246000fd5b9060005260206000200160009054906101000a90046001600160a01b0316905080848681548110612d8957634e487b7160e01b600052603260045260246000fd5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505b82805480612dd757634e487b7160e01b600052603160045260246000fd5b6001900381819060005260206000200160006101000a8154906001600160a01b0302191690559055856001600160a01b0316877ff67353fc70998a6f08087eae9321c87523ad583c1f248f11c4db223cd381be6787856000604051612e3e93929190615894565b60405180910390a350505050505050565b610fff8363a9059cbb60e01b8484604051602401612e6e929190615627565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613f0c565b60015460ff1615612eeb5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108da565b565b60808101516001600160a01b031660009081526007602052604090205460ff16612f4c5760405162461bcd60e51b815260206004820152601060248201526f496e76616c69642063757272656e637960801b60448201526064016108da565b6040808201516001600160a01b031660009081526008602052205460ff16612fad5760405162461bcd60e51b815260206004820152601460248201527324b73b30b634b21022a9219b9918903a37b5b2b760611b60448201526064016108da565b600454816060015163ffffffff1611156130045760405162461bcd60e51b815260206004820152601860248201527724b73b30b634b21036b0bc34b6bab690323ab930ba34b7b760411b60448201526064016108da565b600554816060015163ffffffff16101561305b5760405162461bcd60e51b815260206004820152601860248201527724b73b30b634b21036b4b734b6bab690323ab930ba34b7b760411b60448201526064016108da565b8051602082015110156110f95760405162461bcd60e51b8152602060048201526015602482015274496e76616c696420696e746572657374207261746560581b60448201526064016108da565b6109dc600060018484613adf565b6130be614a09565b5060408051610120810182528451815260208086015190820152808201939093526080808501516001600160a01b0390811660608087019190915286015163ffffffff169185019190915260065461ffff1660a0850152426001600160401b031660c085015293015190921660e082015290151561010082015290565b6040808301516001600160a01b038116600090815260116020908152838220865183529052919091205460ff16156131ac5760405162461bcd60e51b815260206004820152601460248201527313195b99195c881b9bdb98d9481a5b9d985b1a5960621b60448201526064016108da565b6131da7f2aeb38be3df14d720aeb10a2de6df09b0fb3cd5c5ec256283a22d4593110ca4083604001516116a9565b61321e5760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b210313937b5b2b91039b4b3b732b960591b60448201526064016108da565b60a08601516001600160a01b0382166000908152601260205260409020541061327b5760405162461bcd60e51b815260206004820152600f60248201526e13d999995c8818d85b98d95b1b1959608a1b60448201526064016108da565b6118078686868686613fde565b6001600160a01b0385166000908152601160209081526040808320855184529091528120805460ff19166001179055806132c2878761420c565b63ffffffff8082166000818152600f60209081526040918290208a518155818b01516001820155828b0151600282015560608b015160038201805460808e015160a08f015161ffff16600160c01b0261ffff60c01b1991909916600160a01b026001600160c01b03199092166001600160a01b039485161791909117169690961790955560c08b01516004909101805460e08d01516101008e01511515600160e01b0260ff60e01b19918916600160401b026001600160e01b03199093166001600160401b039095169490941791909117169190911790558882015189518951928a0151935196975094169433947ff2605177b2b695bc687a0fb9ac9e447ba4b6a02145b2f335fb749308678cb1cb936133e19391928d9291906158d4565b60405180910390a49695505050505050565b6001600160a01b03811615610fff57600061340c61239c565b90506000846040015190506000856000015190506000866080015190506000846001600160a01b03166311a1933c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561346457600080fd5b505afa158015613478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061349c9190614c85565b90506000806001600160a01b0383161561368d576040516315ee833560e21b81526001600160a01b03898116600483015233602483015287811660448301528416906357ba0cd49060640160206040518083038186803b1580156134ff57600080fd5b505afa158015613513573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135379190615284565b915061ffff82161561363c5761271061355461ffff841687615ae0565b61355e9190615ac0565b9050866001600160a01b0316630b0bba1e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561359957600080fd5b505afa1580156135ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135d19190614c85565b60035460405163df77783560e01b81526001600160a01b039283169263df777835926136099233929091169089908790600401615575565b600060405180830381600087803b15801561362357600080fd5b505af1158015613637573d6000803e3d6000fd5b505050505b6040805161ffff84168152602081018390526001600160a01b038a169163ffffffff8c16917f6b0714b8faf060425ff50a36726d7dbfab63b9e3c17515f10290fd04ec946e27910160405180910390a35b50505050505050505050565b6109dc6000808484613adf565b6001600160a01b038316158015906136c757506001600160e01b0319821615155b61370b5760405162461bcd60e51b81526020600482015260156024820152746167656e74206973207a65726f206164647265737360581b60448201526064016108da565b6001600160a01b03831660008181526009602090815260408083206001600160e01b0319871680855290835292819020805460ff19168615159081179091558151938452918301919091527feef855269fc053a84572ea142b53ab4a0e276e2346315c1c1622587f971ee4a3910160405180910390a2505050565b60006001600160e01b03198216637965db0b60e01b148061089b57506301ffc9a760e01b6001600160e01b031983161461089b565b6137c582826116a9565b6109dc576137dd816001600160a01b031660146144ed565b6137e88360206144ed565b6040516020016137f99291906154f2565b60408051601f198184030181529082905262461bcd60e51b82526108da916004016156ce565b6109dc6001808484613adf565b600080613838836146ce565b91509150600061384661239c565b9050806001600160a01b0316630b0bba1e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561388157600080fd5b505afa158015613895573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138b99190614c85565b6001600160a01b031663df77783589888760600151866040518563ffffffff1660e01b81526004016138ee9493929190615575565b600060405180830381600087803b15801561390857600080fd5b505af115801561391c573d6000803e3d6000fd5b50505050806001600160a01b0316630b0bba1e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561395957600080fd5b505afa15801561396d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139919190614c85565b600354606086015160405163df77783560e01b81526001600160a01b039384169363df777835936139cd938e9392909116918990600401615575565b600060405180830381600087803b1580156139e757600080fd5b505af11580156139fb573d6000803e3d6000fd5b5050855160408088015160e08901516060808b0151845195865260208601939093529284018890529183018890526001600160a01b039182166080840152811660a0830152808a1693508a16915063ffffffff8816907f6ee3573bd905753c83bc1aaca3c15bfa36391db95b778bd825eb010645a7ee459060c00160405180910390a45050505050505050565b6109dc600160008484613adf565b60015460ff16612eeb5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016108da565b6000600c8560038110613b0257634e487b7160e01b600052603260045260246000fd5b6001600160a01b038516600090815291016020908152604080832085845282529182902080548351818402810184019094528084529091830182828015613b7257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613b54575b5050505050905060005b8151811015611807578415613c1957818181518110613bab57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031663619452ef8786866040518463ffffffff1660e01b8152600401613be2939291906158b5565b600060405180830381600087803b158015613bfc57600080fd5b505af1158015613c10573d6000803e3d6000fd5b50505050613ca3565b818181518110613c3957634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316634f297ecd8786866040518463ffffffff1660e01b8152600401613c70939291906158b5565b600060405180830381600087803b158015613c8a57600080fd5b505af1158015613c9e573d6000803e3d6000fd5b505050505b836001600160a01b0316867f9125866eb9cfb156e40aea5aea2cf396c4a72b7c8e86c7e8c7c091324bf6370085858581518110613cf057634e487b7160e01b600052603260045260246000fd5b602002602001015189604051613d0893929190615894565b60405180910390a380613d1a81615cc9565b915050613b7c565b63ffffffff81166000908152600b6020526040902060018154600160401b900460ff166002811115613d6457634e487b7160e01b600052602160045260246000fd5b14613da95760405162461bcd60e51b81526020600482015260156024820152744c6f616e206973206e6f742061206e6577206f6e6560581b60448201526064016108da565b805460ff60401b1916600160411b178155600080613dc5614725565b8454604051630852cd8d60e31b81526001600160401b03909116600482015291935091506001600160a01b038216906342966c6890602401600060405180830381600087803b158015613e1757600080fd5b505af1158015613e2b573d6000803e3d6000fd5b50508454604051630852cd8d60e31b81526001600160401b0390911660048201526001600160a01b03851692506342966c689150602401600060405180830381600087803b158015613e7c57600080fd5b505af1158015613e90573d6000803e3d6000fd5b505084546040516001600160401b03909116925063ffffffff871691507fa99afb24dca45e3cebef49cd6184255e4623c0bf6c5e87bb6738629ceefa2dac90613edb906002906156c0565b60405180910390a350505063ffffffff166000908152600b60205260409020805468ffffffffffffffffff19169055565b6000613f61826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166148889092919063ffffffff16565b805190915015610fff5780806020019051810190613f7f919061512b565b610fff5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108da565b821561408e5760405163dd90aba160e01b8152736a7acf3feb58fcf15f74b73391c78a879f7c9e359063dd90aba19061401d908890869060040161583a565b60206040518083038186803b15801561403557600080fd5b505af4158015614049573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061406d919061512b565b6140895760405162461bcd60e51b81526004016108da906156e1565b614135565b60405163a9170a7f60e01b8152736a7acf3feb58fcf15f74b73391c78a879f7c9e359063a9170a7f906140c99088908890879060040161585f565b60206040518083038186803b1580156140e157600080fd5b505af41580156140f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614119919061512b565b6141355760405162461bcd60e51b81526004016108da906156e1565b60405163a9170a7f60e01b8152736a7acf3feb58fcf15f74b73391c78a879f7c9e359063a9170a7f906141709088908890869060040161585f565b60206040518083038186803b15801561418857600080fd5b505af415801561419c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141c0919061512b565b611b485760405162461bcd60e51b815260206004820152601b60248201527f5369676e6572207369676e617475726520697320696e76616c6964000000000060448201526064016108da565b60006001600a60148282829054906101000a900463ffffffff166142309190615a98565b82546101009290920a63ffffffff81810219909316919092169190910217905550600a546040513060601b6bffffffffffffffffffffffff19166020820152600160a01b90910460e01b6001600160e01b031916603482015260009060380160408051808303601f1901815282825280516020918201208383019092526001600160401b038216835260019083015291506000806142cc614725565b600a5460408051600160a01b90920463ffffffff1660208301529294509092506001600160a01b038316916394d008ef918a918891016040516020818303038152906040526040518463ffffffff1660e01b815260040161432f93929190615640565b600060405180830381600087803b15801561434957600080fd5b505af115801561435d573d6000803e3d6000fd5b5050600a5460408051600160a01b90920463ffffffff1660208301526001600160a01b03861693506394d008ef925089918891016040516020818303038152906040526040518463ffffffff1660e01b81526004016143be93929190615640565b600060405180830381600087803b1580156143d857600080fd5b505af11580156143ec573d6000803e3d6000fd5b5050600a5463ffffffff600160a01b909104166000908152600b60209081526040909120865181546001600160401b0390911667ffffffffffffffff19821681178355928801518895509193509091839168ffffffffffffffffff191617600160401b83600281111561446f57634e487b7160e01b600052602160045260246000fd5b0217905550905050836001600160401b0316600a60149054906101000a900463ffffffff1663ffffffff167fa99afb24dca45e3cebef49cd6184255e4623c0bf6c5e87bb6738629ceefa2dac60016040516144ca91906156c0565b60405180910390a35050600a54600160a01b900463ffffffff1695945050505050565b606060006144fc836002615ae0565b614507906002615a80565b6001600160401b0381111561452c57634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015614556576020820181803683370190505b509050600360fc1b8160008151811061457f57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106145bc57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060006145e0846002615ae0565b6145eb906001615a80565b90505b600181111561467f576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061462d57634e487b7160e01b600052603260045260246000fd5b1a60f81b82828151811061465157634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535060049490941c9361467881615cb2565b90506145ee565b5083156115095760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016108da565b6000806000836000015184602001516146e79190615aff565b60a0850151909150612710906147019061ffff1683615ae0565b61470b9190615ac0565b925082846020015161471d9190615aff565b915050915091565b6000806000306001600160a01b031663f8c689346040518163ffffffff1660e01b815260040160206040518083038186803b15801561476357600080fd5b505afa158015614777573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061479b9190614c85565b9050806001600160a01b031663681dee566040518163ffffffff1660e01b815260040160206040518083038186803b1580156147d657600080fd5b505afa1580156147ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061480e9190614c85565b9250806001600160a01b031663d1d261d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561484957600080fd5b505afa15801561485d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148819190614c85565b9150509091565b6060614897848460008561489f565b949350505050565b6060824710156149005760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016108da565b6001600160a01b0385163b6149575760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108da565b600080866001600160a01b0316858760405161497391906154d6565b60006040518083038185875af1925050503d80600081146149b0576040519150601f19603f3d011682016040523d82523d6000602084013e6149b5565b606091505b50915091506149c58282866149d0565b979650505050505050565b606083156149df575081611509565b8251156149ef5782518084602001fd5b8160405162461bcd60e51b81526004016108da91906156ce565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b8035614a6081615d10565b919050565b600082601f830112614a75578081fd5b81356020614a8a614a8583615a5d565b615a2d565b80838252828201915082860187848660051b8901011115614aa9578586fd5b855b85811015614ad0578135614abe81615d10565b84529284019290840190600101614aab565b5090979650505050505050565b600082601f830112614aed578081fd5b81356020614afd614a8583615a5d565b80838252828201915082860187848660051b8901011115614b1c578586fd5b855b85811015614ad0578135614b3181615d25565b84529284019290840190600101614b1e565b600082601f830112614b53578081fd5b81356020614b63614a8583615a5d565b80838252828201915082860187848660051b8901011115614b82578586fd5b855b85811015614ad057813584529284019290840190600101614b84565b8035614a6081615d25565b80356001600160e01b031981168114614a6057600080fd5b600082601f830112614bd3578081fd5b81356001600160401b03811115614bec57614bec615cfa565b614bff601f8201601f1916602001615a2d565b818152846020838601011115614c13578283fd5b816020850160208301379081016020019190915292915050565b600060808284031215614c3e578081fd5b50919050565b600060e08284031215614c3e578081fd5b803563ffffffff81168114614a6057600080fd5b600060208284031215614c7a578081fd5b813561150981615d10565b600060208284031215614c96578081fd5b815161150981615d10565b600080600080600060a08688031215614cb8578081fd5b8535614cc381615d10565b94506020860135614cd381615d10565b935060408601356001600160401b0380821115614cee578283fd5b614cfa89838a01614b43565b94506060880135915080821115614d0f578283fd5b614d1b89838a01614b43565b93506080880135915080821115614d30578283fd5b50614d3d88828901614bc3565b9150509295509295909350565b60008060008060808587031215614d5f578182fd5b8435614d6a81615d10565b93506020850135614d7a81615d10565b92506040850135915060608501356001600160401b03811115614d9b578182fd5b614da787828801614bc3565b91505092959194509250565b600080600080600060a08688031215614dca578283fd5b8535614dd581615d10565b94506020860135614de581615d10565b9350604086013592506060860135915060808601356001600160401b03811115614e0d578182fd5b614d3d88828901614bc3565b600080600060608486031215614e2d578081fd5b8335614e3881615d10565b925060208401356001600160401b0380821115614e53578283fd5b614e5f87838801614a65565b93506040860135915080821115614e74578283fd5b50614e8186828701614b43565b9150509250925092565b60008060008060808587031215614ea0578182fd5b8435614eab81615d10565b935060208501356001600160401b0380821115614ec6578384fd5b614ed288838901614a65565b94506040870135915080821115614ee7578384fd5b614ef388838901614b43565b93506060870135915080821115614f08578283fd5b50614da787828801614b43565b60008060408385031215614f27578182fd5b8235614f3281615d10565b9150614f4060208401614bab565b90509250929050565b600080600060408486031215614f5d578081fd5b8335614f6881615d10565b925060208401356001600160401b0380821115614f83578283fd5b818601915086601f830112614f96578283fd5b813581811115614fa4578384fd5b876020828501011115614fb5578384fd5b6020830194508093505050509250925092565b60008060408385031215614fda578182fd5b8235614fe581615d10565b946020939093013593505050565b60008060408385031215615005578182fd5b82356001600160401b038082111561501b578384fd5b61502786838701614a65565b9350602085013591508082111561503c578283fd5b5061504985828601614add565b9150509250929050565b600080600060608486031215615067578081fd5b83356001600160401b038082111561507d578283fd5b61508987838801614a65565b945060209150818601358181111561509f578384fd5b8601601f810188136150af578384fd5b80356150bd614a8582615a5d565b8082825285820191508584018b878560051b87010111156150dc578788fd5b8794505b83851015615105576150f181614bab565b8352600194909401939186019186016150e0565b509650505050604086013591508082111561511e578283fd5b50614e8186828701614add565b60006020828403121561513c578081fd5b815161150981615d25565b600060208284031215615158578081fd5b5035919050565b60008060408385031215615171578182fd5b82359150602083013561518381615d10565b809150509250929050565b60006020828403121561519f578081fd5b61150982614bab565b60008060008060008060c087890312156151c0578384fd5b86356001600160401b03808211156151d6578586fd5b6151e28a838b01614c44565b9750602089013596506151f760408a01614ba0565b9550606089013591508082111561520c578283fd5b6152188a838b01614c2d565b9450608089013591508082111561522d578283fd5b6152398a838b01614c2d565b935060a089013591508082111561524e578283fd5b5061525b89828a01614c2d565b9150509295509295509295565b600060208284031215615279578081fd5b813561150981615d33565b600060208284031215615295578081fd5b815161150981615d33565b6000806000806000608086880312156152b7578283fd5b8535945060208601356152c981615d10565b935060408601356001600160401b03808211156152e4578485fd5b818801915088601f8301126152f7578485fd5b813581811115615305578586fd5b8960208260051b8501011115615319578586fd5b602083019550809450505050606086013561533381615d10565b809150509295509295909350565b600080600060608486031215615355578081fd5b83359250602084013561536781615d10565b929592945050506040919091013590565b600060208284031215615389578081fd5b61150982614c55565b600080600080608085870312156153a7578182fd5b6153b085614c55565b935060208501356153c081615d10565b92506153ce60408601614bab565b915060608501356001600160401b03811115614d9b578182fd5b60008151808452615400816020860160208601615c86565b601f01601f19169290920160200192915050565b6003811061543257634e487b7160e01b600052602160045260246000fd5b9052565b80518252602081015160208301526000604082015160018060a01b03808216604086015263ffffffff6060850151166060860152806080850151166080860152505060a082015160a084015260c082015160e060c085015261489760e08501826153e8565b805182526020810151602083015260018060a01b036040820151166040830152600060608201516080606085015261489760808501826153e8565b600082516154e8818460208701615c86565b9190910192915050565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b815260008351615524816017850160208801615c86565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615555816028840160208801615c86565b01602801949350505050565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b6001600160a01b0383168152604060208201819052600090614897908301846153e8565b6001600160a01b03929092168252602082015260400190565b6001600160a01b03841681526001600160401b0383166020820152606060408201819052600090611c08908301846153e8565b6020808252825182820181905260009190848201906040850190845b818110156156b45783516001600160a01b03168352928401929184019160010161568f565b50909695505050505050565b6020810161089b8284615414565b60208152600061150960208301846153e8565b6020808252601b908201527f4c656e646572207369676e617475726520697320696e76616c69640000000000604082015260600190565b60208082526010908201526f24b73b30b634b210323ab930ba34b7b760811b604082015260600190565b60208082526023908201527f6164647265737320616e64207065726d697473206c656e677468206d69736d616040820152620e8c6d60eb1b606082015260800190565b60208082526010908201526f2637b0b71034b9903737ba1037b832b760811b604082015260600190565b6020808252600f908201526e131bd85b881a5cc8195e1c1a5c9959608a1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b81516001600160401b03168152602080830151604083019161583390840182615414565b5092915050565b60408152600061584d6040830185615436565b8281036020840152611c08818561549b565b6060815260006158726060830186615436565b846020840152828103604084015261588a818561549b565b9695505050505050565b9283526001600160a01b039190911660208301521515604082015260600190565b9283526001600160a01b03919091166020830152604082015260600190565b60006101808201905085825284516020830152602085015160408301526040850151606083015260018060a01b036060860151166080830152608085015161592460a084018263ffffffff169052565b5060a085015161ffff811660c08401525060c08501516001600160401b03811660e08401525060e0850151610100615966818501836001600160a01b03169052565b8601511515610120840152506001600160a01b0384166101408301526001600160e01b03198316610160830152611c08565b6000808335601e198436030181126159ae578283fd5b8301803591506001600160401b038211156159c7578283fd5b6020019150368190038213156159dc57600080fd5b9250929050565b604051608081016001600160401b0381118282101715615a0557615a05615cfa565b60405290565b60405160e081016001600160401b0381118282101715615a0557615a05615cfa565b604051601f8201601f191681016001600160401b0381118282101715615a5557615a55615cfa565b604052919050565b60006001600160401b03821115615a7657615a76615cfa565b5060051b60200190565b60008219821115615a9357615a93615ce4565b500190565b600063ffffffff808316818516808303821115615ab757615ab7615ce4565b01949350505050565b600082615adb57634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615afa57615afa615ce4565b500290565b600082821015615b1157615b11615ce4565b500390565b600060808236031215615b27578081fd5b615b2f6159e3565b8235615b3a81615d10565b8152615b4860208401614bab565b602082015260408301356001600160401b03811115615b65578283fd5b615b7136828601614bc3565b604083015250606092830135928101929092525090565b600060e08236031215615b99578081fd5b615ba1615a0b565b8235815260208301356020820152615bbb60408401614a55565b6040820152615bcc60608401614c55565b6060820152615bdd60808401614a55565b608082015260a083013560a082015260c08301356001600160401b03811115615c04578283fd5b615c1036828601614bc3565b60c08301525092915050565b600060808236031215615c2d578081fd5b615c356159e3565b82358152602083013560208201526040830135615c5181615d10565b604082015260608301356001600160401b03811115615c6e578283fd5b615c7a36828601614bc3565b60608301525092915050565b60005b83811015615ca1578181015183820152602001615c89565b838111156109595750506000910152565b600081615cc157615cc1615ce4565b506000190190565b6000600019821415615cdd57615cdd615ce4565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146110f957600080fd5b80151581146110f957600080fd5b61ffff811681146110f957600080fdfeaf290d8680820aad922855f39b306097b20e28774d6c1ad35a20325630c3a02ca2646970667358221220738ba32f118f5ccf85ded19a16c1e1b712bfadefc4b3f8ffe8a9304e9ce127bd64736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002087d218c030d47a564d336385ddffafaad5520800000000000000000000000021a619115f36de1a71b549e9081022fe84136f65
-----Decoded View---------------
Arg [0] : _admin (address): 0x2087D218c030d47A564D336385ddFfAFAAD55208
Arg [1] : _addressProvider (address): 0x21A619115F36dE1A71B549e9081022fe84136f65
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000002087d218c030d47a564d336385ddffafaad55208
Arg [1] : 00000000000000000000000021a619115f36de1a71b549e9081022fe84136f65
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.