Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 7 from a total of 7 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Liquidate Expire... | 15532834 | 878 days ago | IN | 0 ETH | 0.00146577 | ||||
Accept Offer | 15496199 | 884 days ago | IN | 0 ETH | 0.00513883 | ||||
Liquidate Expire... | 15495342 | 884 days ago | IN | 0 ETH | 0.0038382 | ||||
Accept Offer | 15485943 | 886 days ago | IN | 0 ETH | 0.0104754 | ||||
Accept Offer | 15485188 | 886 days ago | IN | 0 ETH | 0.00147748 | ||||
Set ERC20Permits | 15458102 | 890 days ago | IN | 0 ETH | 0.00176995 | ||||
Update Admin Fee | 15458094 | 890 days ago | IN | 0 ETH | 0.00034231 |
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 Source Code Verified (Exact Match)
Contract Name:
LoanSimple
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "./LoanCommonEssential.sol"; import "../../utils/KeysMapping.sol"; contract LoanSimple is LoanCommonEssential { bytes32 public constant LOAN_TYPE = bytes32("DIRECT_LOAN_FIXED_OFFER"); constructor( address _admin, address _dispatcher, address[] memory _allowedERC20s ) LoanCommonEssential( _admin, _dispatcher, KeysMapping.keyToId("DIRECT_LOAN_COORDINATOR"), _allowedERC20s ) { // solhint-disable-previous-line no-empty-blocks } function acceptOffer( Offer memory _offer, Signature memory _signature, BorrowerSettings memory _borrowerSettings ) external whenNotPaused nonReentrant { address nftWrapper = _getWrapper(_offer.nftCollateralContract); _loanSanityChecks(_offer, nftWrapper); _loanSanityChecksOffer(_offer); _acceptOffer( LOAN_TYPE, _setupLoanTerms(_offer, nftWrapper), _setupLoanExtras(_borrowerSettings.revenueSharePartner, _borrowerSettings.referralFeeInBasisPoints), _offer, _signature ); } function computePayoffAmount(uint32 _loanId) external view override returns (uint256) { LoanTerms storage loan = loanIdToLoan[_loanId]; return loan.maximumRepaymentAmount; } function _acceptOffer( bytes32 _loanType, LoanTerms memory _loanTerms, LoanExtras memory _loanExtras, Offer memory _offer, Signature memory _signature ) internal { require(!_nonceHasBeenUsedForUser[_signature.signer][_signature.nonce], "Lender nonce invalid"); _nonceHasBeenUsedForUser[_signature.signer][_signature.nonce] = true; require(SignHelper.checkLenderSignatureValidity(_offer, _signature), "Lender signature is invalid"); address bundle = hub.getContract(KeysMapping.LIQUIDOTS_BUNDLER); require(_loanTerms.nftCollateralContract != bundle, "Collateral cannot be bundle"); uint32 loanId = _createLoan(_loanType, _loanTerms, _loanExtras, msg.sender, _signature.signer, _offer.referrer); // Emit an event with all relevant details from this transaction. emit LoanStarted(loanId, msg.sender, _signature.signer, _loanTerms, _loanExtras); } function _setupLoanTerms(Offer memory _offer, address _nftWrapper) internal view returns (LoanTerms memory) { return LoanTerms({ loanERC20Denomination: _offer.loanERC20Denomination, loanPrincipalAmount: _offer.loanPrincipalAmount, maximumRepaymentAmount: _offer.maximumRepaymentAmount, nftCollateralContract: _offer.nftCollateralContract, nftCollateralWrapper: _nftWrapper, nftCollateralId: _offer.nftCollateralId, loanStartTime: uint64(block.timestamp), loanDuration: _offer.loanDuration, loanInterestRateForDurationInBasisPoints: uint16(0), loanAdminFeeInBasisPoints: _offer.loanAdminFeeInBasisPoints, borrower: msg.sender }); } function _payoffAndFee(LoanTerms memory _loanTerms) internal pure override returns (uint256 adminFee, uint256 payoffAmount) { // Calculate amounts to send to lender and admins uint256 interestDue = _loanTerms.maximumRepaymentAmount - _loanTerms.loanPrincipalAmount; adminFee = LoanComputations.getAdminFee( interestDue, uint256(_loanTerms.loanAdminFeeInBasisPoints) ); payoffAmount = _loanTerms.maximumRepaymentAmount - adminFee; } function _loanSanityChecksOffer(LoanStructures.Offer memory _offer) internal pure { require( _offer.maximumRepaymentAmount >= _offer.loanPrincipalAmount, "Negative interest rate loans are not allowed." ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "./ILoanCommon.sol"; import "./LoanStructures.sol"; import "./LoanComputations.sol"; import "./LoanAirdropHelper.sol"; import "../MainLoan.sol"; import "../../utils/NftAcceptor.sol"; import "../../utils/SignHelper.sol"; import "../../interfaces/IDispatcher.sol"; import "../../utils/KeysMapping.sol"; import "../../interfaces/ILoanManager.sol"; import "../../interfaces/INftWrapper.sol"; import "../../interfaces/IAllowedPartners.sol"; import "../../interfaces/IAllowedERC20s.sol"; import "../../interfaces/IAllowedNFTs.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; abstract contract LoanCommonEssential is ILoanCommon, IAllowedERC20s, MainLoan, NftAcceptor, LoanStructures { using SafeERC20 for IERC20; uint16 public constant HUNDRED_PERCENT = 10000; bytes32 public immutable override LOAN_COORDINATOR; uint256 public override maximumLoanDuration = 53 weeks; uint16 public override adminFeeInBasisPoints = 25; mapping(uint32 => LoanTerms) public override loanIdToLoan; mapping(uint32 => LoanExtras) public loanIdToLoanExtras; mapping(uint32 => bool) public override loanRepaidOrLiquidated; mapping(address => mapping(uint256 => uint256)) private _escrowTokens; mapping(address => mapping(uint256 => bool)) internal _nonceHasBeenUsedForUser; mapping(address => bool) private erc20Permits; IDispatcher public immutable hub; event AdminFeeUpdated(uint16 newAdminFee); event MaximumLoanDurationUpdated(uint256 newMaximumLoanDuration); event LoanStarted( uint32 indexed loanId, address indexed borrower, address indexed lender, LoanTerms loanTerms, LoanExtras loanExtras ); event LoanRepaid( uint32 indexed loanId, address indexed borrower, address indexed lender, uint256 loanPrincipalAmount, uint256 nftCollateralId, uint256 amountPaidToLender, uint256 adminFee, uint256 revenueShare, address revenueSharePartner, address nftCollateralContract, address loanERC20Denomination ); event LoanLiquidated( uint32 indexed loanId, address indexed borrower, address indexed lender, uint256 loanPrincipalAmount, uint256 nftCollateralId, uint256 loanMaturityDate, uint256 loanLiquidationDate, address nftCollateralContract ); event LoanRenegotiated( uint32 indexed loanId, address indexed borrower, address indexed lender, uint32 newLoanDuration, uint256 newMaximumRepaymentAmount, uint256 renegotiationFee, uint256 renegotiationAdminFee ); event ERC20Permit(address indexed erc20Contract, bool isPermitted); constructor( address _admin, address _dispatcher, bytes32 _loanCoordinatorKey, address[] memory _allowedERC20s ) MainLoan(_admin) { hub = IDispatcher(_dispatcher); LOAN_COORDINATOR = _loanCoordinatorKey; for (uint256 i = 0; i < _allowedERC20s.length; i++) { _setERC20Permit(_allowedERC20s[i], true); } } function updateMaximumLoanDuration(uint256 _newMaximumLoanDuration) external onlyOwner { require(_newMaximumLoanDuration <= uint256(type(uint32).max), "Loan duration overflow"); maximumLoanDuration = _newMaximumLoanDuration; emit MaximumLoanDurationUpdated(_newMaximumLoanDuration); } function updateAdminFee(uint16 _newAdminFeeInBasisPoints) external onlyOwner { require(_newAdminFeeInBasisPoints <= HUNDRED_PERCENT, "basis points > 10000"); adminFeeInBasisPoints = _newAdminFeeInBasisPoints; emit AdminFeeUpdated(_newAdminFeeInBasisPoints); } function pipeERC20Airdrop(address _tokenAddress, address _receiver) external onlyOwner { IERC20 tokenContract = IERC20(_tokenAddress); uint256 amount = tokenContract.balanceOf(address(this)); require(amount > 0, "no tokens owned"); tokenContract.safeTransfer(_receiver, amount); } function setERC20Permit(address _erc20, bool _permit) external onlyOwner { _setERC20Permit(_erc20, _permit); } function setERC20Permits(address[] memory _erc20s, bool[] memory _permits) external onlyOwner { require(_erc20s.length == _permits.length, "setERC20Permits function information arity mismatch"); for (uint256 i = 0; i < _erc20s.length; i++) { _setERC20Permit(_erc20s[i], _permits[i]); } } function pipeERC721Airdrop( address _tokenAddress, uint256 _tokenId, address _receiver ) external onlyOwner { IERC721 tokenContract = IERC721(_tokenAddress); require(_escrowTokens[_tokenAddress][_tokenId] == 0, "token is collateral"); require(tokenContract.ownerOf(_tokenId) == address(this), "nft not owned"); tokenContract.safeTransferFrom(address(this), _receiver, _tokenId); } function pipeERC1155Airdrop( address _tokenAddress, uint256 _tokenId, address _receiver ) external onlyOwner { IERC1155 tokenContract = IERC1155(_tokenAddress); uint256 amount = tokenContract.balanceOf(address(this), _tokenId); require(_escrowTokens[_tokenAddress][_tokenId] == 0, "token is collateral"); require(amount > 0, "no nfts owned"); tokenContract.safeTransferFrom(address(this), _receiver, _tokenId, amount, ""); } function mintObligationReceipt(uint32 _loanId) external nonReentrant { address borrower = loanIdToLoan[_loanId].borrower; require(msg.sender == borrower, "sender has to be borrower"); ILoanManager loanCoordinator = ILoanManager(hub.getContract(LOAN_COORDINATOR)); loanCoordinator.mintObligationReceipt(_loanId, borrower); delete loanIdToLoan[_loanId].borrower; } function renegotiateLoan( uint32 _loanId, uint32 _newLoanDuration, uint256 _newMaximumRepaymentAmount, uint256 _renegotiationFee, uint256 _lenderNonce, uint256 _expiry, bytes memory _lenderSignature ) external whenNotPaused nonReentrant { _renegotiateLoan( _loanId, _newLoanDuration, _newMaximumRepaymentAmount, _renegotiationFee, _lenderNonce, _expiry, _lenderSignature ); } function payBackLoan(uint32 _loanId) external nonReentrant { LoanComputations.validatePayback(_loanId, hub); ( address borrower, address lender, LoanTerms memory loan, ILoanManager loanCoordinator ) = _getLoanData(_loanId); _payBackLoan(_loanId, borrower, lender, loan); _resolveLoan(_loanId, borrower, loan, loanCoordinator); // Delete the loan from storage in order to achieve a substantial gas savings and to lessen the burden of // storage on Ethereum nodes, since we will never access this loan's details again, and the details are still // available through event data. delete loanIdToLoan[_loanId]; delete loanIdToLoanExtras[_loanId]; } function liquidateExpiredLoan(uint32 _loanId) external nonReentrant { LoanComputations.checkLoanIdValidity(_loanId, hub); // Sanity check that payBackLoan() and liquidateExpiredLoan() have never been called on this loanId. // Depending on how the rest of the code turns out, this check may be unnecessary. require(!loanRepaidOrLiquidated[_loanId], "Loan already repaid/liquidated"); ( address borrower, address lender, LoanTerms memory loan, ILoanManager loanCoordinator ) = _getLoanData(_loanId); // Ensure that the loan is indeed overdue, since we can only liquidate overdue loans. uint256 loanMaturityDate = uint256(loan.loanStartTime) + uint256(loan.loanDuration); require(block.timestamp > loanMaturityDate, "Loan is not overdue yet"); require(msg.sender == lender, "Only lender can liquidate"); _resolveLoan(_loanId, lender, loan, loanCoordinator); // Emit an event with all relevant details from this transaction. emit LoanLiquidated( _loanId, borrower, lender, loan.loanPrincipalAmount, loan.nftCollateralId, loanMaturityDate, block.timestamp, loan.nftCollateralContract ); // Delete the loan from storage in order to achieve a substantial gas savings and to lessen the burden of // storage on Ethereum nodes, since we will never access this loan's details again, and the details are still // available through event data. delete loanIdToLoan[_loanId]; delete loanIdToLoanExtras[_loanId]; } function pullAirdrop( uint32 _loanId, address _target, bytes calldata _data, address _nftAirdrop, uint256 _nftAirdropId, bool _is1155, uint256 _nftAirdropAmount ) external nonReentrant { LoanComputations.checkLoanIdValidity(_loanId, hub); require(!loanRepaidOrLiquidated[_loanId], "Loan already repaid/liquidated"); LoanTerms memory loan = loanIdToLoan[_loanId]; LoanAirdropHelper.pullAirdrop( _loanId, loan, _target, _data, _nftAirdrop, _nftAirdropId, _is1155, _nftAirdropAmount, hub ); } function wrapCollateral(uint32 _loanId) external nonReentrant { LoanComputations.checkLoanIdValidity(_loanId, hub); require(!loanRepaidOrLiquidated[_loanId], "Loan already repaid/liquidated"); LoanTerms storage loan = loanIdToLoan[_loanId]; _escrowTokens[loan.nftCollateralContract][loan.nftCollateralId] -= 1; (address instance, uint256 receiverId) = LoanAirdropHelper.wrapCollateral(_loanId, loan, hub); _escrowTokens[instance][receiverId] += 1; } function cancelNonceForUser(uint256 _nonce) external { require(!_nonceHasBeenUsedForUser[msg.sender][_nonce], "Invalid nonce"); _nonceHasBeenUsedForUser[msg.sender][_nonce] = true; } function computePayoffAmount(uint32 _loanId) external view virtual returns (uint256); function hasNonceBeenUsedForUser(address _user, uint256 _nonce) external view override returns (bool) { return _nonceHasBeenUsedForUser[_user][_nonce]; } function isERC20Permitted(address _erc20) public view override returns (bool) { return erc20Permits[_erc20]; } function _renegotiateLoan( uint32 _loanId, uint32 _newLoanDuration, uint256 _newMaximumRepaymentAmount, uint256 _renegotiationFee, uint256 _lenderNonce, uint256 _expiry, bytes memory _lenderSignature ) internal { LoanTerms storage loan = loanIdToLoan[_loanId]; (address borrower, address lender) = LoanComputations.validateRenegotiation( loan, _loanId, _newLoanDuration, _newMaximumRepaymentAmount, _lenderNonce, hub ); _nonceHasBeenUsedForUser[lender][_lenderNonce] = true; require( SignHelper.checkLenderRenegotiationSignatureValidity( _loanId, _newLoanDuration, _newMaximumRepaymentAmount, _renegotiationFee, Signature({signer: lender, nonce: _lenderNonce, expiry: _expiry, signature: _lenderSignature}) ), "Renegotiation signature is invalid" ); uint256 renegotiationAdminFee; if (_renegotiationFee > 0) { renegotiationAdminFee = LoanComputations.getAdminFee( _renegotiationFee, loan.loanAdminFeeInBasisPoints ); // Transfer principal-plus-interest-minus-fees from the caller (always has to be borrower) to lender IERC20(loan.loanERC20Denomination).safeTransferFrom( borrower, lender, _renegotiationFee - renegotiationAdminFee ); // Transfer fees from the caller (always has to be borrower) to admins IERC20(loan.loanERC20Denomination).safeTransferFrom(borrower, owner(), renegotiationAdminFee); } loan.loanDuration = _newLoanDuration; loan.maximumRepaymentAmount = _newMaximumRepaymentAmount; emit LoanRenegotiated( _loanId, borrower, lender, _newLoanDuration, _newMaximumRepaymentAmount, _renegotiationFee, renegotiationAdminFee ); } function _createLoan( bytes32 _loanType, LoanTerms memory _loanTerms, LoanExtras memory _loanExtras, address _borrower, address _lender, address _referrer ) internal returns (uint32) { // Transfer collateral from borrower to this contract to be held until // loan completion. _transferNFT(_loanTerms, _borrower, address(this)); return _createLoanNoNftTransfer(_loanType, _loanTerms, _loanExtras, _borrower, _lender, _referrer); } function _createLoanNoNftTransfer( bytes32 _loanType, LoanTerms memory _loanTerms, LoanExtras memory _loanExtras, address _borrower, address _lender, address _referrer ) internal returns (uint32 loanId) { _escrowTokens[_loanTerms.nftCollateralContract][_loanTerms.nftCollateralId] += 1; uint256 referralfee = LoanComputations.getReferralFee( _loanTerms.loanPrincipalAmount, _loanExtras.referralFeeInBasisPoints, _referrer ); uint256 principalAmount = _loanTerms.loanPrincipalAmount - referralfee; if (referralfee > 0) { // Transfer the referral fee from lender to referrer. IERC20(_loanTerms.loanERC20Denomination).safeTransferFrom(_lender, _referrer, referralfee); } // Transfer principal from lender to borrower. IERC20(_loanTerms.loanERC20Denomination).safeTransferFrom(_lender, _borrower, principalAmount); // Issue an ERC721 promissory note to the lender that gives them the // right to either the principal-plus-interest or the collateral, // and an obligation note to the borrower that gives them the // right to pay back the loan and get the collateral back. ILoanManager loanCoordinator = ILoanManager(hub.getContract(LOAN_COORDINATOR)); loanId = loanCoordinator.registerLoan(_lender, _loanType); // Add the loan to storage before moving collateral/principal to follow // the Checks-Effects-Interactions pattern. loanIdToLoan[loanId] = _loanTerms; loanIdToLoanExtras[loanId] = _loanExtras; return loanId; } function _transferNFT( LoanTerms memory _loanTerms, address _sender, address _recipient ) internal { Address.functionDelegateCall( _loanTerms.nftCollateralWrapper, abi.encodeWithSelector( INftWrapper(_loanTerms.nftCollateralWrapper).transferNFT.selector, _sender, _recipient, _loanTerms.nftCollateralContract, _loanTerms.nftCollateralId ), "NFT not successfully transferred" ); } function _payBackLoan( uint32 _loanId, address _borrower, address _lender, LoanTerms memory _loan ) internal { // Fetch loan details from storage, but store them in memory for the sake of saving gas. LoanExtras memory loanExtras = loanIdToLoanExtras[_loanId]; (uint256 adminFee, uint256 payoffAmount) = _payoffAndFee(_loan); // Transfer principal-plus-interest-minus-fees from the caller to lender IERC20(_loan.loanERC20Denomination).safeTransferFrom(msg.sender, _lender, payoffAmount); uint256 revenueShare = LoanComputations.getRevenueShare( adminFee, loanExtras.revenueShareInBasisPoints ); // AllowedPartners contract doesn't allow to set a revenueShareInBasisPoints for address zero so revenuShare // > 0 implies that revenueSharePartner ~= address(0), BUT revenueShare can be zero for a partener when the // adminFee is low if (revenueShare > 0 && loanExtras.revenueSharePartner != address(0)) { adminFee -= revenueShare; // Transfer revenue share from the caller to permitted partner IERC20(_loan.loanERC20Denomination).safeTransferFrom( msg.sender, loanExtras.revenueSharePartner, revenueShare ); } // Transfer fees from the caller to admins IERC20(_loan.loanERC20Denomination).safeTransferFrom(msg.sender, owner(), adminFee); // Emit an event with all relevant details from this transaction. emit LoanRepaid( _loanId, _borrower, _lender, _loan.loanPrincipalAmount, _loan.nftCollateralId, payoffAmount, adminFee, revenueShare, loanExtras.revenueSharePartner, // this could be a non address zero even if revenueShare is 0 _loan.nftCollateralContract, _loan.loanERC20Denomination ); } function _resolveLoan( uint32 _loanId, address _nftAcceptor, LoanTerms memory _loanTerms, ILoanManager _loanCoordinator ) internal { _resolveLoanNoNftTransfer(_loanId, _loanTerms, _loanCoordinator); // Transfer collateral from this contract to the lender, since the lender is seizing collateral for an overdue // loan _transferNFT(_loanTerms, address(this), _nftAcceptor); } function _resolveLoanNoNftTransfer( uint32 _loanId, LoanTerms memory _loanTerms, ILoanManager _loanCoordinator ) internal { // Mark loan as liquidated before doing any external transfers to follow the Checks-Effects-Interactions design // pattern loanRepaidOrLiquidated[_loanId] = true; _escrowTokens[_loanTerms.nftCollateralContract][_loanTerms.nftCollateralId] -= 1; // Destroy the lender's promissory note for this loan and borrower obligation receipt _loanCoordinator.resolveLoan(_loanId); } function _setERC20Permit(address _erc20, bool _permit) internal { require(_erc20 != address(0), "erc20 is zero address"); erc20Permits[_erc20] = _permit; emit ERC20Permit(_erc20, _permit); } function _loanSanityChecks(LoanStructures.Offer memory _offer, address _nftWrapper) internal view { require(isERC20Permitted(_offer.loanERC20Denomination), "Currency denomination is not permitted"); require(_nftWrapper != address(0), "NFT collateral contract is not permitted"); require(uint256(_offer.loanDuration) <= maximumLoanDuration, "Loan duration exceeds maximum loan duration"); require(uint256(_offer.loanDuration) != 0, "Loan duration cannot be zero"); require( _offer.loanAdminFeeInBasisPoints == adminFeeInBasisPoints, "The admin fee has changed since this order was signed." ); } function _getLoanData(uint32 _loanId) internal view returns ( address borrower, address lender, LoanTerms memory loan, ILoanManager loanCoordinator ) { loanCoordinator = ILoanManager(hub.getContract(LOAN_COORDINATOR)); ILoanManager.Loan memory loanCoordinatorData = loanCoordinator.getLoanData(_loanId); uint256 notesNftId = loanCoordinatorData.notesNftId; // Fetch loan details from storage, but store them in memory for the sake of saving gas. loan = loanIdToLoan[_loanId]; if (loan.borrower != address(0)) { borrower = loan.borrower; } else { // Fetch current owner of loan obligation note. borrower = IERC721(loanCoordinator.obligationReceiptToken()).ownerOf(notesNftId); } lender = IERC721(loanCoordinator.promissoryNoteToken()).ownerOf(notesNftId); } function _setupLoanExtras(address _revenueSharePartner, uint16 _referralFeeInBasisPoints) internal view returns (LoanExtras memory) { // Save loan details to a struct in memory first, to save on gas if any // of the below checks fail, and to avoid the "Stack Too Deep" error by // clumping the parameters together into one struct held in memory. return LoanExtras({ revenueSharePartner: _revenueSharePartner, revenueShareInBasisPoints: LoanComputations.getRevenueSharePercent(_revenueSharePartner, hub), referralFeeInBasisPoints: _referralFeeInBasisPoints }); } function _payoffAndFee(LoanTerms memory _loanTerms) internal view virtual returns (uint256, uint256); function _getWrapper(address _nftCollateralContract) internal view returns (address) { return IAllowedNFTs(hub.getContract(KeysMapping.PERMITTED_NFTS)).getNFTWrapper(_nftCollateralContract); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; library KeysMapping { bytes32 public constant PERMITTED_ERC20S = bytes32("PERMITTED_ERC20S"); bytes32 public constant PERMITTED_NFTS = bytes32("PERMITTED_NFTS"); bytes32 public constant PERMITTED_PARTNERS = bytes32("PERMITTED_PARTNERS"); bytes32 public constant NFT_TYPE_REGISTRY = bytes32("NFT_TYPE_REGISTRY"); bytes32 public constant LOAN_REGISTRY = bytes32("LOAN_REGISTRY"); bytes32 public constant PERMITTED_SNFT_RECEIVER = bytes32("PERMITTED_SNFT_RECEIVER"); bytes32 public constant PERMITTED_BUNDLE_ERC20S = bytes32("PERMITTED_BUNDLE_ERC20S"); bytes32 public constant PERMITTED_AIRDROPS = bytes32("PERMITTED_AIRDROPS"); bytes32 public constant AIRDROP_RECEIVER = bytes32("AIRDROP_RECEIVER"); bytes32 public constant AIRDROP_FACTORY = bytes32("AIRDROP_FACTORY"); bytes32 public constant AIRDROP_FLASH_LOAN = bytes32("AIRDROP_FLASH_LOAN"); bytes32 public constant LIQUIDOTS_BUNDLER = bytes32("LIQUIDOTS_BUNDLER"); string public constant AIRDROP_WRAPPER_STRING = "AirdropWrapper"; function keyToId(string memory _key) external pure returns (bytes32 id) { require(bytes(_key).length <= 32, "invalid key"); // solhint-disable-next-line no-inline-assembly assembly { id := mload(add(_key, 32)) } } }
// SPDX-License-Identifier: MIT import "./LoanStructures.sol"; pragma solidity 0.8.4; interface ILoanCommon { function maximumLoanDuration() external view returns (uint256); function adminFeeInBasisPoints() external view returns (uint16); // solhint-disable-next-line func-name-mixedcase function LOAN_COORDINATOR() external view returns (bytes32); function loanIdToLoan(uint32) external view returns ( uint256, uint256, uint256, address, uint32, uint16, uint16, address, uint64, address, address ); function loanRepaidOrLiquidated(uint32) external view returns (bool); function hasNonceBeenUsedForUser(address _user, uint256 _nonce) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; interface LoanStructures { struct LoanTerms { uint256 loanPrincipalAmount; uint256 maximumRepaymentAmount; uint256 nftCollateralId; address loanERC20Denomination; uint32 loanDuration; uint16 loanInterestRateForDurationInBasisPoints; uint16 loanAdminFeeInBasisPoints; address nftCollateralWrapper; uint64 loanStartTime; address nftCollateralContract; address borrower; } struct LoanExtras { address revenueSharePartner; uint16 revenueShareInBasisPoints; uint16 referralFeeInBasisPoints; } struct Offer { uint256 loanPrincipalAmount; uint256 maximumRepaymentAmount; uint256 nftCollateralId; address nftCollateralContract; uint32 loanDuration; uint16 loanAdminFeeInBasisPoints; address loanERC20Denomination; address referrer; } struct Signature { uint256 nonce; uint256 expiry; address signer; bytes signature; } struct BorrowerSettings { address revenueSharePartner; uint16 referralFeeInBasisPoints; } struct ListingTerms { uint256 minLoanPrincipalAmount; uint256 maxLoanPrincipalAmount; uint256 nftCollateralId; address nftCollateralContract; uint32 minLoanDuration; uint32 maxLoanDuration; uint16 maxInterestRateForDurationInBasisPoints; uint16 referralFeeInBasisPoints; address revenueSharePartner; address loanERC20Denomination; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "./ILoanCommon.sol"; import "./LoanStructures.sol"; import "../../interfaces/ILoanManager.sol"; import "../../utils/KeysMapping.sol"; import "../../interfaces/IDispatcher.sol"; import "../../interfaces/IAllowedPartners.sol"; import "../../interfaces/IAllowedERC20s.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; library LoanComputations { uint16 private constant HUNDRED_PERCENT = 10000; function validatePayback(uint32 _loanId, IDispatcher _hub) external view { checkLoanIdValidity(_loanId, _hub); // Sanity check that payBackLoan() and liquidateExpiredLoan() have never been called on this loanId. // Depending on how the rest of the code turns out, this check may be unnecessary. require(!ILoanCommon(address(this)).loanRepaidOrLiquidated(_loanId), "Loan already repaid/liquidated"); // Fetch loan details from storage, but store them in memory for the sake of saving gas. (, , , , uint32 loanDuration, , , , uint64 loanStartTime, , ) = ILoanCommon(address(this)).loanIdToLoan( _loanId ); // When a loan exceeds the loan term, it is expired. At this stage the Lender can call Liquidate Loan to resolve // the loan. require(block.timestamp <= (uint256(loanStartTime) + uint256(loanDuration)), "Loan is expired"); } function checkLoanIdValidity(uint32 _loanId, IDispatcher _hub) public view { require( ILoanManager(_hub.getContract(ILoanCommon(address(this)).LOAN_COORDINATOR())).isValidLoanId( _loanId, address(this) ), "invalid loanId" ); } function getRevenueSharePercent(address _revenueSharePartner, IDispatcher _hub) external view returns (uint16) { // return soon if no partner is set to avoid a public call if (_revenueSharePartner == address(0)) { return 0; } uint16 revenueSharePercent = IAllowedPartners(_hub.getContract(KeysMapping.PERMITTED_PARTNERS)) .getPartnerPermit(_revenueSharePartner); return revenueSharePercent; } function validateRenegotiation( LoanStructures.LoanTerms memory _loan, uint32 _loanId, uint32 _newLoanDuration, uint256 _newMaximumRepaymentAmount, uint256 _lenderNonce, IDispatcher _hub ) external view returns (address, address) { checkLoanIdValidity(_loanId, _hub); ILoanManager loanCoordinator = ILoanManager( _hub.getContract(ILoanCommon(address(this)).LOAN_COORDINATOR()) ); uint256 notesNftId = loanCoordinator.getLoanData(_loanId).notesNftId; address borrower; if (_loan.borrower != address(0)) { borrower = _loan.borrower; } else { borrower = IERC721(loanCoordinator.obligationReceiptToken()).ownerOf(notesNftId); } require(msg.sender == borrower, "Only borrower can initiate"); require(block.timestamp <= (uint256(_loan.loanStartTime) + _newLoanDuration), "New duration already expired"); require( uint256(_newLoanDuration) <= ILoanCommon(address(this)).maximumLoanDuration(), "New duration exceeds maximum loan duration" ); require(!ILoanCommon(address(this)).loanRepaidOrLiquidated(_loanId), "Loan already repaid/liquidated"); require( _newMaximumRepaymentAmount >= _loan.loanPrincipalAmount, "Negative interest rate loans are not allowed." ); // Fetch current owner of loan promissory note. address lender = IERC721(loanCoordinator.promissoryNoteToken()).ownerOf(notesNftId); require( !ILoanCommon(address(this)).hasNonceBeenUsedForUser(lender, _lenderNonce), "Lender nonce invalid" ); return (borrower, lender); } function bindingTermsSanityChecks(LoanStructures.ListingTerms memory _listingTerms, LoanStructures.Offer memory _offer) external pure { // offer vs listing validations require(_offer.loanERC20Denomination == _listingTerms.loanERC20Denomination, "Invalid loanERC20Denomination"); require( _offer.loanPrincipalAmount >= _listingTerms.minLoanPrincipalAmount && _offer.loanPrincipalAmount <= _listingTerms.maxLoanPrincipalAmount, "Invalid loanPrincipalAmount" ); uint256 maxRepaymentLimit = _offer.loanPrincipalAmount + (_offer.loanPrincipalAmount * _listingTerms.maxInterestRateForDurationInBasisPoints) / HUNDRED_PERCENT; require(_offer.maximumRepaymentAmount <= maxRepaymentLimit, "maxInterestRateForDurationInBasisPoints violated"); require( _offer.loanDuration >= _listingTerms.minLoanDuration && _offer.loanDuration <= _listingTerms.maxLoanDuration, "Invalid loanDuration" ); } function getRevenueShare(uint256 _adminFee, uint256 _revenueShareInBasisPoints) external pure returns (uint256) { return (_adminFee * _revenueShareInBasisPoints) / HUNDRED_PERCENT; } function getAdminFee(uint256 _interestDue, uint256 _adminFeeInBasisPoints) external pure returns (uint256) { return (_interestDue * _adminFeeInBasisPoints) / HUNDRED_PERCENT; } function getReferralFee( uint256 _loanPrincipalAmount, uint256 _referralFeeInBasisPoints, address _referrer ) external pure returns (uint256) { if (_referralFeeInBasisPoints == 0 || _referrer == address(0)) { return 0; } return (_loanPrincipalAmount * _referralFeeInBasisPoints) / HUNDRED_PERCENT; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "./ILoanCommon.sol"; import "./LoanStructures.sol"; import "../../interfaces/ILoanManager.sol"; import "../../utils/KeysMapping.sol"; import "../../interfaces/IDispatcher.sol"; import "../../interfaces/IAllowedPartners.sol"; import "../../interfaces/IAllowedERC20s.sol"; import "../../interfaces/IAirdropBurstLoan.sol"; import "../../interfaces/INftWrapper.sol"; import "../../airdrop/IAirdropAcceptorFactory.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/utils/Address.sol"; library LoanAirdropHelper { event AirdropPulledBurstloan( uint256 indexed loanId, address indexed borrower, uint256 nftCollateralId, address nftCollateralContract, address target, bytes data ); event CollateralWrapped( uint256 indexed loanId, address indexed borrower, uint256 nftCollateralId, address nftCollateralContract, uint256 receiverId, address receiverInstance ); function pullAirdrop( uint32 _loanId, LoanStructures.LoanTerms memory _loan, address _target, bytes calldata _data, address _nftAirdrop, uint256 _nftAirdropId, bool _is1155, uint256 _nftAirdropAmount, IDispatcher _hub ) external { ILoanManager loanCoordinator = ILoanManager( _hub.getContract(ILoanCommon(address(this)).LOAN_COORDINATOR()) ); address borrower; // scoped to aviod stack too deep { ILoanManager.Loan memory loanCoordinatorData = loanCoordinator.getLoanData(_loanId); uint256 notesNftId = loanCoordinatorData.notesNftId; if (_loan.borrower != address(0)) { borrower = _loan.borrower; } else { borrower = IERC721(loanCoordinator.obligationReceiptToken()).ownerOf(notesNftId); } } require(msg.sender == borrower, "Only borrower can airdrop"); { IAirdropBurstLoan airdropBurstLoan = IAirdropBurstLoan(_hub.getContract(KeysMapping.AIRDROP_FLASH_LOAN)); _transferNFT(_loan, address(this), address(airdropBurstLoan)); airdropBurstLoan.pullAirdrop( _loan.nftCollateralContract, _loan.nftCollateralId, _loan.nftCollateralWrapper, _target, _data, _nftAirdrop, _nftAirdropId, _is1155, _nftAirdropAmount, borrower ); } // revert if the collateral hasn't been transferred back before it ends require( INftWrapper(_loan.nftCollateralWrapper).isOwner( address(this), _loan.nftCollateralContract, _loan.nftCollateralId ), "Collateral should be returned" ); emit AirdropPulledBurstloan( _loanId, borrower, _loan.nftCollateralId, _loan.nftCollateralContract, _target, _data ); } function wrapCollateral( uint32 _loanId, LoanStructures.LoanTerms storage _loan, IDispatcher _hub ) external returns (address instance, uint256 receiverId) { ILoanManager loanCoordinator = ILoanManager( _hub.getContract(ILoanCommon(address(this)).LOAN_COORDINATOR()) ); // Fetch the current lender of the promissory note corresponding to this overdue loan. ILoanManager.Loan memory loanCoordinatorData = loanCoordinator.getLoanData(_loanId); uint256 notesNftId = loanCoordinatorData.notesNftId; address borrower; if (_loan.borrower != address(0)) { borrower = _loan.borrower; } else { borrower = IERC721(loanCoordinator.obligationReceiptToken()).ownerOf(notesNftId); } require(msg.sender == borrower, "Only borrower can wrapp"); IAirdropAcceptorFactory factory = IAirdropAcceptorFactory(_hub.getContract(KeysMapping.AIRDROP_FACTORY)); (instance, receiverId) = factory.createAirdropAcceptor(address(this)); // transfer collateral to airdrop receiver wrapper _transferNFTtoAirdropAcceptor(_loan, instance, borrower); emit CollateralWrapped( _loanId, borrower, _loan.nftCollateralId, _loan.nftCollateralContract, receiverId, instance ); // set the receiver as the new collateral _loan.nftCollateralContract = instance; _loan.nftCollateralId = receiverId; } function _transferNFT( LoanStructures.LoanTerms memory _loan, address _sender, address _recipient ) internal { Address.functionDelegateCall( _loan.nftCollateralWrapper, abi.encodeWithSelector( INftWrapper(_loan.nftCollateralWrapper).transferNFT.selector, _sender, _recipient, _loan.nftCollateralContract, _loan.nftCollateralId ), "NFT not successfully transferred" ); } function _transferNFTtoAirdropAcceptor( LoanStructures.LoanTerms memory _loan, address _airdropAcceptorInstance, address _airdropBeneficiary ) internal { Address.functionDelegateCall( _loan.nftCollateralWrapper, abi.encodeWithSelector( INftWrapper(_loan.nftCollateralWrapper).wrapAirdropAcceptor.selector, _airdropAcceptorInstance, _loan.nftCollateralContract, _loan.nftCollateralId, _airdropBeneficiary ), "NFT was not successfully migrated" ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "../utils/Ownable.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; abstract contract MainLoan is Ownable, Pausable, ReentrancyGuard { constructor(address _admin) Ownable(_admin) { // solhint-disable-previous-line no-empty-blocks } function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _unpause(); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; abstract contract NftAcceptor is IERC1155Receiver, ERC721Holder { function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external virtual override returns (bytes4) { revert("ERC1155 batch not supported"); } function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) { return _interfaceId == type(IERC1155Receiver).interfaceId || _interfaceId == type(IERC721Receiver).interfaceId || _interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "../interfaces/IPackBuilder.sol"; import "../loans/types/LoanStructures.sol"; import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; library SignHelper { function getChainID() public view returns (uint256) { uint256 id; // solhint-disable-next-line no-inline-assembly assembly { id := chainid() } return id; } function checkBorrowerSignatureValidity(LoanStructures.ListingTerms memory _listingTerms, LoanStructures.Signature memory _signature) external view returns (bool) { return checkBorrowerSignatureValidity(_listingTerms, _signature, address(this)); } function checkBorrowerSignatureValidity( LoanStructures.ListingTerms memory _listingTerms, LoanStructures.Signature memory _signature, address _loanContract ) public view returns (bool) { require(block.timestamp <= _signature.expiry, "Borrower Signature has expired"); require(_loanContract != address(0), "Loan is zero address"); if (_signature.signer == address(0)) { return false; } else { bytes32 message = keccak256( abi.encodePacked( getPackedListing(_listingTerms), getPackedSignature(_signature), _loanContract, getChainID() ) ); return SignatureChecker.isValidSignatureNow( _signature.signer, ECDSA.toEthSignedMessageHash(message), _signature.signature ); } } function checkBorrowerSignatureValidityBundle( LoanStructures.ListingTerms memory _listingTerms, IPackBuilder.BundleElements memory _bundleElements, LoanStructures.Signature memory _signature ) external view returns (bool) { return checkBorrowerSignatureValidityBundle(_listingTerms, _bundleElements, _signature, address(this)); } function checkBorrowerSignatureValidityBundle( LoanStructures.ListingTerms memory _listingTerms, IPackBuilder.BundleElements memory _bundleElements, LoanStructures.Signature memory _signature, address _loanContract ) public view returns (bool) { require(block.timestamp <= _signature.expiry, "Borrower Signature has expired"); require(_loanContract != address(0), "Loan is zero address"); if (_signature.signer == address(0)) { return false; } else { bytes32 message = keccak256( abi.encodePacked( getPackedListing(_listingTerms), abi.encode(_bundleElements), getPackedSignature(_signature), _loanContract, getChainID() ) ); return SignatureChecker.isValidSignatureNow( _signature.signer, ECDSA.toEthSignedMessageHash(message), _signature.signature ); } } function checkLenderSignatureValidity(LoanStructures.Offer memory _offer, LoanStructures.Signature memory _signature) external view returns (bool) { return checkLenderSignatureValidity(_offer, _signature, address(this)); } function checkLenderSignatureValidity( LoanStructures.Offer memory _offer, LoanStructures.Signature memory _signature, address _loanContract ) public view returns (bool) { require(block.timestamp <= _signature.expiry, "Lender Signature has expired"); require(_loanContract != address(0), "Loan is zero address"); if (_signature.signer == address(0)) { return false; } else { bytes32 message = keccak256( abi.encodePacked(getPackedOffer(_offer), getPackedSignature(_signature), _loanContract, getChainID()) ); return SignatureChecker.isValidSignatureNow( _signature.signer, ECDSA.toEthSignedMessageHash(message), _signature.signature ); } } function checkLenderSignatureValidityBundle( LoanStructures.Offer memory _offer, IPackBuilder.BundleElements memory _bundleElements, LoanStructures.Signature memory _signature ) external view returns (bool) { return checkLenderSignatureValidityBundle(_offer, _bundleElements, _signature, address(this)); } function checkLenderSignatureValidityBundle( LoanStructures.Offer memory _offer, IPackBuilder.BundleElements memory _bundleElements, LoanStructures.Signature memory _signature, address _loanContract ) public view returns (bool) { require(block.timestamp <= _signature.expiry, "Lender Signature has expired"); require(_loanContract != address(0), "Loan is zero address"); if (_signature.signer == address(0)) { return false; } else { bytes32 message = keccak256( abi.encodePacked( getPackedOffer(_offer), abi.encode(_bundleElements), getPackedSignature(_signature), _loanContract, getChainID() ) ); return SignatureChecker.isValidSignatureNow( _signature.signer, ECDSA.toEthSignedMessageHash(message), _signature.signature ); } } function checkLenderRenegotiationSignatureValidity( uint256 _loanId, uint32 _newLoanDuration, uint256 _newMaximumRepaymentAmount, uint256 _renegotiationFee, LoanStructures.Signature memory _signature ) external view returns (bool) { return checkLenderRenegotiationSignatureValidity( _loanId, _newLoanDuration, _newMaximumRepaymentAmount, _renegotiationFee, _signature, address(this) ); } function checkLenderRenegotiationSignatureValidity( uint256 _loanId, uint32 _newLoanDuration, uint256 _newMaximumRepaymentAmount, uint256 _renegotiationFee, LoanStructures.Signature memory _signature, address _loanContract ) public view returns (bool) { require(block.timestamp <= _signature.expiry, "Renegotiation Signature has expired"); require(_loanContract != address(0), "Loan is zero address"); if (_signature.signer == address(0)) { return false; } else { bytes32 message = keccak256( abi.encodePacked( _loanId, _newLoanDuration, _newMaximumRepaymentAmount, _renegotiationFee, getPackedSignature(_signature), _loanContract, getChainID() ) ); return SignatureChecker.isValidSignatureNow( _signature.signer, ECDSA.toEthSignedMessageHash(message), _signature.signature ); } } function getPackedListing(LoanStructures.ListingTerms memory _listingTerms) internal pure returns (bytes memory) { return abi.encodePacked( _listingTerms.loanERC20Denomination, _listingTerms.minLoanPrincipalAmount, _listingTerms.maxLoanPrincipalAmount, _listingTerms.nftCollateralContract, _listingTerms.nftCollateralId, _listingTerms.revenueSharePartner, _listingTerms.minLoanDuration, _listingTerms.maxLoanDuration, _listingTerms.maxInterestRateForDurationInBasisPoints, _listingTerms.referralFeeInBasisPoints ); } function getPackedOffer(LoanStructures.Offer memory _offer) internal pure returns (bytes memory) { return abi.encodePacked( _offer.loanERC20Denomination, _offer.loanPrincipalAmount, _offer.maximumRepaymentAmount, _offer.nftCollateralContract, _offer.nftCollateralId, _offer.referrer, _offer.loanDuration, _offer.loanAdminFeeInBasisPoints ); } function getPackedSignature(LoanStructures.Signature memory _signature) internal pure returns (bytes memory) { return abi.encodePacked(_signature.signer, _signature.nonce, _signature.expiry); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; interface IDispatcher { function setContract(string calldata _contractKey, address _contractAddress) external; function getContract(bytes32 _contractKey) external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; interface ILoanManager { enum StatusType { NOT_EXISTS, NEW, RESOLVED } struct Loan { address loanContract; uint64 notesNftId; StatusType status; } function registerLoan(address _lender, bytes32 _loanType) external returns (uint32); function mintObligationReceipt(uint32 _loanId, address _borrower) external; function resolveLoan(uint32 _loanId) external; function promissoryNoteToken() external view returns (address); function obligationReceiptToken() external view returns (address); function getLoanData(uint32 _loanId) external view returns (Loan memory); function isValidLoanId(uint32 _loanId, address _loanContract) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; interface INftWrapper { function transferNFT( address from, address to, address nftContract, uint256 tokenId ) external returns (bool); function isOwner( address owner, address nftContract, uint256 tokenId ) external view returns (bool); function wrapAirdropAcceptor( address _recipient, address _nftContract, uint256 _nftId, address _beneficiary ) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; interface IAllowedPartners { function getPartnerPermit(address _partner) external view returns (uint16); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; interface IAllowedERC20s { function isERC20Permitted(address _erc20) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; interface IAllowedNFTs { function setNFTPermit(address _nftContract, string memory _nftType) external; function getNFTPermit(address _nftContract) external view returns (bytes32); function getNFTWrapper(address _nftContract) external view returns (address); }
// 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/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/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.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 (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 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 pragma solidity 0.8.4; interface IAirdropBurstLoan { function pullAirdrop( address _nftCollateralContract, uint256 _nftCollateralId, address _nftWrapper, address _target, bytes calldata _data, address _nftAirdrop, uint256 _nftAirdropId, bool _is1155, uint256 _nftAirdropAmount, address _beneficiary ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; interface IAirdropAcceptorFactory { function createAirdropAcceptor(address _to) external returns (address, uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.4; import "@openzeppelin/contracts/utils/Context.sol"; abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } constructor(address _initialOwner) { _setOwner(_initialOwner); } function transferOwnership(address _newOwner) public virtual onlyOwner { require(_newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(_newOwner); } function owner() public view virtual returns (address) { return _owner; } function _setOwner(address _newOwner) private { address oldOwner = _owner; _owner = _newOwner; emit OwnershipTransferred(oldOwner, _newOwner); } }
// 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 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.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 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.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 pragma solidity 0.8.4; interface IPackBuilder { struct BundleElementERC721 { address tokenContract; uint256 id; bool safeTransferable; } struct BundleElementERC20 { address tokenContract; uint256 amount; } struct BundleElementERC1155 { address tokenContract; uint256[] ids; uint256[] amounts; } struct BundleElements { BundleElementERC721[] erc721s; BundleElementERC20[] erc20s; BundleElementERC1155[] erc1155s; } function createBundle( BundleElements memory _bundleElements, address _sender, address _receiver ) external returns (uint256); function unpackBundle(uint256 _tokenId, address _receiver) external; }
// 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 (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 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) (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: 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); }
{ "optimizer": { "enabled": true, "runs": 100 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/utils/KeysMapping.sol": { "KeysMapping": "0x4ddc8349CcCa17f55cDeD3E81cec21dFEEB366f9" }, "contracts/loans/types/LoanAirdropHelper.sol": { "LoanAirdropHelper": "0x68fa3ed5f5642b7d6560de759bca7451dd5c7843" }, "contracts/loans/types/LoanComputations.sol": { "LoanComputations": "0x4d9ad703d5f62ad82c34311ac4f7dd08fb087c68" }, "contracts/utils/SignHelper.sol": { "SignHelper": "0xd8286584cb2cb4bbd600149b9e5c8a5e3b691464" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_dispatcher","type":"address"},{"internalType":"address[]","name":"_allowedERC20s","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"newAdminFee","type":"uint16"}],"name":"AdminFeeUpdated","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":"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":"loanPrincipalAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loanMaturityDate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loanLiquidationDate","type":"uint256"},{"indexed":false,"internalType":"address","name":"nftCollateralContract","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":"uint32","name":"newLoanDuration","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"newMaximumRepaymentAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"renegotiationFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"renegotiationAdminFee","type":"uint256"}],"name":"LoanRenegotiated","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":"loanPrincipalAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountPaidToLender","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"adminFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"revenueShare","type":"uint256"},{"indexed":false,"internalType":"address","name":"revenueSharePartner","type":"address"},{"indexed":false,"internalType":"address","name":"nftCollateralContract","type":"address"},{"indexed":false,"internalType":"address","name":"loanERC20Denomination","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"},{"components":[{"internalType":"uint256","name":"loanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maximumRepaymentAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"loanERC20Denomination","type":"address"},{"internalType":"uint32","name":"loanDuration","type":"uint32"},{"internalType":"uint16","name":"loanInterestRateForDurationInBasisPoints","type":"uint16"},{"internalType":"uint16","name":"loanAdminFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"nftCollateralWrapper","type":"address"},{"internalType":"uint64","name":"loanStartTime","type":"uint64"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"indexed":false,"internalType":"struct LoanStructures.LoanTerms","name":"loanTerms","type":"tuple"},{"components":[{"internalType":"address","name":"revenueSharePartner","type":"address"},{"internalType":"uint16","name":"revenueShareInBasisPoints","type":"uint16"},{"internalType":"uint16","name":"referralFeeInBasisPoints","type":"uint16"}],"indexed":false,"internalType":"struct LoanStructures.LoanExtras","name":"loanExtras","type":"tuple"}],"name":"LoanStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaximumLoanDuration","type":"uint256"}],"name":"MaximumLoanDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"HUNDRED_PERCENT","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOAN_COORDINATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOAN_TYPE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"loanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maximumRepaymentAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"uint32","name":"loanDuration","type":"uint32"},{"internalType":"uint16","name":"loanAdminFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"loanERC20Denomination","type":"address"},{"internalType":"address","name":"referrer","type":"address"}],"internalType":"struct LoanStructures.Offer","name":"_offer","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 LoanStructures.Signature","name":"_signature","type":"tuple"},{"components":[{"internalType":"address","name":"revenueSharePartner","type":"address"},{"internalType":"uint16","name":"referralFeeInBasisPoints","type":"uint16"}],"internalType":"struct LoanStructures.BorrowerSettings","name":"_borrowerSettings","type":"tuple"}],"name":"acceptOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"adminFeeInBasisPoints","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"cancelNonceForUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"}],"name":"computePayoffAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"hasNonceBeenUsedForUser","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hub","outputs":[{"internalType":"contract IDispatcher","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_erc20","type":"address"}],"name":"isERC20Permitted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"}],"name":"liquidateExpiredLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"loanIdToLoan","outputs":[{"internalType":"uint256","name":"loanPrincipalAmount","type":"uint256"},{"internalType":"uint256","name":"maximumRepaymentAmount","type":"uint256"},{"internalType":"uint256","name":"nftCollateralId","type":"uint256"},{"internalType":"address","name":"loanERC20Denomination","type":"address"},{"internalType":"uint32","name":"loanDuration","type":"uint32"},{"internalType":"uint16","name":"loanInterestRateForDurationInBasisPoints","type":"uint16"},{"internalType":"uint16","name":"loanAdminFeeInBasisPoints","type":"uint16"},{"internalType":"address","name":"nftCollateralWrapper","type":"address"},{"internalType":"uint64","name":"loanStartTime","type":"uint64"},{"internalType":"address","name":"nftCollateralContract","type":"address"},{"internalType":"address","name":"borrower","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"loanIdToLoanExtras","outputs":[{"internalType":"address","name":"revenueSharePartner","type":"address"},{"internalType":"uint16","name":"revenueShareInBasisPoints","type":"uint16"},{"internalType":"uint16","name":"referralFeeInBasisPoints","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"loanRepaidOrLiquidated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumLoanDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"}],"name":"mintObligationReceipt","outputs":[],"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":"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":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"uint32","name":"_loanId","type":"uint32"}],"name":"payBackLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"pipeERC1155Airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"pipeERC20Airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"pipeERC721Airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"},{"internalType":"address","name":"_target","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_nftAirdrop","type":"address"},{"internalType":"uint256","name":"_nftAirdropId","type":"uint256"},{"internalType":"bool","name":"_is1155","type":"bool"},{"internalType":"uint256","name":"_nftAirdropAmount","type":"uint256"}],"name":"pullAirdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"},{"internalType":"uint32","name":"_newLoanDuration","type":"uint32"},{"internalType":"uint256","name":"_newMaximumRepaymentAmount","type":"uint256"},{"internalType":"uint256","name":"_renegotiationFee","type":"uint256"},{"internalType":"uint256","name":"_lenderNonce","type":"uint256"},{"internalType":"uint256","name":"_expiry","type":"uint256"},{"internalType":"bytes","name":"_lenderSignature","type":"bytes"}],"name":"renegotiateLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_erc20","type":"address"},{"internalType":"bool","name":"_permit","type":"bool"}],"name":"setERC20Permit","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":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_newAdminFeeInBasisPoints","type":"uint16"}],"name":"updateAdminFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMaximumLoanDuration","type":"uint256"}],"name":"updateMaximumLoanDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_loanId","type":"uint32"}],"name":"wrapCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60c06040526301e91c806002556003805461ffff191660191790553480156200002757600080fd5b5060405162005038380380620050388339810160408190526200004a91620002ca565b604051633750258560e11b815260206004820152601760248201527f4449524543545f4c4f414e5f434f4f5244494e41544f52000000000000000000604482015283908390734ddc8349ccca17f55cded3e81cec21dfeeb366f990636ea04b0a9060640160206040518083038186803b158015620000c757600080fd5b505af4158015620000dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001029190620003c6565b8383806200011081620001a3565b50506000805460ff60a01b19168155600180556001600160601b0319606085901b1660a05260808390525b81518110156200019557620001808282815181106200016a57634e487b7160e01b600052603260045260246000fd5b60200260200101516001620001f360201b60201c565b806200018c81620003df565b9150506200013b565b50505050505050506200041d565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b0382166200024e5760405162461bcd60e51b815260206004820152601560248201527f6572633230206973207a65726f20616464726573730000000000000000000000604482015260640160405180910390fd5b6001600160a01b038216600081815260096020908152604091829020805460ff191685151590811790915591519182527ff100355be652ecc881568750e6a98c0713e4316f75d5314ebc9039e0acb52f24910160405180910390a25050565b80516001600160a01b0381168114620002c557600080fd5b919050565b600080600060608486031215620002df578283fd5b620002ea84620002ad565b92506020620002fb818601620002ad565b60408601519093506001600160401b038082111562000318578384fd5b818701915087601f8301126200032c578384fd5b81518181111562000341576200034162000407565b8060051b604051601f19603f8301168101818110858211171562000369576200036962000407565b604052828152858101935084860182860187018c101562000388578788fd5b8795505b83861015620003b557620003a081620002ad565b8552600195909501949386019386016200038c565b508096505050505050509250925092565b600060208284031215620003d8578081fd5b5051919050565b60006000198214156200040057634e487b7160e01b81526011600452602481fd5b5060010190565b634e487b7160e01b600052604160045260246000fd5b60805160a05160601c614b82620004b6600039600081816104920152818161081e01528181610b1f01528181610ca901528181610fff01528181611109015281816117300152818161189c01528181611bf40152818161230701528181612793015281816129e401528181612c8f01526136030152600081816105be0152818161170701528181611bcb01526135da0152614b826000f3fe608060405234801561001057600080fd5b50600436106101dc5760003560e01c80635beb7abb116101055780638456cb591161009d5780638456cb59146106065780638da5cb5b1461060e578063a4441a6f14610616578063b18e777214610624578063bc197c8114610637578063bce42e421461064a578063efa3b7241461065d578063f23a6e6114610670578063f2fde38b1461069057600080fd5b80635beb7abb146105155780635c975abb14610528578063616693d814610530578063645097371461055157806369ddcbe6146105645780636ed93dd01461059d57806377cfa991146105b95780637836baf1146105e057806379b64040146105f357600080fd5b80632b476f22116101785780632b476f221461043e57806331863d6714610451578063318dacd31461047a578063365a86fc1461048d5780633bddfcb5146104c15780633f4ba83a146104d457806347948d92146104dc57806356efe98c146104ef57806359a727341461050257600080fd5b806301ffc9a7146101e15780630717f3aa146102095780630ff81c3f1461022c578063150b7a0214610296578063192b355d146102cd5780631c6caf41146102e4578063227cda18146102f957806328aaa7b4146103ff5780632b2180221461042b575b600080fd5b6101f46101ef366004614156565b6106a3565b60405190151581526020015b60405180910390f35b6101f461021736600461433f565b60066020526000908152604090205460ff1681565b61026c61023a36600461433f565b6005602052600090815260409020546001600160a01b0381169061ffff600160a01b8204811691600160b01b90041683565b604080516001600160a01b03909416845261ffff9283166020850152911690820152606001610200565b6102b46102a4366004613ed0565b630a85bd0160e11b949350505050565b6040516001600160e01b03199091168152602001610200565b6102d660025481565b604051908152602001610200565b6102f76102f23660046142d7565b6106f5565b005b61038b61030736600461433f565b600460208190526000918252604090912080546001820154600283015460038401549484015460058501546006909501549395929491936001600160a01b0380851694600160a01b80820463ffffffff1695600160c01b830461ffff90811696600160d01b909404169484841694929093046001600160401b03169290821691168b565b604080519b8c5260208c019a909a52988a01979097526001600160a01b0395861660608a015263ffffffff909416608089015261ffff92831660a0890152911660c0870152821660e08601526001600160401b03166101008501529081166101208401521661014082015261016001610200565b6101f461040d366004613d78565b6001600160a01b031660009081526009602052604090205460ff1690565b6102f761043936600461433f565b6107c5565b6102f761044c366004614037565b61092d565b6102d661045f36600461433f565b63ffffffff1660009081526004602052604090206001015490565b6102f7610488366004614377565b610ac7565b6104b47f000000000000000000000000000000000000000000000000000000000000000081565b60405161020091906145ea565b6102f76104cf366004613db0565b610d0e565b6102f7610e1c565b6102f76104ea36600461430f565b610e55565b6102f76104fd3660046141fc565b610f06565b6102f761051036600461433f565b610fa7565b6102f7610523366004614037565b6111e9565b6101f46113a1565b6102d6762224a922a1aa2fa627a0a72fa324ac22a22fa7a32322a960491b81565b6102f761055f36600461430f565b6113b1565b6101f4610572366004613fdf565b6001600160a01b03919091166000908152600860209081526040808320938352929052205460ff1690565b6105a661271081565b60405161ffff9091168152602001610200565b6102d67f000000000000000000000000000000000000000000000000000000000000000081565b6102f76105ee366004613fb2565b611432565b6102f7610601366004614078565b61146f565b6102f7611586565b6104b46115bd565b6003546105a69061ffff1681565b6102f7610632366004614416565b6115cc565b6102b4610645366004613e16565b611618565b6102f761065836600461433f565b611663565b6102f761066b36600461433f565b611844565b6102b461067e366004613f39565b63f23a6e6160e01b9695505050505050565b6102f761069e366004613d78565b611b11565b60006001600160e01b03198216630271189760e51b14806106d457506001600160e01b03198216630a85bd0160e11b145b806106ef57506001600160e01b031982166301ffc9a760e01b145b92915050565b336106fe6115bd565b6001600160a01b03161461072d5760405162461bcd60e51b815260040161072490614685565b60405180910390fd5b61271061ffff8216111561077a5760405162461bcd60e51b81526020600482015260146024820152730626173697320706f696e7473203e2031303030360641b6044820152606401610724565b6003805461ffff191661ffff83169081179091556040519081527f03017365bbe16943b524030df07e7689168ab63e854d27417498e6f9dc584dab906020015b60405180910390a150565b600260015414156107e85760405162461bcd60e51b8152600401610724906146e7565b6002600155604051630120b83960e51b8152734d9ad703d5f62ad82c34311ac4f7dd08fb087c68906324170720906108469084907f0000000000000000000000000000000000000000000000000000000000000000906004016148fe565b60006040518083038186803b15801561085e57600080fd5b505af4158015610872573d6000803e3d6000fd5b5050505060008060008061088585611bb1565b935093509350935061089985858585611fc5565b6108a5858584846121db565b5050505063ffffffff1660009081526004602081815260408084208481556001808201869055600282018690556003820180546001600160e01b03199081169091559482018054909516909455600580820180546001600160a01b03199081169091556006909201805490921690915590915290912080546001600160c01b03191690558055565b336109366115bd565b6001600160a01b03161461095c5760405162461bcd60e51b815260040161072490614685565b6001600160a01b038316600090815260076020908152604080832085845290915290205483901561099f5760405162461bcd60e51b8152600401610724906146ba565b6040516331a9108f60e11b81526004810184905230906001600160a01b03831690636352211e9060240160206040518083038186803b1580156109e157600080fd5b505afa1580156109f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a199190613d94565b6001600160a01b031614610a5f5760405162461bcd60e51b815260206004820152600d60248201526c1b999d081b9bdd081bdddb9959609a1b6044820152606401610724565b604051632142170760e11b81526001600160a01b038216906342842e0e90610a8f903090869088906004016145fe565b600060405180830381600087803b158015610aa957600080fd5b505af1158015610abd573d6000803e3d6000fd5b5050505050505050565b60026001541415610aea5760405162461bcd60e51b8152600401610724906146e7565b6002600155604051625d27e360e91b8152734d9ad703d5f62ad82c34311ac4f7dd08fb087c689063ba4fc60090610b47908b907f0000000000000000000000000000000000000000000000000000000000000000906004016148fe565b60006040518083038186803b158015610b5f57600080fd5b505af4158015610b73573d6000803e3d6000fd5b5050505063ffffffff881660009081526006602052604090205460ff1615610bad5760405162461bcd60e51b81526004016107249061464e565b63ffffffff8881166000908152600460208181526040928390208351610160810185528154815260018201549281019290925260028101548285015260038101546001600160a01b038082166060850152600160a01b8083049097166080850152600160c01b820461ffff90811660a0860152600160d01b90920490911660c08401528184015480821660e0850152959095046001600160401b03166101008301526005810154851661012083015260060154909316610140840152905163066d303d60e31b81527368fa3ed5f5642b7d6560de759bca7451dd5c78439163336981e891610ccf918d9186918e918e918e918e918e918e918e917f0000000000000000000000000000000000000000000000000000000000000000910161491d565b60006040518083038186803b158015610ce757600080fd5b505af4158015610cfb573d6000803e3d6000fd5b5050600180555050505050505050505050565b33610d176115bd565b6001600160a01b031614610d3d5760405162461bcd60e51b815260040161072490614685565b6040516370a0823160e01b815282906000906001600160a01b038316906370a0823190610d6e9030906004016145ea565b60206040518083038186803b158015610d8657600080fd5b505afa158015610d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbe9190614327565b905060008111610e025760405162461bcd60e51b815260206004820152600f60248201526e1b9bc81d1bdad95b9cc81bdddb9959608a1b6044820152606401610724565b610e166001600160a01b03831684836121f1565b50505050565b33610e256115bd565b6001600160a01b031614610e4b5760405162461bcd60e51b815260040161072490614685565b610e53612247565b565b33610e5e6115bd565b6001600160a01b031614610e845760405162461bcd60e51b815260040161072490614685565b63ffffffff811115610ed15760405162461bcd60e51b81526020600482015260166024820152754c6f616e206475726174696f6e206f766572666c6f7760501b6044820152606401610724565b60028190556040518181527f64f65a4a1a932867ad599da36210fc47c698b3abb2413cfdfd36bf59697a69cb906020016107ba565b610f0e612296565b60026001541415610f315760405162461bcd60e51b8152600401610724906146e7565b60026001556060830151600090610f47906122de565b9050610f538482612404565b610f5c84612629565b610f9d762224a922a1aa2fa627a0a72fa324ac22a22fa7a32322a960491b610f848684612694565b610f9685600001518660200151612748565b8787612846565b5050600180555050565b60026001541415610fca5760405162461bcd60e51b8152600401610724906146e7565b6002600155604051625d27e360e91b8152734d9ad703d5f62ad82c34311ac4f7dd08fb087c689063ba4fc600906110279084907f0000000000000000000000000000000000000000000000000000000000000000906004016148fe565b60006040518083038186803b15801561103f57600080fd5b505af4158015611053573d6000803e3d6000fd5b5050505063ffffffff811660009081526006602052604090205460ff161561108d5760405162461bcd60e51b81526004016107249061464e565b63ffffffff8116600090815260046020908152604080832060058101546001600160a01b0316845260078352818420600282015485529092528220805491926001926110da908490614a7d565b90915550506040516311517d3f60e11b815263ffffffff83166004820152602481018290526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016604482015260009081907368fa3ed5f5642b7d6560de759bca7451dd5c7843906322a2fa7e90606401604080518083038186803b15801561116957600080fd5b505af415801561117d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a1919061400a565b6001600160a01b0382166000908152600760209081526040808320848452909152812080549395509193506001926111da908490614a65565b90915550506001805550505050565b336111f26115bd565b6001600160a01b0316146112185760405162461bcd60e51b815260040161072490614685565b604051627eeac760e11b815283906000906001600160a01b0383169062fdd58e906112499030908890600401614622565b60206040518083038186803b15801561126157600080fd5b505afa158015611275573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112999190614327565b6001600160a01b0386166000908152600760209081526040808320888452909152902054909150156112dd5760405162461bcd60e51b8152600401610724906146ba565b6000811161131d5760405162461bcd60e51b815260206004820152600d60248201526c1b9bc81b999d1cc81bdddb9959609a1b6044820152606401610724565b604051637921219560e11b81523060048201526001600160a01b038481166024830152604482018690526064820183905260a06084830152600060a483015283169063f242432a9060c401600060405180830381600087803b15801561138257600080fd5b505af1158015611396573d6000803e3d6000fd5b505050505050505050565b600054600160a01b900460ff1690565b33600090815260086020908152604080832084845290915290205460ff161561140c5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b6044820152606401610724565b33600090815260086020908152604080832093835292905220805460ff19166001179055565b3361143b6115bd565b6001600160a01b0316146114615760405162461bcd60e51b815260040161072490614685565b61146b8282612b4a565b5050565b336114786115bd565b6001600160a01b03161461149e5760405162461bcd60e51b815260040161072490614685565b805182511461150b5760405162461bcd60e51b815260206004820152603360248201527f73657445524332305065726d6974732066756e6374696f6e20696e666f726d616044820152720e8d2dedc40c2e4d2e8f240dad2e6dac2e8c6d606b1b6064820152608401610724565b60005b82518110156115815761156f83828151811061153a57634e487b7160e01b600052603260045260246000fd5b602002602001015183838151811061156257634e487b7160e01b600052603260045260246000fd5b6020026020010151612b4a565b8061157981614ac0565b91505061150e565b505050565b3361158f6115bd565b6001600160a01b0316146115b55760405162461bcd60e51b815260040161072490614685565b610e53612bf7565b6000546001600160a01b031690565b6115d4612296565b600260015414156115f75760405162461bcd60e51b8152600401610724906146e7565b600260015561160b87878787878787612c3a565b5050600180555050505050565b60405162461bcd60e51b815260206004820152601b60248201527f45524331313535206261746368206e6f7420737570706f7274656400000000006044820152600090606401610724565b600260015414156116865760405162461bcd60e51b8152600401610724906146e7565b600260015563ffffffff81166000908152600460205260409020600601546001600160a01b03163381146116f85760405162461bcd60e51b815260206004820152601960248201527839b2b73232b9103430b9903a37903132903137b93937bbb2b960391b6044820152606401610724565b604051631c2d8fb360e31b81527f000000000000000000000000000000000000000000000000000000000000000060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e16c7d989060240160206040518083038186803b15801561177a57600080fd5b505afa15801561178e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b29190613d94565b604051631b982cf160e01b81529091506001600160a01b03821690631b982cf1906117e390869086906004016148fe565b600060405180830381600087803b1580156117fd57600080fd5b505af1158015611811573d6000803e3d6000fd5b50505063ffffffff909316600090815260046020526040902060060180546001600160a01b031916905550506001805550565b600260015414156118675760405162461bcd60e51b8152600401610724906146e7565b6002600155604051625d27e360e91b8152734d9ad703d5f62ad82c34311ac4f7dd08fb087c689063ba4fc600906118c49084907f0000000000000000000000000000000000000000000000000000000000000000906004016148fe565b60006040518083038186803b1580156118dc57600080fd5b505af41580156118f0573d6000803e3d6000fd5b5050505063ffffffff811660009081526006602052604090205460ff161561192a5760405162461bcd60e51b81526004016107249061464e565b60008060008061193985611bb1565b93509350935093506000826080015163ffffffff168361010001516001600160401b03166119679190614a65565b90508042116119b25760405162461bcd60e51b8152602060048201526017602482015276131bd85b881a5cc81b9bdd081bdd995c991d59481e595d604a1b6044820152606401610724565b336001600160a01b03851614611a065760405162461bcd60e51b81526020600482015260196024820152784f6e6c79206c656e6465722063616e206c697175696461746560381b6044820152606401610724565b611a12868585856121db565b8251604080850151610120860151825193845260208401919091529082018390524260608301526001600160a01b039081166080830152808616919087169063ffffffff8916907f4fac0ff43299a330bce57d0579985305af580acf256a6d7977083ede81be13269060a00160405180910390a450505063ffffffff90921660009081526004602081815260408084208481556001808201869055600282018690556003820180546001600160e01b03199081169091559482018054909516909455600580820180546001600160a01b03199081169091556006909201805490921690915590915290912080546001600160c01b031916905580555050565b33611b1a6115bd565b6001600160a01b031614611b405760405162461bcd60e51b815260040161072490614685565b6001600160a01b038116611ba55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610724565b611bae81612fb9565b50565b600080611bbc613a9e565b604051631c2d8fb360e31b81527f000000000000000000000000000000000000000000000000000000000000000060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e16c7d989060240160206040518083038186803b158015611c3e57600080fd5b505afa158015611c52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c769190613d94565b60405163e6c5a54160e01b815263ffffffff871660048201529091506000906001600160a01b0383169063e6c5a5419060240160606040518083038186803b158015611cc157600080fd5b505afa158015611cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf9919061417e565b60208181015163ffffffff898116600090815260048085526040918290208251610160810184528154815260018201549681019690965260028101549286019290925260038201546001600160a01b038082166060880152600160a01b8083049095166080880152600160c01b820461ffff90811660a0890152600160d01b90920490911660c08701529082015480821660e08701526001600160401b03939004831661010086015260058201548116610120860152600690910154166101408401819052929650929350919091169015611ddb578361014001519550611ecc565b826001600160a01b0316638208e76c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1457600080fd5b505afa158015611e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4c9190613d94565b6001600160a01b0316636352211e826040518263ffffffff1660e01b8152600401611e7991815260200190565b60206040518083038186803b158015611e9157600080fd5b505afa158015611ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec99190613d94565b95505b826001600160a01b0316634fbe68a06040518163ffffffff1660e01b815260040160206040518083038186803b158015611f0557600080fd5b505afa158015611f19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f3d9190613d94565b6001600160a01b0316636352211e826040518263ffffffff1660e01b8152600401611f6a91815260200190565b60206040518083038186803b158015611f8257600080fd5b505afa158015611f96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fba9190613d94565b945050509193509193565b63ffffffff84166000908152600560209081526040808320815160608101835290546001600160a01b038116825261ffff600160a01b8204811694830194909452600160b01b900490921690820152908061201f84613009565b6060860151919350915061203e906001600160a01b03163387846130d2565b602083015160405163d0d9287b60e01b81526004810184905261ffff9091166024820152600090734d9ad703d5f62ad82c34311ac4f7dd08fb087c689063d0d9287b9060440160206040518083038186803b15801561209c57600080fd5b505af41580156120b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d49190614327565b90506000811180156120ef575083516001600160a01b031615155b1561211e576120fe8184614a7d565b8451606087015191945061211e916001600160a01b0316903390846130d2565b6121403361212a6115bd565b60608801516001600160a01b03169190866130d2565b845160408087015186516101208901516060808b0151855196875260208701949094528585018890528501889052608085018690526001600160a01b0391821660a0860152811660c085015290811660e0840152905188821692918a169163ffffffff8c16917f3687d64f40b11dd1c102a76882ac1735891c546a96ae27935eb5c7865b9d86fa918190036101000190a45050505050505050565b6121e68483836130f3565b610e168230856131b6565b6115818363a9059cbb60e01b8484604051602401612210929190614622565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613259565b61224f61332b565b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405161228c91906145ea565b60405180910390a1565b61229e6113a1565b15610e535760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610724565b604051631c2d8fb360e31b81526d5045524d49545445445f4e46545360901b60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e16c7d989060240160206040518083038186803b15801561235157600080fd5b505afa158015612365573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123899190613d94565b6001600160a01b031663b8c8aff8836040518263ffffffff1660e01b81526004016123b491906145ea565b60206040518083038186803b1580156123cc57600080fd5b505afa1580156123e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ef9190613d94565b60c08201516001600160a01b031660009081526009602052604090205460ff1661247f5760405162461bcd60e51b815260206004820152602660248201527f43757272656e63792064656e6f6d696e6174696f6e206973206e6f74207065726044820152651b5a5d1d195960d21b6064820152608401610724565b6001600160a01b0381166124e65760405162461bcd60e51b815260206004820152602860248201527f4e465420636f6c6c61746572616c20636f6e7472616374206973206e6f742070604482015267195c9b5a5d1d195960c21b6064820152608401610724565b600254826080015163ffffffff1611156125565760405162461bcd60e51b815260206004820152602b60248201527f4c6f616e206475726174696f6e2065786365656473206d6178696d756d206c6f60448201526a30b710323ab930ba34b7b760a91b6064820152608401610724565b608082015163ffffffff166125ad5760405162461bcd60e51b815260206004820152601c60248201527f4c6f616e206475726174696f6e2063616e6e6f74206265207a65726f000000006044820152606401610724565b60035460a083015161ffff90811691161461146b5760405162461bcd60e51b815260206004820152603660248201527f5468652061646d696e2066656520686173206368616e6765642073696e6365206044820152753a3434b99037b93232b9103bb0b99039b4b3b732b21760511b6064820152608401610724565b805160208201511015611bae5760405162461bcd60e51b815260206004820152602d60248201527f4e6567617469766520696e7465726573742072617465206c6f616e732061726560448201526c103737ba1030b63637bbb2b21760991b6064820152608401610724565b61269c613a9e565b6040518061016001604052808460000151815260200184602001518152602001846040015181526020018460c001516001600160a01b03168152602001846080015163ffffffff168152602001600061ffff1681526020018460a0015161ffff168152602001836001600160a01b03168152602001426001600160401b0316815260200184606001516001600160a01b03168152602001336001600160a01b0316815250905092915050565b6040805160608101825260008082526020820181905291810191909152604080516060810182526001600160a01b038086168083529251632044e57f60e01b815260048101939093527f0000000000000000000000000000000000000000000000000000000000000000166024830152906020820190734d9ad703d5f62ad82c34311ac4f7dd08fb087c6890632044e57f9060440160206040518083038186803b1580156127f557600080fd5b505af4158015612809573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061282d91906142f3565b61ffff1681526020018361ffff16815250905092915050565b6040808201516001600160a01b0316600090815260086020908152828220845183529052205460ff16156128b35760405162461bcd60e51b815260206004820152601460248201527313195b99195c881b9bdb98d9481a5b9d985b1a5960621b6044820152606401610724565b6040808201516001600160a01b0316600090815260086020908152828220845183529052819020805460ff191660011790555163aaf0891960e01b815273d8286584cb2cb4bbd600149b9e5c8a5e3b6914649063aaf089199061291c908590859060040161486f565b60206040518083038186803b15801561293457600080fd5b505af4158015612948573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296c919061413a565b6129b85760405162461bcd60e51b815260206004820152601b60248201527f4c656e646572207369676e617475726520697320696e76616c696400000000006044820152606401610724565b604051631c2d8fb360e31b8152702624a8aaa4a227aa29afa12aa7222622a960791b60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e16c7d989060240160206040518083038186803b158015612a2e57600080fd5b505afa158015612a42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a669190613d94565b9050806001600160a01b03168561012001516001600160a01b03161415612acf5760405162461bcd60e51b815260206004820152601b60248201527f436f6c6c61746572616c2063616e6e6f742062652062756e646c6500000000006044820152606401610724565b6000612ae78787873387604001518960e00151613376565b905082604001516001600160a01b0316336001600160a01b03168263ffffffff167f42cc7f53ef7b494c5dd6f0095175f7d07b5d3d7b2a03f34389fea445ba4a3a8b8989604051612b3992919061471e565b60405180910390a450505050505050565b6001600160a01b038216612b985760405162461bcd60e51b81526020600482015260156024820152746572633230206973207a65726f206164647265737360581b6044820152606401610724565b6001600160a01b038216600081815260096020908152604091829020805460ff191685151590811790915591519182527ff100355be652ecc881568750e6a98c0713e4316f75d5314ebc9039e0acb52f24910160405180910390a25050565b612bff612296565b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861227f3390565b63ffffffff871660009081526004602081905260408083209051631928588360e31b81529092918291734d9ad703d5f62ad82c34311ac4f7dd08fb087c689163c942c41891612cb59187918f918f918f918e917f00000000000000000000000000000000000000000000000000000000000000009101614764565b604080518083038186803b158015612ccc57600080fd5b505af4158015612ce0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d049190613de8565b6001600160a01b03811660008181526008602090815260408083208c8452825291829020805460ff1916600117905581516080810183528b81529081018a9052808201929092526060820188905251632308a79d60e21b815292945090925073d8286584cb2cb4bbd600149b9e5c8a5e3b69146491638c229e7491612d93918e918e918e918e916004016149b4565b60206040518083038186803b158015612dab57600080fd5b505af4158015612dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de3919061413a565b612e3a5760405162461bcd60e51b815260206004820152602260248201527f52656e65676f74696174696f6e207369676e617475726520697320696e76616c6044820152611a5960f21b6064820152608401610724565b60008715612f245760038401546040516325a8a74560e21b8152600481018a9052600160d01b90910461ffff166024820152734d9ad703d5f62ad82c34311ac4f7dd08fb087c68906396a29d149060440160206040518083038186803b158015612ea357600080fd5b505af4158015612eb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612edb9190614327565b9050612f028383612eec848c614a7d565b60038801546001600160a01b03169291906130d2565b612f2483612f0e6115bd565b60038701546001600160a01b03169190846130d2565b60038401805463ffffffff60a01b1916600160a01b63ffffffff8d811691820292909217909255600186018b905560408051928352602083018c905282018a9052606082018390526001600160a01b0384811692908616918e16907f37357bed780fda5aed28c32fe9cd762cb2f2f8a70c0d9b342aba59c945943ca09060800160405180910390a45050505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000806000836000015184602001516130229190614a7d565b60c08501516040516325a8a74560e21b81526004810183905261ffff9091166024820152909150734d9ad703d5f62ad82c34311ac4f7dd08fb087c68906396a29d149060440160206040518083038186803b15801561308057600080fd5b505af4158015613094573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b89190614327565b92508284602001516130ca9190614a7d565b915050915091565b610e16846323b872dd60e01b858585604051602401612210939291906145fe565b63ffffffff83166000908152600660209081526040808320805460ff191660019081179091556101208601516001600160a01b0316845260078352818420868301518552909252822080549192909161314d908490614a7d565b909155505060405163490b1f5360e11b815263ffffffff841660048201526001600160a01b038216906392163ea690602401600060405180830381600087803b15801561319957600080fd5b505af11580156131ad573d6000803e3d6000fd5b50505050505050565b60e083015161012084015160408086015181516001600160a01b038781166024830152868116604483015290931660648401526084808401919091528151808403909101815260a49092018152602080830180516001600160e01b031663b030667160e01b17905281518083019092528082527f4e4654206e6f74207375636365737366756c6c79207472616e7366657272656490820152610e1692919061339c565b60006132ae826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661347b9092919063ffffffff16565b80519091501561158157808060200190518101906132cc919061413a565b6115815760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610724565b6133336113a1565b610e535760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610724565b60006133838685306131b6565b613391878787878787613492565b979650505050505050565b60606001600160a01b0384163b6134045760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610724565b600080856001600160a01b03168560405161341f91906145ce565b600060405180830381855af49150503d806000811461345a576040519150601f19603f3d011682016040523d82523d6000602084013e61345f565b606091505b509150915061346f82828661393f565b925050505b9392505050565b606061348a8484600085613978565b949350505050565b6101208501516001600160a01b03166000908152600760209081526040808320818901518452909152812080546001919083906134d0908490614a65565b90915550508551604086810151905163331cf13160e11b8152600481019290925261ffff1660248201526001600160a01b0383166044820152600090734d9ad703d5f62ad82c34311ac4f7dd08fb087c6890636639e2629060640160206040518083038186803b15801561354357600080fd5b505af4158015613557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061357b9190614327565b9050600081886000015161358f9190614a7d565b905081156135b15760608801516135b1906001600160a01b03168686856130d2565b60608801516135cb906001600160a01b03168688846130d2565b604051631c2d8fb360e31b81527f000000000000000000000000000000000000000000000000000000000000000060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e16c7d989060240160206040518083038186803b15801561364d57600080fd5b505afa158015613661573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136859190613d94565b60405163d1f7659560e01b81529091506001600160a01b0382169063d1f76595906136b69089908e90600401614622565b602060405180830381600087803b1580156136d057600080fd5b505af11580156136e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613708919061435b565b935088600460008663ffffffff1663ffffffff16815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160030160186101000a81548161ffff021916908361ffff16021790555060c082015181600301601a6101000a81548161ffff021916908361ffff16021790555060e08201518160040160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160040160146101000a8154816001600160401b0302191690836001600160401b031602179055506101208201518160050160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506101408201518160060160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555090505087600560008663ffffffff1663ffffffff16815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548161ffff021916908361ffff1602179055509050505050509695505050505050565b6060831561394e575081613474565b82511561395e5782518084602001fd5b8160405162461bcd60e51b8152600401610724919061463b565b6060824710156139d95760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610724565b6001600160a01b0385163b613a305760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610724565b600080866001600160a01b03168587604051613a4c91906145ce565b60006040518083038185875af1925050503d8060008114613a89576040519150601f19603f3d011682016040523d82523d6000602084013e613a8e565b606091505b509150915061339182828661393f565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b8035613b0581614b07565b919050565b600082601f830112613b1a578081fd5b81356020613b2f613b2a83614a42565b614a12565b80838252828201915082860187848660051b8901011115613b4e578586fd5b855b85811015613b75578135613b6381614b1c565b84529284019290840190600101613b50565b5090979650505050505050565b60008083601f840112613b93578182fd5b5081356001600160401b03811115613ba9578182fd5b6020830191508360208260051b8501011115613bc457600080fd5b9250929050565b60008083601f840112613bdc578182fd5b5081356001600160401b03811115613bf2578182fd5b602083019150836020828501011115613bc457600080fd5b600082601f830112613c1a578081fd5b81356001600160401b03811115613c3357613c33614af1565b613c46601f8201601f1916602001614a12565b818152846020838601011115613c5a578283fd5b816020850160208301379081016020019190915292915050565b600060408284031215613c85578081fd5b604051604081018181106001600160401b0382111715613ca757613ca7614af1565b6040529050808235613cb881614b07565b81526020830135613cc881614b2a565b6020919091015292915050565b600060808284031215613ce6578081fd5b604051608081016001600160401b038282108183111715613d0957613d09614af1565b81604052829350843583526020850135602084015260408501359150613d2e82614b07565b8160408401526060850135915080821115613d4857600080fd5b50613d5585828601613c0a565b6060830152505092915050565b8035613b0581614b2a565b8035613b0581614b3a565b600060208284031215613d89578081fd5b813561347481614b07565b600060208284031215613da5578081fd5b815161347481614b07565b60008060408385031215613dc2578081fd5b8235613dcd81614b07565b91506020830135613ddd81614b07565b809150509250929050565b60008060408385031215613dfa578182fd5b8251613e0581614b07565b6020840151909250613ddd81614b07565b60008060008060008060008060a0898b031215613e31578384fd5b8835613e3c81614b07565b97506020890135613e4c81614b07565b965060408901356001600160401b0380821115613e67578586fd5b613e738c838d01613b82565b909850965060608b0135915080821115613e8b578586fd5b613e978c838d01613b82565b909650945060808b0135915080821115613eaf578384fd5b50613ebc8b828c01613bcb565b999c989b5096995094979396929594505050565b60008060008060808587031215613ee5578182fd5b8435613ef081614b07565b93506020850135613f0081614b07565b92506040850135915060608501356001600160401b03811115613f21578182fd5b613f2d87828801613c0a565b91505092959194509250565b60008060008060008060a08789031215613f51578384fd5b8635613f5c81614b07565b95506020870135613f6c81614b07565b9450604087013593506060870135925060808701356001600160401b03811115613f94578283fd5b613fa089828a01613bcb565b979a9699509497509295939492505050565b60008060408385031215613fc4578182fd5b8235613fcf81614b07565b91506020830135613ddd81614b1c565b60008060408385031215613ff1578182fd5b8235613ffc81614b07565b946020939093013593505050565b6000806040838503121561401c578182fd5b825161402781614b07565b6020939093015192949293505050565b60008060006060848603121561404b578081fd5b833561405681614b07565b925060208401359150604084013561406d81614b07565b809150509250925092565b6000806040838503121561408a578182fd5b82356001600160401b03808211156140a0578384fd5b818501915085601f8301126140b3578384fd5b813560206140c3613b2a83614a42565b8083825282820191508286018a848660051b89010111156140e2578889fd5b8896505b8487101561410d5780356140f981614b07565b8352600196909601959183019183016140e6565b5096505086013592505080821115614123578283fd5b5061413085828601613b0a565b9150509250929050565b60006020828403121561414b578081fd5b815161347481614b1c565b600060208284031215614167578081fd5b81356001600160e01b031981168114613474578182fd5b60006060828403121561418f578081fd5b604051606081016001600160401b0382821081831117156141b2576141b2614af1565b81604052845191506141c382614b07565b90825260208401519080821682146141d9578384fd5b5060208201526040830151600381106141f0578283fd5b60408201529392505050565b6000806000838503610160811215614212578182fd5b61010080821215614221578283fd5b6142296149e9565b915085358252602086013560208301526040860135604083015261424f60608701613afa565b606083015261426060808701613d6d565b608083015261427160a08701613d62565b60a083015261428260c08701613afa565b60c083015261429360e08701613afa565b60e08301529093508401356001600160401b038111156142b1578182fd5b6142bd86828701613cd5565b9250506142ce856101208601613c74565b90509250925092565b6000602082840312156142e8578081fd5b813561347481614b2a565b600060208284031215614304578081fd5b815161347481614b2a565b600060208284031215614320578081fd5b5035919050565b600060208284031215614338578081fd5b5051919050565b600060208284031215614350578081fd5b813561347481614b3a565b60006020828403121561436c578081fd5b815161347481614b3a565b60008060008060008060008060e0898b031215614392578182fd5b883561439d81614b3a565b975060208901356143ad81614b07565b965060408901356001600160401b038111156143c7578283fd5b6143d38b828c01613bcb565b90975095505060608901356143e781614b07565b93506080890135925060a08901356143fe81614b1c565b8092505060c089013590509295985092959890939650565b600080600080600080600060e0888a031215614430578081fd5b873561443b81614b3a565b9650602088013561444b81614b3a565b955060408801359450606088013593506080880135925060a0880135915060c08801356001600160401b03811115614481578182fd5b61448d8a828b01613c0a565b91505092959891949750929550565b6001600160a01b03169052565b600081518084526144c1816020860160208601614a94565b601f01601f19169290920160200192915050565b80518252602081015160208301526040810151604083015260608101516144ff606084018261449c565b506080810151614517608084018263ffffffff169052565b5060a081015161452d60a084018261ffff169052565b5060c081015161454360c084018261ffff169052565b5060e081015161455660e084018261449c565b50610100818101516001600160401b0316908301526101208082015161457e8285018261449c565b505061014080820151610e168285018261449c565b805182526020810151602083015260018060a01b036040820151166040830152600060608201516080606085015261348a60808501826144a9565b600082516145e0818460208701614a94565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b60208152600061347460208301846144a9565b6020808252601e908201527f4c6f616e20616c7265616479207265706169642f6c6971756964617465640000604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601390820152721d1bdad95b881a5cc818dbdb1b185d195c985b606a1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6101c0810161472d82856144d5565b82516001600160a01b0316610160830152602083015161ffff9081166101808401526040909301519092166101a090910152919050565b86548152600187015460208201526002870154604082015260038701546102008201906001600160a01b0361479e6060850182841661449c565b60a082901c63ffffffff16608085015261ffff60c083901c811660a08601526147d260c08601828560d01c1661ffff169052565b5060048a015491506147e960e0850182841661449c565b5060a081901c6001600160401b03166101008401525060058801546001600160a01b031661481b61012084018261449c565b5060068801546001600160a01b031661483861014084018261449c565b5063ffffffff871661016083015263ffffffff8616610180830152846101a0830152836101c08301526133916101e083018461449c565b600061012084518352602085015160208401526040850151604084015260018060a01b03606086015116606084015263ffffffff608086015116608084015261ffff60a08601511660a084015260c08501516148ce60c085018261449c565b5060e08501516148e160e085018261449c565b50806101008401526148f581840185614593565b95945050505050565b63ffffffff9290921682526001600160a01b0316602082015260400190565b600061026063ffffffff8d168352614938602084018d6144d5565b6001600160a01b038b81166101808501526101a0840182905290830189905261028090898b83860137838a018201929092529087166101c08301526101e082018690528415156102008301526102208201849052601f8801601f19168201016149a561024083018461449c565b9b9a5050505050505050505050565b600063ffffffff808816835280871660208401525084604083015283606083015260a0608083015261339160a0830184614593565b60405161010081016001600160401b0381118282101715614a0c57614a0c614af1565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614a3a57614a3a614af1565b604052919050565b60006001600160401b03821115614a5b57614a5b614af1565b5060051b60200190565b60008219821115614a7857614a78614adb565b500190565b600082821015614a8f57614a8f614adb565b500390565b60005b83811015614aaf578181015183820152602001614a97565b83811115610e165750506000910152565b6000600019821415614ad457614ad4614adb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114611bae57600080fd5b8015158114611bae57600080fd5b61ffff81168114611bae57600080fd5b63ffffffff81168114611bae57600080fdfea2646970667358221220f2e0bfce947c9c7524f4284139376adef4408696b83082d0c9db7b1b5c43cd7564736f6c634300080400330000000000000000000000007f601c53cb2209b8e204989b01bf2f87a963b6b2000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101dc5760003560e01c80635beb7abb116101055780638456cb591161009d5780638456cb59146106065780638da5cb5b1461060e578063a4441a6f14610616578063b18e777214610624578063bc197c8114610637578063bce42e421461064a578063efa3b7241461065d578063f23a6e6114610670578063f2fde38b1461069057600080fd5b80635beb7abb146105155780635c975abb14610528578063616693d814610530578063645097371461055157806369ddcbe6146105645780636ed93dd01461059d57806377cfa991146105b95780637836baf1146105e057806379b64040146105f357600080fd5b80632b476f22116101785780632b476f221461043e57806331863d6714610451578063318dacd31461047a578063365a86fc1461048d5780633bddfcb5146104c15780633f4ba83a146104d457806347948d92146104dc57806356efe98c146104ef57806359a727341461050257600080fd5b806301ffc9a7146101e15780630717f3aa146102095780630ff81c3f1461022c578063150b7a0214610296578063192b355d146102cd5780631c6caf41146102e4578063227cda18146102f957806328aaa7b4146103ff5780632b2180221461042b575b600080fd5b6101f46101ef366004614156565b6106a3565b60405190151581526020015b60405180910390f35b6101f461021736600461433f565b60066020526000908152604090205460ff1681565b61026c61023a36600461433f565b6005602052600090815260409020546001600160a01b0381169061ffff600160a01b8204811691600160b01b90041683565b604080516001600160a01b03909416845261ffff9283166020850152911690820152606001610200565b6102b46102a4366004613ed0565b630a85bd0160e11b949350505050565b6040516001600160e01b03199091168152602001610200565b6102d660025481565b604051908152602001610200565b6102f76102f23660046142d7565b6106f5565b005b61038b61030736600461433f565b600460208190526000918252604090912080546001820154600283015460038401549484015460058501546006909501549395929491936001600160a01b0380851694600160a01b80820463ffffffff1695600160c01b830461ffff90811696600160d01b909404169484841694929093046001600160401b03169290821691168b565b604080519b8c5260208c019a909a52988a01979097526001600160a01b0395861660608a015263ffffffff909416608089015261ffff92831660a0890152911660c0870152821660e08601526001600160401b03166101008501529081166101208401521661014082015261016001610200565b6101f461040d366004613d78565b6001600160a01b031660009081526009602052604090205460ff1690565b6102f761043936600461433f565b6107c5565b6102f761044c366004614037565b61092d565b6102d661045f36600461433f565b63ffffffff1660009081526004602052604090206001015490565b6102f7610488366004614377565b610ac7565b6104b47f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d81565b60405161020091906145ea565b6102f76104cf366004613db0565b610d0e565b6102f7610e1c565b6102f76104ea36600461430f565b610e55565b6102f76104fd3660046141fc565b610f06565b6102f761051036600461433f565b610fa7565b6102f7610523366004614037565b6111e9565b6101f46113a1565b6102d6762224a922a1aa2fa627a0a72fa324ac22a22fa7a32322a960491b81565b6102f761055f36600461430f565b6113b1565b6101f4610572366004613fdf565b6001600160a01b03919091166000908152600860209081526040808320938352929052205460ff1690565b6105a661271081565b60405161ffff9091168152602001610200565b6102d67f4449524543545f4c4f414e5f434f4f5244494e41544f5200000000000000000081565b6102f76105ee366004613fb2565b611432565b6102f7610601366004614078565b61146f565b6102f7611586565b6104b46115bd565b6003546105a69061ffff1681565b6102f7610632366004614416565b6115cc565b6102b4610645366004613e16565b611618565b6102f761065836600461433f565b611663565b6102f761066b36600461433f565b611844565b6102b461067e366004613f39565b63f23a6e6160e01b9695505050505050565b6102f761069e366004613d78565b611b11565b60006001600160e01b03198216630271189760e51b14806106d457506001600160e01b03198216630a85bd0160e11b145b806106ef57506001600160e01b031982166301ffc9a760e01b145b92915050565b336106fe6115bd565b6001600160a01b03161461072d5760405162461bcd60e51b815260040161072490614685565b60405180910390fd5b61271061ffff8216111561077a5760405162461bcd60e51b81526020600482015260146024820152730626173697320706f696e7473203e2031303030360641b6044820152606401610724565b6003805461ffff191661ffff83169081179091556040519081527f03017365bbe16943b524030df07e7689168ab63e854d27417498e6f9dc584dab906020015b60405180910390a150565b600260015414156107e85760405162461bcd60e51b8152600401610724906146e7565b6002600155604051630120b83960e51b8152734d9ad703d5f62ad82c34311ac4f7dd08fb087c68906324170720906108469084907f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d906004016148fe565b60006040518083038186803b15801561085e57600080fd5b505af4158015610872573d6000803e3d6000fd5b5050505060008060008061088585611bb1565b935093509350935061089985858585611fc5565b6108a5858584846121db565b5050505063ffffffff1660009081526004602081815260408084208481556001808201869055600282018690556003820180546001600160e01b03199081169091559482018054909516909455600580820180546001600160a01b03199081169091556006909201805490921690915590915290912080546001600160c01b03191690558055565b336109366115bd565b6001600160a01b03161461095c5760405162461bcd60e51b815260040161072490614685565b6001600160a01b038316600090815260076020908152604080832085845290915290205483901561099f5760405162461bcd60e51b8152600401610724906146ba565b6040516331a9108f60e11b81526004810184905230906001600160a01b03831690636352211e9060240160206040518083038186803b1580156109e157600080fd5b505afa1580156109f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a199190613d94565b6001600160a01b031614610a5f5760405162461bcd60e51b815260206004820152600d60248201526c1b999d081b9bdd081bdddb9959609a1b6044820152606401610724565b604051632142170760e11b81526001600160a01b038216906342842e0e90610a8f903090869088906004016145fe565b600060405180830381600087803b158015610aa957600080fd5b505af1158015610abd573d6000803e3d6000fd5b5050505050505050565b60026001541415610aea5760405162461bcd60e51b8152600401610724906146e7565b6002600155604051625d27e360e91b8152734d9ad703d5f62ad82c34311ac4f7dd08fb087c689063ba4fc60090610b47908b907f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d906004016148fe565b60006040518083038186803b158015610b5f57600080fd5b505af4158015610b73573d6000803e3d6000fd5b5050505063ffffffff881660009081526006602052604090205460ff1615610bad5760405162461bcd60e51b81526004016107249061464e565b63ffffffff8881166000908152600460208181526040928390208351610160810185528154815260018201549281019290925260028101548285015260038101546001600160a01b038082166060850152600160a01b8083049097166080850152600160c01b820461ffff90811660a0860152600160d01b90920490911660c08401528184015480821660e0850152959095046001600160401b03166101008301526005810154851661012083015260060154909316610140840152905163066d303d60e31b81527368fa3ed5f5642b7d6560de759bca7451dd5c78439163336981e891610ccf918d9186918e918e918e918e918e918e918e917f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d910161491d565b60006040518083038186803b158015610ce757600080fd5b505af4158015610cfb573d6000803e3d6000fd5b5050600180555050505050505050505050565b33610d176115bd565b6001600160a01b031614610d3d5760405162461bcd60e51b815260040161072490614685565b6040516370a0823160e01b815282906000906001600160a01b038316906370a0823190610d6e9030906004016145ea565b60206040518083038186803b158015610d8657600080fd5b505afa158015610d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dbe9190614327565b905060008111610e025760405162461bcd60e51b815260206004820152600f60248201526e1b9bc81d1bdad95b9cc81bdddb9959608a1b6044820152606401610724565b610e166001600160a01b03831684836121f1565b50505050565b33610e256115bd565b6001600160a01b031614610e4b5760405162461bcd60e51b815260040161072490614685565b610e53612247565b565b33610e5e6115bd565b6001600160a01b031614610e845760405162461bcd60e51b815260040161072490614685565b63ffffffff811115610ed15760405162461bcd60e51b81526020600482015260166024820152754c6f616e206475726174696f6e206f766572666c6f7760501b6044820152606401610724565b60028190556040518181527f64f65a4a1a932867ad599da36210fc47c698b3abb2413cfdfd36bf59697a69cb906020016107ba565b610f0e612296565b60026001541415610f315760405162461bcd60e51b8152600401610724906146e7565b60026001556060830151600090610f47906122de565b9050610f538482612404565b610f5c84612629565b610f9d762224a922a1aa2fa627a0a72fa324ac22a22fa7a32322a960491b610f848684612694565b610f9685600001518660200151612748565b8787612846565b5050600180555050565b60026001541415610fca5760405162461bcd60e51b8152600401610724906146e7565b6002600155604051625d27e360e91b8152734d9ad703d5f62ad82c34311ac4f7dd08fb087c689063ba4fc600906110279084907f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d906004016148fe565b60006040518083038186803b15801561103f57600080fd5b505af4158015611053573d6000803e3d6000fd5b5050505063ffffffff811660009081526006602052604090205460ff161561108d5760405162461bcd60e51b81526004016107249061464e565b63ffffffff8116600090815260046020908152604080832060058101546001600160a01b0316845260078352818420600282015485529092528220805491926001926110da908490614a7d565b90915550506040516311517d3f60e11b815263ffffffff83166004820152602481018290526001600160a01b037f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d16604482015260009081907368fa3ed5f5642b7d6560de759bca7451dd5c7843906322a2fa7e90606401604080518083038186803b15801561116957600080fd5b505af415801561117d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111a1919061400a565b6001600160a01b0382166000908152600760209081526040808320848452909152812080549395509193506001926111da908490614a65565b90915550506001805550505050565b336111f26115bd565b6001600160a01b0316146112185760405162461bcd60e51b815260040161072490614685565b604051627eeac760e11b815283906000906001600160a01b0383169062fdd58e906112499030908890600401614622565b60206040518083038186803b15801561126157600080fd5b505afa158015611275573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112999190614327565b6001600160a01b0386166000908152600760209081526040808320888452909152902054909150156112dd5760405162461bcd60e51b8152600401610724906146ba565b6000811161131d5760405162461bcd60e51b815260206004820152600d60248201526c1b9bc81b999d1cc81bdddb9959609a1b6044820152606401610724565b604051637921219560e11b81523060048201526001600160a01b038481166024830152604482018690526064820183905260a06084830152600060a483015283169063f242432a9060c401600060405180830381600087803b15801561138257600080fd5b505af1158015611396573d6000803e3d6000fd5b505050505050505050565b600054600160a01b900460ff1690565b33600090815260086020908152604080832084845290915290205460ff161561140c5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b6044820152606401610724565b33600090815260086020908152604080832093835292905220805460ff19166001179055565b3361143b6115bd565b6001600160a01b0316146114615760405162461bcd60e51b815260040161072490614685565b61146b8282612b4a565b5050565b336114786115bd565b6001600160a01b03161461149e5760405162461bcd60e51b815260040161072490614685565b805182511461150b5760405162461bcd60e51b815260206004820152603360248201527f73657445524332305065726d6974732066756e6374696f6e20696e666f726d616044820152720e8d2dedc40c2e4d2e8f240dad2e6dac2e8c6d606b1b6064820152608401610724565b60005b82518110156115815761156f83828151811061153a57634e487b7160e01b600052603260045260246000fd5b602002602001015183838151811061156257634e487b7160e01b600052603260045260246000fd5b6020026020010151612b4a565b8061157981614ac0565b91505061150e565b505050565b3361158f6115bd565b6001600160a01b0316146115b55760405162461bcd60e51b815260040161072490614685565b610e53612bf7565b6000546001600160a01b031690565b6115d4612296565b600260015414156115f75760405162461bcd60e51b8152600401610724906146e7565b600260015561160b87878787878787612c3a565b5050600180555050505050565b60405162461bcd60e51b815260206004820152601b60248201527f45524331313535206261746368206e6f7420737570706f7274656400000000006044820152600090606401610724565b600260015414156116865760405162461bcd60e51b8152600401610724906146e7565b600260015563ffffffff81166000908152600460205260409020600601546001600160a01b03163381146116f85760405162461bcd60e51b815260206004820152601960248201527839b2b73232b9103430b9903a37903132903137b93937bbb2b960391b6044820152606401610724565b604051631c2d8fb360e31b81527f4449524543545f4c4f414e5f434f4f5244494e41544f5200000000000000000060048201526000907f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d6001600160a01b03169063e16c7d989060240160206040518083038186803b15801561177a57600080fd5b505afa15801561178e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b29190613d94565b604051631b982cf160e01b81529091506001600160a01b03821690631b982cf1906117e390869086906004016148fe565b600060405180830381600087803b1580156117fd57600080fd5b505af1158015611811573d6000803e3d6000fd5b50505063ffffffff909316600090815260046020526040902060060180546001600160a01b031916905550506001805550565b600260015414156118675760405162461bcd60e51b8152600401610724906146e7565b6002600155604051625d27e360e91b8152734d9ad703d5f62ad82c34311ac4f7dd08fb087c689063ba4fc600906118c49084907f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d906004016148fe565b60006040518083038186803b1580156118dc57600080fd5b505af41580156118f0573d6000803e3d6000fd5b5050505063ffffffff811660009081526006602052604090205460ff161561192a5760405162461bcd60e51b81526004016107249061464e565b60008060008061193985611bb1565b93509350935093506000826080015163ffffffff168361010001516001600160401b03166119679190614a65565b90508042116119b25760405162461bcd60e51b8152602060048201526017602482015276131bd85b881a5cc81b9bdd081bdd995c991d59481e595d604a1b6044820152606401610724565b336001600160a01b03851614611a065760405162461bcd60e51b81526020600482015260196024820152784f6e6c79206c656e6465722063616e206c697175696461746560381b6044820152606401610724565b611a12868585856121db565b8251604080850151610120860151825193845260208401919091529082018390524260608301526001600160a01b039081166080830152808616919087169063ffffffff8916907f4fac0ff43299a330bce57d0579985305af580acf256a6d7977083ede81be13269060a00160405180910390a450505063ffffffff90921660009081526004602081815260408084208481556001808201869055600282018690556003820180546001600160e01b03199081169091559482018054909516909455600580820180546001600160a01b03199081169091556006909201805490921690915590915290912080546001600160c01b031916905580555050565b33611b1a6115bd565b6001600160a01b031614611b405760405162461bcd60e51b815260040161072490614685565b6001600160a01b038116611ba55760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610724565b611bae81612fb9565b50565b600080611bbc613a9e565b604051631c2d8fb360e31b81527f4449524543545f4c4f414e5f434f4f5244494e41544f5200000000000000000060048201526000907f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d6001600160a01b03169063e16c7d989060240160206040518083038186803b158015611c3e57600080fd5b505afa158015611c52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c769190613d94565b60405163e6c5a54160e01b815263ffffffff871660048201529091506000906001600160a01b0383169063e6c5a5419060240160606040518083038186803b158015611cc157600080fd5b505afa158015611cd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf9919061417e565b60208181015163ffffffff898116600090815260048085526040918290208251610160810184528154815260018201549681019690965260028101549286019290925260038201546001600160a01b038082166060880152600160a01b8083049095166080880152600160c01b820461ffff90811660a0890152600160d01b90920490911660c08701529082015480821660e08701526001600160401b03939004831661010086015260058201548116610120860152600690910154166101408401819052929650929350919091169015611ddb578361014001519550611ecc565b826001600160a01b0316638208e76c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611e1457600080fd5b505afa158015611e28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4c9190613d94565b6001600160a01b0316636352211e826040518263ffffffff1660e01b8152600401611e7991815260200190565b60206040518083038186803b158015611e9157600080fd5b505afa158015611ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ec99190613d94565b95505b826001600160a01b0316634fbe68a06040518163ffffffff1660e01b815260040160206040518083038186803b158015611f0557600080fd5b505afa158015611f19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f3d9190613d94565b6001600160a01b0316636352211e826040518263ffffffff1660e01b8152600401611f6a91815260200190565b60206040518083038186803b158015611f8257600080fd5b505afa158015611f96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fba9190613d94565b945050509193509193565b63ffffffff84166000908152600560209081526040808320815160608101835290546001600160a01b038116825261ffff600160a01b8204811694830194909452600160b01b900490921690820152908061201f84613009565b6060860151919350915061203e906001600160a01b03163387846130d2565b602083015160405163d0d9287b60e01b81526004810184905261ffff9091166024820152600090734d9ad703d5f62ad82c34311ac4f7dd08fb087c689063d0d9287b9060440160206040518083038186803b15801561209c57600080fd5b505af41580156120b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d49190614327565b90506000811180156120ef575083516001600160a01b031615155b1561211e576120fe8184614a7d565b8451606087015191945061211e916001600160a01b0316903390846130d2565b6121403361212a6115bd565b60608801516001600160a01b03169190866130d2565b845160408087015186516101208901516060808b0151855196875260208701949094528585018890528501889052608085018690526001600160a01b0391821660a0860152811660c085015290811660e0840152905188821692918a169163ffffffff8c16917f3687d64f40b11dd1c102a76882ac1735891c546a96ae27935eb5c7865b9d86fa918190036101000190a45050505050505050565b6121e68483836130f3565b610e168230856131b6565b6115818363a9059cbb60e01b8484604051602401612210929190614622565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613259565b61224f61332b565b6000805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405161228c91906145ea565b60405180910390a1565b61229e6113a1565b15610e535760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610724565b604051631c2d8fb360e31b81526d5045524d49545445445f4e46545360901b60048201526000907f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d6001600160a01b03169063e16c7d989060240160206040518083038186803b15801561235157600080fd5b505afa158015612365573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123899190613d94565b6001600160a01b031663b8c8aff8836040518263ffffffff1660e01b81526004016123b491906145ea565b60206040518083038186803b1580156123cc57600080fd5b505afa1580156123e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ef9190613d94565b60c08201516001600160a01b031660009081526009602052604090205460ff1661247f5760405162461bcd60e51b815260206004820152602660248201527f43757272656e63792064656e6f6d696e6174696f6e206973206e6f74207065726044820152651b5a5d1d195960d21b6064820152608401610724565b6001600160a01b0381166124e65760405162461bcd60e51b815260206004820152602860248201527f4e465420636f6c6c61746572616c20636f6e7472616374206973206e6f742070604482015267195c9b5a5d1d195960c21b6064820152608401610724565b600254826080015163ffffffff1611156125565760405162461bcd60e51b815260206004820152602b60248201527f4c6f616e206475726174696f6e2065786365656473206d6178696d756d206c6f60448201526a30b710323ab930ba34b7b760a91b6064820152608401610724565b608082015163ffffffff166125ad5760405162461bcd60e51b815260206004820152601c60248201527f4c6f616e206475726174696f6e2063616e6e6f74206265207a65726f000000006044820152606401610724565b60035460a083015161ffff90811691161461146b5760405162461bcd60e51b815260206004820152603660248201527f5468652061646d696e2066656520686173206368616e6765642073696e6365206044820152753a3434b99037b93232b9103bb0b99039b4b3b732b21760511b6064820152608401610724565b805160208201511015611bae5760405162461bcd60e51b815260206004820152602d60248201527f4e6567617469766520696e7465726573742072617465206c6f616e732061726560448201526c103737ba1030b63637bbb2b21760991b6064820152608401610724565b61269c613a9e565b6040518061016001604052808460000151815260200184602001518152602001846040015181526020018460c001516001600160a01b03168152602001846080015163ffffffff168152602001600061ffff1681526020018460a0015161ffff168152602001836001600160a01b03168152602001426001600160401b0316815260200184606001516001600160a01b03168152602001336001600160a01b0316815250905092915050565b6040805160608101825260008082526020820181905291810191909152604080516060810182526001600160a01b038086168083529251632044e57f60e01b815260048101939093527f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d166024830152906020820190734d9ad703d5f62ad82c34311ac4f7dd08fb087c6890632044e57f9060440160206040518083038186803b1580156127f557600080fd5b505af4158015612809573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061282d91906142f3565b61ffff1681526020018361ffff16815250905092915050565b6040808201516001600160a01b0316600090815260086020908152828220845183529052205460ff16156128b35760405162461bcd60e51b815260206004820152601460248201527313195b99195c881b9bdb98d9481a5b9d985b1a5960621b6044820152606401610724565b6040808201516001600160a01b0316600090815260086020908152828220845183529052819020805460ff191660011790555163aaf0891960e01b815273d8286584cb2cb4bbd600149b9e5c8a5e3b6914649063aaf089199061291c908590859060040161486f565b60206040518083038186803b15801561293457600080fd5b505af4158015612948573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061296c919061413a565b6129b85760405162461bcd60e51b815260206004820152601b60248201527f4c656e646572207369676e617475726520697320696e76616c696400000000006044820152606401610724565b604051631c2d8fb360e31b8152702624a8aaa4a227aa29afa12aa7222622a960791b60048201526000907f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d6001600160a01b03169063e16c7d989060240160206040518083038186803b158015612a2e57600080fd5b505afa158015612a42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a669190613d94565b9050806001600160a01b03168561012001516001600160a01b03161415612acf5760405162461bcd60e51b815260206004820152601b60248201527f436f6c6c61746572616c2063616e6e6f742062652062756e646c6500000000006044820152606401610724565b6000612ae78787873387604001518960e00151613376565b905082604001516001600160a01b0316336001600160a01b03168263ffffffff167f42cc7f53ef7b494c5dd6f0095175f7d07b5d3d7b2a03f34389fea445ba4a3a8b8989604051612b3992919061471e565b60405180910390a450505050505050565b6001600160a01b038216612b985760405162461bcd60e51b81526020600482015260156024820152746572633230206973207a65726f206164647265737360581b6044820152606401610724565b6001600160a01b038216600081815260096020908152604091829020805460ff191685151590811790915591519182527ff100355be652ecc881568750e6a98c0713e4316f75d5314ebc9039e0acb52f24910160405180910390a25050565b612bff612296565b6000805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861227f3390565b63ffffffff871660009081526004602081905260408083209051631928588360e31b81529092918291734d9ad703d5f62ad82c34311ac4f7dd08fb087c689163c942c41891612cb59187918f918f918f918e917f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d9101614764565b604080518083038186803b158015612ccc57600080fd5b505af4158015612ce0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d049190613de8565b6001600160a01b03811660008181526008602090815260408083208c8452825291829020805460ff1916600117905581516080810183528b81529081018a9052808201929092526060820188905251632308a79d60e21b815292945090925073d8286584cb2cb4bbd600149b9e5c8a5e3b69146491638c229e7491612d93918e918e918e918e916004016149b4565b60206040518083038186803b158015612dab57600080fd5b505af4158015612dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612de3919061413a565b612e3a5760405162461bcd60e51b815260206004820152602260248201527f52656e65676f74696174696f6e207369676e617475726520697320696e76616c6044820152611a5960f21b6064820152608401610724565b60008715612f245760038401546040516325a8a74560e21b8152600481018a9052600160d01b90910461ffff166024820152734d9ad703d5f62ad82c34311ac4f7dd08fb087c68906396a29d149060440160206040518083038186803b158015612ea357600080fd5b505af4158015612eb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612edb9190614327565b9050612f028383612eec848c614a7d565b60038801546001600160a01b03169291906130d2565b612f2483612f0e6115bd565b60038701546001600160a01b03169190846130d2565b60038401805463ffffffff60a01b1916600160a01b63ffffffff8d811691820292909217909255600186018b905560408051928352602083018c905282018a9052606082018390526001600160a01b0384811692908616918e16907f37357bed780fda5aed28c32fe9cd762cb2f2f8a70c0d9b342aba59c945943ca09060800160405180910390a45050505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000806000836000015184602001516130229190614a7d565b60c08501516040516325a8a74560e21b81526004810183905261ffff9091166024820152909150734d9ad703d5f62ad82c34311ac4f7dd08fb087c68906396a29d149060440160206040518083038186803b15801561308057600080fd5b505af4158015613094573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130b89190614327565b92508284602001516130ca9190614a7d565b915050915091565b610e16846323b872dd60e01b858585604051602401612210939291906145fe565b63ffffffff83166000908152600660209081526040808320805460ff191660019081179091556101208601516001600160a01b0316845260078352818420868301518552909252822080549192909161314d908490614a7d565b909155505060405163490b1f5360e11b815263ffffffff841660048201526001600160a01b038216906392163ea690602401600060405180830381600087803b15801561319957600080fd5b505af11580156131ad573d6000803e3d6000fd5b50505050505050565b60e083015161012084015160408086015181516001600160a01b038781166024830152868116604483015290931660648401526084808401919091528151808403909101815260a49092018152602080830180516001600160e01b031663b030667160e01b17905281518083019092528082527f4e4654206e6f74207375636365737366756c6c79207472616e7366657272656490820152610e1692919061339c565b60006132ae826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661347b9092919063ffffffff16565b80519091501561158157808060200190518101906132cc919061413a565b6115815760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610724565b6133336113a1565b610e535760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610724565b60006133838685306131b6565b613391878787878787613492565b979650505050505050565b60606001600160a01b0384163b6134045760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b6064820152608401610724565b600080856001600160a01b03168560405161341f91906145ce565b600060405180830381855af49150503d806000811461345a576040519150601f19603f3d011682016040523d82523d6000602084013e61345f565b606091505b509150915061346f82828661393f565b925050505b9392505050565b606061348a8484600085613978565b949350505050565b6101208501516001600160a01b03166000908152600760209081526040808320818901518452909152812080546001919083906134d0908490614a65565b90915550508551604086810151905163331cf13160e11b8152600481019290925261ffff1660248201526001600160a01b0383166044820152600090734d9ad703d5f62ad82c34311ac4f7dd08fb087c6890636639e2629060640160206040518083038186803b15801561354357600080fd5b505af4158015613557573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061357b9190614327565b9050600081886000015161358f9190614a7d565b905081156135b15760608801516135b1906001600160a01b03168686856130d2565b60608801516135cb906001600160a01b03168688846130d2565b604051631c2d8fb360e31b81527f4449524543545f4c4f414e5f434f4f5244494e41544f5200000000000000000060048201526000907f000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d6001600160a01b03169063e16c7d989060240160206040518083038186803b15801561364d57600080fd5b505afa158015613661573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136859190613d94565b60405163d1f7659560e01b81529091506001600160a01b0382169063d1f76595906136b69089908e90600401614622565b602060405180830381600087803b1580156136d057600080fd5b505af11580156136e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613708919061435b565b935088600460008663ffffffff1663ffffffff16815260200190815260200160002060008201518160000155602082015181600101556040820151816002015560608201518160030160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060808201518160030160146101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160030160186101000a81548161ffff021916908361ffff16021790555060c082015181600301601a6101000a81548161ffff021916908361ffff16021790555060e08201518160040160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160040160146101000a8154816001600160401b0302191690836001600160401b031602179055506101208201518160050160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506101408201518160060160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555090505087600560008663ffffffff1663ffffffff16815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548161ffff021916908361ffff16021790555060408201518160000160166101000a81548161ffff021916908361ffff1602179055509050505050509695505050505050565b6060831561394e575081613474565b82511561395e5782518084602001fd5b8160405162461bcd60e51b8152600401610724919061463b565b6060824710156139d95760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610724565b6001600160a01b0385163b613a305760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610724565b600080866001600160a01b03168587604051613a4c91906145ce565b60006040518083038185875af1925050503d8060008114613a89576040519150601f19603f3d011682016040523d82523d6000602084013e613a8e565b606091505b509150915061339182828661393f565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810182905261014081019190915290565b8035613b0581614b07565b919050565b600082601f830112613b1a578081fd5b81356020613b2f613b2a83614a42565b614a12565b80838252828201915082860187848660051b8901011115613b4e578586fd5b855b85811015613b75578135613b6381614b1c565b84529284019290840190600101613b50565b5090979650505050505050565b60008083601f840112613b93578182fd5b5081356001600160401b03811115613ba9578182fd5b6020830191508360208260051b8501011115613bc457600080fd5b9250929050565b60008083601f840112613bdc578182fd5b5081356001600160401b03811115613bf2578182fd5b602083019150836020828501011115613bc457600080fd5b600082601f830112613c1a578081fd5b81356001600160401b03811115613c3357613c33614af1565b613c46601f8201601f1916602001614a12565b818152846020838601011115613c5a578283fd5b816020850160208301379081016020019190915292915050565b600060408284031215613c85578081fd5b604051604081018181106001600160401b0382111715613ca757613ca7614af1565b6040529050808235613cb881614b07565b81526020830135613cc881614b2a565b6020919091015292915050565b600060808284031215613ce6578081fd5b604051608081016001600160401b038282108183111715613d0957613d09614af1565b81604052829350843583526020850135602084015260408501359150613d2e82614b07565b8160408401526060850135915080821115613d4857600080fd5b50613d5585828601613c0a565b6060830152505092915050565b8035613b0581614b2a565b8035613b0581614b3a565b600060208284031215613d89578081fd5b813561347481614b07565b600060208284031215613da5578081fd5b815161347481614b07565b60008060408385031215613dc2578081fd5b8235613dcd81614b07565b91506020830135613ddd81614b07565b809150509250929050565b60008060408385031215613dfa578182fd5b8251613e0581614b07565b6020840151909250613ddd81614b07565b60008060008060008060008060a0898b031215613e31578384fd5b8835613e3c81614b07565b97506020890135613e4c81614b07565b965060408901356001600160401b0380821115613e67578586fd5b613e738c838d01613b82565b909850965060608b0135915080821115613e8b578586fd5b613e978c838d01613b82565b909650945060808b0135915080821115613eaf578384fd5b50613ebc8b828c01613bcb565b999c989b5096995094979396929594505050565b60008060008060808587031215613ee5578182fd5b8435613ef081614b07565b93506020850135613f0081614b07565b92506040850135915060608501356001600160401b03811115613f21578182fd5b613f2d87828801613c0a565b91505092959194509250565b60008060008060008060a08789031215613f51578384fd5b8635613f5c81614b07565b95506020870135613f6c81614b07565b9450604087013593506060870135925060808701356001600160401b03811115613f94578283fd5b613fa089828a01613bcb565b979a9699509497509295939492505050565b60008060408385031215613fc4578182fd5b8235613fcf81614b07565b91506020830135613ddd81614b1c565b60008060408385031215613ff1578182fd5b8235613ffc81614b07565b946020939093013593505050565b6000806040838503121561401c578182fd5b825161402781614b07565b6020939093015192949293505050565b60008060006060848603121561404b578081fd5b833561405681614b07565b925060208401359150604084013561406d81614b07565b809150509250925092565b6000806040838503121561408a578182fd5b82356001600160401b03808211156140a0578384fd5b818501915085601f8301126140b3578384fd5b813560206140c3613b2a83614a42565b8083825282820191508286018a848660051b89010111156140e2578889fd5b8896505b8487101561410d5780356140f981614b07565b8352600196909601959183019183016140e6565b5096505086013592505080821115614123578283fd5b5061413085828601613b0a565b9150509250929050565b60006020828403121561414b578081fd5b815161347481614b1c565b600060208284031215614167578081fd5b81356001600160e01b031981168114613474578182fd5b60006060828403121561418f578081fd5b604051606081016001600160401b0382821081831117156141b2576141b2614af1565b81604052845191506141c382614b07565b90825260208401519080821682146141d9578384fd5b5060208201526040830151600381106141f0578283fd5b60408201529392505050565b6000806000838503610160811215614212578182fd5b61010080821215614221578283fd5b6142296149e9565b915085358252602086013560208301526040860135604083015261424f60608701613afa565b606083015261426060808701613d6d565b608083015261427160a08701613d62565b60a083015261428260c08701613afa565b60c083015261429360e08701613afa565b60e08301529093508401356001600160401b038111156142b1578182fd5b6142bd86828701613cd5565b9250506142ce856101208601613c74565b90509250925092565b6000602082840312156142e8578081fd5b813561347481614b2a565b600060208284031215614304578081fd5b815161347481614b2a565b600060208284031215614320578081fd5b5035919050565b600060208284031215614338578081fd5b5051919050565b600060208284031215614350578081fd5b813561347481614b3a565b60006020828403121561436c578081fd5b815161347481614b3a565b60008060008060008060008060e0898b031215614392578182fd5b883561439d81614b3a565b975060208901356143ad81614b07565b965060408901356001600160401b038111156143c7578283fd5b6143d38b828c01613bcb565b90975095505060608901356143e781614b07565b93506080890135925060a08901356143fe81614b1c565b8092505060c089013590509295985092959890939650565b600080600080600080600060e0888a031215614430578081fd5b873561443b81614b3a565b9650602088013561444b81614b3a565b955060408801359450606088013593506080880135925060a0880135915060c08801356001600160401b03811115614481578182fd5b61448d8a828b01613c0a565b91505092959891949750929550565b6001600160a01b03169052565b600081518084526144c1816020860160208601614a94565b601f01601f19169290920160200192915050565b80518252602081015160208301526040810151604083015260608101516144ff606084018261449c565b506080810151614517608084018263ffffffff169052565b5060a081015161452d60a084018261ffff169052565b5060c081015161454360c084018261ffff169052565b5060e081015161455660e084018261449c565b50610100818101516001600160401b0316908301526101208082015161457e8285018261449c565b505061014080820151610e168285018261449c565b805182526020810151602083015260018060a01b036040820151166040830152600060608201516080606085015261348a60808501826144a9565b600082516145e0818460208701614a94565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b60208152600061347460208301846144a9565b6020808252601e908201527f4c6f616e20616c7265616479207265706169642f6c6971756964617465640000604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601390820152721d1bdad95b881a5cc818dbdb1b185d195c985b606a1b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6101c0810161472d82856144d5565b82516001600160a01b0316610160830152602083015161ffff9081166101808401526040909301519092166101a090910152919050565b86548152600187015460208201526002870154604082015260038701546102008201906001600160a01b0361479e6060850182841661449c565b60a082901c63ffffffff16608085015261ffff60c083901c811660a08601526147d260c08601828560d01c1661ffff169052565b5060048a015491506147e960e0850182841661449c565b5060a081901c6001600160401b03166101008401525060058801546001600160a01b031661481b61012084018261449c565b5060068801546001600160a01b031661483861014084018261449c565b5063ffffffff871661016083015263ffffffff8616610180830152846101a0830152836101c08301526133916101e083018461449c565b600061012084518352602085015160208401526040850151604084015260018060a01b03606086015116606084015263ffffffff608086015116608084015261ffff60a08601511660a084015260c08501516148ce60c085018261449c565b5060e08501516148e160e085018261449c565b50806101008401526148f581840185614593565b95945050505050565b63ffffffff9290921682526001600160a01b0316602082015260400190565b600061026063ffffffff8d168352614938602084018d6144d5565b6001600160a01b038b81166101808501526101a0840182905290830189905261028090898b83860137838a018201929092529087166101c08301526101e082018690528415156102008301526102208201849052601f8801601f19168201016149a561024083018461449c565b9b9a5050505050505050505050565b600063ffffffff808816835280871660208401525084604083015283606083015260a0608083015261339160a0830184614593565b60405161010081016001600160401b0381118282101715614a0c57614a0c614af1565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614a3a57614a3a614af1565b604052919050565b60006001600160401b03821115614a5b57614a5b614af1565b5060051b60200190565b60008219821115614a7857614a78614adb565b500190565b600082821015614a8f57614a8f614adb565b500390565b60005b83811015614aaf578181015183820152602001614a97565b83811115610e165750506000910152565b6000600019821415614ad457614ad4614adb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114611bae57600080fd5b8015158114611bae57600080fd5b61ffff81168114611bae57600080fd5b63ffffffff81168114611bae57600080fdfea2646970667358221220f2e0bfce947c9c7524f4284139376adef4408696b83082d0c9db7b1b5c43cd7564736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000007f601c53cb2209b8e204989b01bf2f87a963b6b2000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _admin (address): 0x7F601C53cb2209b8E204989B01Bf2f87A963b6b2
Arg [1] : _dispatcher (address): 0x196413C347Ec43aEa4719a83Ec14DB7B42dc832D
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000007f601c53cb2209b8e204989b01bf2f87a963b6b2
Arg [1] : 000000000000000000000000196413c347ec43aea4719a83ec14db7b42dc832d
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.