Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
MapleLoan
Compiler Version
v0.8.7+commit.e28d00a7
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.7; import { IERC20 } from "../modules/erc20/contracts/interfaces/IERC20.sol"; import { ERC20Helper } from "../modules/erc20-helper/src/ERC20Helper.sol"; import { IMapleProxyFactory } from "../modules/maple-proxy-factory/contracts/interfaces/IMapleProxyFactory.sol"; import { MapleProxiedInternals } from "../modules/maple-proxy-factory/contracts/MapleProxiedInternals.sol"; import { IMapleLoan } from "./interfaces/IMapleLoan.sol"; import { IMapleLoanFeeManager } from "./interfaces/IMapleLoanFeeManager.sol"; import { IMapleGlobalsLike, ILenderLike, IMapleProxyFactoryLike } from "./interfaces/Interfaces.sol"; import { MapleLoanStorage } from "./MapleLoanStorage.sol"; /* ███╗ ███╗ █████╗ ██████╗ ██╗ ███████╗ ██╗ ██████╗ █████╗ ███╗ ██╗ ██╗ ██╗██╗ ██╗ ████╗ ████║██╔══██╗██╔══██╗██║ ██╔════╝ ██║ ██╔═══██╗██╔══██╗████╗ ██║ ██║ ██║██║ ██║ ██╔████╔██║███████║██████╔╝██║ █████╗ ██║ ██║ ██║███████║██╔██╗ ██║ ██║ ██║███████║ ██║╚██╔╝██║██╔══██║██╔═══╝ ██║ ██╔══╝ ██║ ██║ ██║██╔══██║██║╚██╗██║ ╚██╗ ██╔╝╚════██║ ██║ ╚═╝ ██║██║ ██║██║ ███████╗███████╗ ███████╗╚██████╔╝██║ ██║██║ ╚████║ ╚████╔╝ ██║ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚══════╝╚══════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═══╝ ╚═╝ */ /// @title MapleLoan implements a primitive loan with additional functionality, and is intended to be proxied. contract MapleLoan is IMapleLoan, MapleProxiedInternals, MapleLoanStorage { uint256 private constant SCALED_ONE = uint256(10 ** 18); modifier limitDrawableUse() { if (msg.sender == _borrower) { _; return; } uint256 drawableFundsBeforePayment = _drawableFunds; _; // Either the caller is the borrower or `_drawableFunds` has not decreased. require(_drawableFunds >= drawableFundsBeforePayment, "ML:CANNOT_USE_DRAWABLE"); } // NOTE: The following functions already check for paused state in the poolManager/loanManager, therefore no need to check here. // * acceptNewTerms // * fundLoan // * impairLoan // * removeLoanImpairment // * repossess // * setPendingLender -> Not implemented modifier whenProtocolNotPaused() { require(!IMapleGlobalsLike(globals()).protocolPaused(), "L:PROTOCOL_PAUSED"); _; } /*******************************************************************************************************************************/ /*** Administrative Functions ***/ /*******************************************************************************************************************************/ function migrate(address migrator_, bytes calldata arguments_) external override { require(msg.sender == _factory(), "ML:M:NOT_FACTORY"); require(_migrate(migrator_, arguments_), "ML:M:FAILED"); } function setImplementation(address newImplementation_) external override { require(msg.sender == _factory(), "ML:SI:NOT_FACTORY"); require(_setImplementation(newImplementation_), "ML:SI:FAILED"); } function upgrade(uint256 toVersion_, bytes calldata arguments_) external override whenProtocolNotPaused { require(msg.sender == IMapleGlobalsLike(globals()).securityAdmin(), "ML:U:NOT_SECURITY_ADMIN"); emit Upgraded(toVersion_, arguments_); IMapleProxyFactory(_factory()).upgradeInstance(toVersion_, arguments_); } /******************************************************************************************************************************/ /*** Borrow Functions ***/ /******************************************************************************************************************************/ function acceptBorrower() external override whenProtocolNotPaused { require(msg.sender == _pendingBorrower, "ML:AB:NOT_PENDING_BORROWER"); _pendingBorrower = address(0); emit BorrowerAccepted(_borrower = msg.sender); } function closeLoan(uint256 amount_) external override limitDrawableUse whenProtocolNotPaused returns (uint256 principal_, uint256 interest_, uint256 fees_) { // The amount specified is an optional amount to be transferred from the caller, as a convenience for EOAs. // NOTE: FUNDS SHOULD NOT BE TRANSFERRED TO THIS CONTRACT NON-ATOMICALLY. IF THEY ARE, THE BALANCE MAY BE STOLEN USING `skim`. require(amount_ == uint256(0) || ERC20Helper.transferFrom(_fundsAsset, msg.sender, address(this), amount_), "ML:CL:TRANSFER_FROM_FAILED"); uint256 paymentDueDate_ = _nextPaymentDueDate; require(block.timestamp <= paymentDueDate_, "ML:CL:PAYMENT_IS_LATE"); _handleImpairment(); ( principal_, interest_, ) = getClosingPaymentBreakdown(); _refinanceInterest = uint256(0); uint256 principalAndInterest = principal_ + interest_; // The drawable funds are increased by the extra funds in the contract, minus the total needed for payment. // NOTE: This line will revert if not enough funds were added for the full payment amount. _drawableFunds = (_drawableFunds + getUnaccountedAmount(_fundsAsset)) - principalAndInterest; fees_ = _handleServiceFeePayment(_paymentsRemaining); _clearLoanAccounting(); emit LoanClosed(principal_, interest_, fees_); require(ERC20Helper.transfer(_fundsAsset, _lender, principalAndInterest), "ML:MP:TRANSFER_FAILED"); ILenderLike(_lender).claim(principal_, interest_, paymentDueDate_, 0); emit FundsClaimed(principalAndInterest, _lender); } function drawdownFunds(uint256 amount_, address destination_) external override whenProtocolNotPaused returns (uint256 collateralPosted_) { require(msg.sender == _borrower, "ML:DF:NOT_BORROWER"); emit FundsDrawnDown(amount_, destination_); // Post additional collateral required to facilitate this drawdown, if needed. uint256 additionalCollateralRequired = getAdditionalCollateralRequiredFor(amount_); if (additionalCollateralRequired > uint256(0)) { // Determine collateral currently unaccounted for. uint256 unaccountedCollateral = getUnaccountedAmount(_collateralAsset); // Post required collateral, specifying then amount lacking as the optional amount to be transferred from. collateralPosted_ = postCollateral( additionalCollateralRequired > unaccountedCollateral ? additionalCollateralRequired - unaccountedCollateral : uint256(0) ); } _drawableFunds -= amount_; require(ERC20Helper.transfer(_fundsAsset, destination_, amount_), "ML:DF:TRANSFER_FAILED"); require(_isCollateralMaintained(), "ML:DF:INSUFFICIENT_COLLATERAL"); } function makePayment(uint256 amount_) external override limitDrawableUse whenProtocolNotPaused returns (uint256 principal_, uint256 interest_, uint256 fees_) { // The amount specified is an optional amount to be transfer from the caller, as a convenience for EOAs. // NOTE: FUNDS SHOULD NOT BE TRANSFERRED TO THIS CONTRACT NON-ATOMICALLY. IF THEY ARE, THE BALANCE MAY BE STOLEN USING `skim`. require(amount_ == uint256(0) || ERC20Helper.transferFrom(_fundsAsset, msg.sender, address(this), amount_), "ML:MP:TRANSFER_FROM_FAILED"); _handleImpairment(); ( principal_, interest_, ) = getNextPaymentBreakdown(); _refinanceInterest = uint256(0); uint256 principalAndInterest = principal_ + interest_; // The drawable funds are increased by the extra funds in the contract, minus the total needed for payment. // NOTE: This line will revert if not enough funds were added for the full payment amount. _drawableFunds = (_drawableFunds + getUnaccountedAmount(_fundsAsset)) - principalAndInterest; fees_ = _handleServiceFeePayment(1); uint256 paymentsRemaining_ = _paymentsRemaining; uint256 previousPaymentDueDate_ = _nextPaymentDueDate; uint256 nextPaymentDueDate_; if (paymentsRemaining_ == uint256(1)) { _clearLoanAccounting(); // Assumes `getNextPaymentBreakdown` returns a `principal_` that is `_principal`. } else { _nextPaymentDueDate = nextPaymentDueDate_ = previousPaymentDueDate_ + _paymentInterval; _principal -= principal_; _paymentsRemaining = paymentsRemaining_ - uint256(1); } emit PaymentMade(principal_, interest_, fees_); require(ERC20Helper.transfer(_fundsAsset, _lender, principalAndInterest), "ML:MP:TRANSFER_FAILED"); ILenderLike(_lender).claim(principal_, interest_, previousPaymentDueDate_, nextPaymentDueDate_); emit FundsClaimed(principalAndInterest, _lender); } function postCollateral(uint256 amount_) public override whenProtocolNotPaused returns (uint256 collateralPosted_) { // The amount specified is an optional amount to be transfer from the caller, as a convenience for EOAs. // NOTE: FUNDS SHOULD NOT BE TRANSFERRED TO THIS CONTRACT NON-ATOMICALLY. IF THEY ARE, THE BALANCE MAY BE STOLEN USING `skim`. require( amount_ == uint256(0) || ERC20Helper.transferFrom(_collateralAsset, msg.sender, address(this), amount_), "ML:PC:TRANSFER_FROM_FAILED" ); _collateral += (collateralPosted_ = getUnaccountedAmount(_collateralAsset)); emit CollateralPosted(collateralPosted_); } function proposeNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_) external override whenProtocolNotPaused returns (bytes32 refinanceCommitment_) { require(msg.sender == _borrower, "ML:PNT:NOT_BORROWER"); require(deadline_ >= block.timestamp, "ML:PNT:INVALID_DEADLINE"); emit NewTermsProposed( refinanceCommitment_ = _refinanceCommitment = calls_.length > uint256(0) ? _getRefinanceCommitment(refinancer_, deadline_, calls_) : bytes32(0), refinancer_, deadline_, calls_ ); } function removeCollateral(uint256 amount_, address destination_) external override whenProtocolNotPaused { require(msg.sender == _borrower, "ML:RC:NOT_BORROWER"); emit CollateralRemoved(amount_, destination_); _collateral -= amount_; require(ERC20Helper.transfer(_collateralAsset, destination_, amount_), "ML:RC:TRANSFER_FAILED"); require(_isCollateralMaintained(), "ML:RC:INSUFFICIENT_COLLATERAL"); } function returnFunds(uint256 amount_) external override whenProtocolNotPaused returns (uint256 fundsReturned_) { // The amount specified is an optional amount to be transfer from the caller, as a convenience for EOAs. // NOTE: FUNDS SHOULD NOT BE TRANSFERRED TO THIS CONTRACT NON-ATOMICALLY. IF THEY ARE, THE BALANCE MAY BE STOLEN USING `skim`. require(amount_ == uint256(0) || ERC20Helper.transferFrom(_fundsAsset, msg.sender, address(this), amount_), "ML:RF:TRANSFER_FROM_FAILED"); _drawableFunds += (fundsReturned_ = getUnaccountedAmount(_fundsAsset)); emit FundsReturned(fundsReturned_); } function setPendingBorrower(address pendingBorrower_) external override whenProtocolNotPaused { require(msg.sender == _borrower, "ML:SPB:NOT_BORROWER"); require(IMapleGlobalsLike(globals()).isBorrower(pendingBorrower_), "ML:SPB:INVALID_BORROWER"); emit PendingBorrowerSet(_pendingBorrower = pendingBorrower_); } /******************************************************************************************************************************/ /*** Lend Functions ***/ /******************************************************************************************************************************/ function acceptLender() external override whenProtocolNotPaused { require(msg.sender == _pendingLender, "ML:AL:NOT_PENDING_LENDER"); _pendingLender = address(0); emit LenderAccepted(_lender = msg.sender); } function acceptNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_) external override returns (bytes32 refinanceCommitment_) { require(msg.sender == _lender, "ML:ANT:NOT_LENDER"); // NOTE: A zero refinancer address and/or empty calls array will never (probabilistically) match a refinance commitment in storage. require( _refinanceCommitment == (refinanceCommitment_ = _getRefinanceCommitment(refinancer_, deadline_, calls_)), "ML:ANT:COMMITMENT_MISMATCH" ); require(refinancer_.code.length != uint256(0), "ML:ANT:INVALID_REFINANCER"); require(block.timestamp <= deadline_, "ML:ANT:EXPIRED_COMMITMENT"); uint256 paymentInterval_ = _paymentInterval; uint256 nextPaymentDueDate_ = _nextPaymentDueDate; uint256 previousPrincipalRequested = _principalRequested; uint256 timeSinceLastDueDate_ = block.timestamp + paymentInterval_ < nextPaymentDueDate_ ? 0 : block.timestamp - (nextPaymentDueDate_ - paymentInterval_); // Not ideal for checks-effects-interactions, but the feeManager is a trusted contract and it's needed to save the fee before refinance. IMapleLoanFeeManager feeManager_ = IMapleLoanFeeManager(_feeManager); feeManager_.updateRefinanceServiceFees(previousPrincipalRequested, timeSinceLastDueDate_); // Get the amount of interest owed since the last payment due date, as well as the time since the last due date uint256 proRataInterest = getRefinanceInterest(block.timestamp); // In case there is still a refinance interest, just increment it instead of setting it. _refinanceInterest += proRataInterest; // Clear refinance commitment to prevent implications of re-acceptance of another call to `_acceptNewTerms`. _refinanceCommitment = bytes32(0); for (uint256 i; i < calls_.length;) { ( bool success, ) = refinancer_.delegatecall(calls_[i]); require(success, "ML:ANT:FAILED"); unchecked { ++i; } } emit NewTermsAccepted(refinanceCommitment_, refinancer_, deadline_, calls_); address fundsAsset_ = _fundsAsset; uint256 principalRequested_ = _principalRequested; paymentInterval_ = _paymentInterval; // Increment the due date to be one full payment interval from now, to restart the payment schedule with new terms. // NOTE: `_paymentInterval` here is possibly newly set via the above delegate calls, so cache it. _nextPaymentDueDate = block.timestamp + paymentInterval_; _handleImpairment(); // Update Platform Fees and pay originations. feeManager_.updatePlatformServiceFee(principalRequested_, paymentInterval_); _drawableFunds -= feeManager_.payOriginationFees(fundsAsset_, principalRequested_); // Ensure that collateral is maintained after changes made. require(_isCollateralMaintained(), "ML:ANT:INSUFFICIENT_COLLATERAL"); require(getUnaccountedAmount(fundsAsset_) == uint256(0), "ML:ANT:UNEXPECTED_FUNDS"); } function fundLoan(address lender_) external override returns (uint256 fundsLent_) { require((_lender = lender_) != address(0), "ML:FL:INVALID_LENDER"); address loanManagerFactory_ = ILenderLike(lender_).factory(); require(IMapleGlobalsLike(globals()).isFactory("LOAN_MANAGER", loanManagerFactory_), "ML:FL:INVALID_FACTORY"); require(IMapleProxyFactoryLike(loanManagerFactory_).isInstance(lender_), "ML:FL:INVALID_INSTANCE"); // Can only fund loan if there are payments remaining (as defined by the initialization) and no payment is due yet (as set by a funding). require((_nextPaymentDueDate == uint256(0)) && (_paymentsRemaining != uint256(0)), "ML:FL:LOAN_ACTIVE"); address fundsAsset_ = _fundsAsset; uint256 paymentInterval_ = _paymentInterval; uint256 principalRequested_ = _principalRequested; require(ERC20Helper.approve(fundsAsset_, _feeManager, type(uint256).max), "ML:FL:APPROVE_FAIL"); // Saves the platform service fee rate for future payments. IMapleLoanFeeManager(_feeManager).updatePlatformServiceFee(principalRequested_, paymentInterval_); uint256 originationFees_ = IMapleLoanFeeManager(_feeManager).payOriginationFees(fundsAsset_, principalRequested_); _drawableFunds = principalRequested_ - originationFees_; require(getUnaccountedAmount(fundsAsset_) == uint256(0), "ML:FL:UNEXPECTED_FUNDS"); emit Funded( lender_, fundsLent_ = _principal = principalRequested_, _nextPaymentDueDate = block.timestamp + paymentInterval_ ); } function removeLoanImpairment() external override { uint256 originalNextPaymentDueDate_ = _originalNextPaymentDueDate; require(msg.sender == _lender, "ML:RLI:NOT_LENDER"); require(originalNextPaymentDueDate_ != 0, "ML:RLI:NOT_IMPAIRED"); require(block.timestamp <= originalNextPaymentDueDate_, "ML:RLI:PAST_DATE"); _nextPaymentDueDate = originalNextPaymentDueDate_; delete _originalNextPaymentDueDate; emit NextPaymentDueDateRestored(originalNextPaymentDueDate_); } function repossess(address destination_) external override returns (uint256 collateralRepossessed_, uint256 fundsRepossessed_) { require(msg.sender == _lender, "ML:R:NOT_LENDER"); uint256 nextPaymentDueDate_ = _nextPaymentDueDate; require( nextPaymentDueDate_ != uint256(0) && (block.timestamp > nextPaymentDueDate_ + _gracePeriod), "ML:R:NOT_IN_DEFAULT" ); _clearLoanAccounting(); // Uniquely in `_repossess`, stop accounting for all funds so that they can be swept. _collateral = uint256(0); _drawableFunds = uint256(0); address collateralAsset_ = _collateralAsset; // Either there is no collateral to repossess, or the transfer of the collateral succeeds. require( (collateralRepossessed_ = getUnaccountedAmount(collateralAsset_)) == uint256(0) || ERC20Helper.transfer(collateralAsset_, destination_, collateralRepossessed_), "ML:R:C_TRANSFER_FAILED" ); address fundsAsset_ = _fundsAsset; // Either there are no funds to repossess, or the transfer of the funds succeeds. require( (fundsRepossessed_ = getUnaccountedAmount(fundsAsset_)) == uint256(0) || ERC20Helper.transfer(fundsAsset_, destination_, fundsRepossessed_), "ML:R:F_TRANSFER_FAILED" ); emit Repossessed(collateralRepossessed_, fundsRepossessed_, destination_); } function setPendingLender(address pendingLender_) external override { require(msg.sender == _lender, "ML:SPL:NOT_LENDER"); emit PendingLenderSet(_pendingLender = pendingLender_); } function impairLoan() external override { uint256 originalNextPaymentDueDate_ = _nextPaymentDueDate; require(msg.sender == _lender, "ML:IL:NOT_LENDER"); // If the loan is late, do not change the payment due date. uint256 newPaymentDueDate_ = block.timestamp > originalNextPaymentDueDate_ ? originalNextPaymentDueDate_ : block.timestamp; emit LoanImpaired(newPaymentDueDate_); _nextPaymentDueDate = newPaymentDueDate_; _originalNextPaymentDueDate = originalNextPaymentDueDate_; // Store the existing payment due date to enable reversion. } /******************************************************************************************************************************/ /*** Miscellaneous Functions ***/ /******************************************************************************************************************************/ function rejectNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_) external override whenProtocolNotPaused returns (bytes32 refinanceCommitment_) { require((msg.sender == _borrower) || (msg.sender == _lender), "ML:RNT:NO_AUTH"); require( _refinanceCommitment == (refinanceCommitment_ = _getRefinanceCommitment(refinancer_, deadline_, calls_)), "ML:RNT:COMMITMENT_MISMATCH" ); _refinanceCommitment = bytes32(0); emit NewTermsRejected(refinanceCommitment_, refinancer_, deadline_, calls_); } function skim(address token_, address destination_) external override whenProtocolNotPaused returns (uint256 skimmed_) { emit Skimmed(token_, skimmed_ = getUnaccountedAmount(token_), destination_); require(ERC20Helper.transfer(token_, destination_, skimmed_), "ML:S:TRANSFER_FAILED"); } /******************************************************************************************************************************/ /*** View Functions ***/ /******************************************************************************************************************************/ function getAdditionalCollateralRequiredFor(uint256 drawdown_) public view override returns (uint256 collateral_) { // Determine the collateral needed in the contract for a reduced drawable funds amount. uint256 collateralNeeded = _getCollateralRequiredFor(_principal, _drawableFunds - drawdown_, _principalRequested, _collateralRequired); uint256 currentCollateral = _collateral; return collateralNeeded > currentCollateral ? collateralNeeded - currentCollateral : uint256(0); } function getClosingPaymentBreakdown() public view override returns (uint256 principal_, uint256 interest_, uint256 fees_) { ( uint256 delegateServiceFee_, uint256 delegateRefinanceFee_, uint256 platformServiceFee_, uint256 platformRefinanceFee_ ) = IMapleLoanFeeManager(_feeManager).getServiceFeeBreakdown(address(this), _paymentsRemaining); fees_ = delegateServiceFee_ + platformServiceFee_ + delegateRefinanceFee_ + platformRefinanceFee_; // Compute interest and include any uncaptured interest from refinance. interest_ = (((principal_ = _principal) * _closingRate) / SCALED_ONE) + _refinanceInterest; } function getNextPaymentDetailedBreakdown() public view override returns ( uint256 principal_, uint256[3] memory interest_, uint256[2] memory fees_ ) { ( principal_, interest_, fees_ ) = _getPaymentBreakdown( block.timestamp, _nextPaymentDueDate, _paymentInterval, _principal, _endingPrincipal, _paymentsRemaining, _interestRate, _lateFeeRate, _lateInterestPremium ); } function getNextPaymentBreakdown() public view override returns (uint256 principal_, uint256 interest_, uint256 fees_) { uint256[3] memory interestArray_; uint256[2] memory feesArray_; ( principal_, interestArray_, feesArray_ ) = _getPaymentBreakdown( block.timestamp, _nextPaymentDueDate, _paymentInterval, _principal, _endingPrincipal, _paymentsRemaining, _interestRate, _lateFeeRate, _lateInterestPremium ); interest_ = interestArray_[0] + interestArray_[1] + interestArray_[2]; fees_ = feesArray_[0] + feesArray_[1]; } function getRefinanceInterest(uint256 timestamp_) public view override returns (uint256 proRataInterest_) { proRataInterest_ = _getRefinanceInterest( timestamp_, _paymentInterval, _principal, _endingPrincipal, _interestRate, _paymentsRemaining, _nextPaymentDueDate, _lateFeeRate, _lateInterestPremium ); } function getUnaccountedAmount(address asset_) public view override returns (uint256 unaccountedAmount_) { return IERC20(asset_).balanceOf(address(this)) - (asset_ == _collateralAsset ? _collateral : uint256(0)) // `_collateral` is `_collateralAsset` accounted for. - (asset_ == _fundsAsset ? _drawableFunds : uint256(0)); // `_drawableFunds` is `_fundsAsset` accounted for. } /******************************************************************************************************************************/ /*** State View Functions ***/ /******************************************************************************************************************************/ function borrower() external view override returns (address borrower_) { return _borrower; } function closingRate() external view override returns (uint256 closingRate_) { return _closingRate; } function collateral() external view override returns (uint256 collateral_) { return _collateral; } function collateralAsset() external view override returns (address collateralAsset_) { return _collateralAsset; } function collateralRequired() external view override returns (uint256 collateralRequired_) { return _collateralRequired; } function drawableFunds() external view override returns (uint256 drawableFunds_) { return _drawableFunds; } function endingPrincipal() external view override returns (uint256 endingPrincipal_) { return _endingPrincipal; } function excessCollateral() external view override returns (uint256 excessCollateral_) { uint256 collateralNeeded = _getCollateralRequiredFor(_principal, _drawableFunds, _principalRequested, _collateralRequired); uint256 currentCollateral = _collateral; return currentCollateral > collateralNeeded ? currentCollateral - collateralNeeded : uint256(0); } function factory() external view override returns (address factory_) { return _factory(); } function feeManager() external view override returns (address feeManager_) { return _feeManager; } function fundsAsset() external view override returns (address fundsAsset_) { return _fundsAsset; } function globals() public view override returns (address globals_) { globals_ = IMapleProxyFactoryLike(_factory()).mapleGlobals(); } function governor() public view override returns (address governor_) { governor_ = IMapleGlobalsLike(globals()).governor(); } function gracePeriod() external view override returns (uint256 gracePeriod_) { return _gracePeriod; } function implementation() external view override returns (address implementation_) { return _implementation(); } function interestRate() external view override returns (uint256 interestRate_) { return _interestRate; } function lateFeeRate() external view override returns (uint256 lateFeeRate_) { return _lateFeeRate; } function lateInterestPremium() external view override returns (uint256 lateInterestPremium_) { return _lateInterestPremium; } function lender() external view override returns (address lender_) { return _lender; } function nextPaymentDueDate() external view override returns (uint256 nextPaymentDueDate_) { return _nextPaymentDueDate; } function originalNextPaymentDueDate() external view override returns (uint256 originalNextPaymentDueDate_) { return _originalNextPaymentDueDate; } function paymentInterval() external view override returns (uint256 paymentInterval_) { return _paymentInterval; } function paymentsRemaining() external view override returns (uint256 paymentsRemaining_) { return _paymentsRemaining; } function pendingBorrower() external view override returns (address pendingBorrower_) { return _pendingBorrower; } function pendingLender() external view override returns (address pendingLender_) { return _pendingLender; } function principal() external view override returns (uint256 principal_) { return _principal; } function principalRequested() external view override returns (uint256 principalRequested_) { return _principalRequested; } function refinanceCommitment() external view override returns (bytes32 refinanceCommitment_) { return _refinanceCommitment; } function refinanceInterest() external view override returns (uint256 refinanceInterest_) { return _refinanceInterest; } function isImpaired() public view override returns (bool isImpaired_) { return _originalNextPaymentDueDate != uint256(0); } /******************************************************************************************************************************/ /*** Internal General Functions ***/ /******************************************************************************************************************************/ /// @dev Clears all state variables to end a loan, but keep borrower and lender withdrawal functionality intact. function _clearLoanAccounting() internal { _gracePeriod = uint256(0); _paymentInterval = uint256(0); _interestRate = uint256(0); _closingRate = uint256(0); _lateFeeRate = uint256(0); _lateInterestPremium = uint256(0); _endingPrincipal = uint256(0); _nextPaymentDueDate = uint256(0); _paymentsRemaining = uint256(0); _principal = uint256(0); _originalNextPaymentDueDate = uint256(0); } /******************************************************************************************************************************/ /*** Internal View Functions ***/ /******************************************************************************************************************************/ /// @dev Returns whether the amount of collateral posted is commensurate with the amount of drawn down (outstanding) principal. function _isCollateralMaintained() internal view returns (bool isMaintained_) { return _collateral >= _getCollateralRequiredFor(_principal, _drawableFunds, _principalRequested, _collateralRequired); } /******************************************************************************************************************************/ /*** Internal Pure Functions ***/ /******************************************************************************************************************************/ /// @dev Returns the total collateral to be posted for some drawn down (outstanding) principal and overall collateral ratio requirement. function _getCollateralRequiredFor( uint256 principal_, uint256 drawableFunds_, uint256 principalRequested_, uint256 collateralRequired_ ) internal pure returns (uint256 collateral_) { // Where (collateral / outstandingPrincipal) should be greater or equal to (collateralRequired / principalRequested). // NOTE: principalRequested_ cannot be 0, which is reasonable, since it means this was never a loan. return principal_ <= drawableFunds_ ? uint256(0) : (collateralRequired_ * (principal_ - drawableFunds_) + principalRequested_ - 1) / principalRequested_; } /// @dev Returns principal and interest portions of a payment instalment, given generic, stateless loan parameters. function _getInstallment(uint256 principal_, uint256 endingPrincipal_, uint256 interestRate_, uint256 paymentInterval_, uint256 totalPayments_) internal pure returns (uint256 principalAmount_, uint256 interestAmount_) { /*************************************************************************************************\ * | * * A = installment amount | / \ / R \ * * P = principal remaining | | / \ | | ----------------------- | * * R = interest rate | A = | | P * ( 1 + R ) ^ N | - E | * | / \ | * * N = payments remaining | | \ / | | | ( 1 + R ) ^ N | - 1 | * * E = ending principal target | \ / \ \ / / * * | * * |---------------------------------------------------------------- * * * * - Where R is `periodicRate` * * - Where (1 + R) ^ N is `raisedRate` * * - Both of these rates are scaled by 1e18 (e.g., 12% => 0.12 * 10 ** 18) * \*************************************************************************************************/ uint256 periodicRate = _getPeriodicInterestRate(interestRate_, paymentInterval_); uint256 raisedRate = _scaledExponent(SCALED_ONE + periodicRate, totalPayments_, SCALED_ONE); // NOTE: If a lack of precision in `_scaledExponent` results in a `raisedRate` smaller than one, assume it to be one and simplify the equation. if (raisedRate <= SCALED_ONE) return ((principal_ - endingPrincipal_) / totalPayments_, uint256(0)); uint256 total = ((((principal_ * raisedRate) / SCALED_ONE) - endingPrincipal_) * periodicRate) / (raisedRate - SCALED_ONE); interestAmount_ = _getInterest(principal_, interestRate_, paymentInterval_); principalAmount_ = total >= interestAmount_ ? total - interestAmount_ : uint256(0); } /// @dev Returns an amount by applying an annualized and scaled interest rate, to a principal, over an interval of time. function _getInterest(uint256 principal_, uint256 interestRate_, uint256 interval_) internal pure returns (uint256 interest_) { return (principal_ * _getPeriodicInterestRate(interestRate_, interval_)) / SCALED_ONE; } /// @dev Returns total principal and interest portion of a number of payments, given generic, stateless loan parameters and loan state. function _getPaymentBreakdown( uint256 currentTime_, uint256 nextPaymentDueDate_, uint256 paymentInterval_, uint256 principal_, uint256 endingPrincipal_, uint256 paymentsRemaining_, uint256 interestRate_, uint256 lateFeeRate_, uint256 lateInterestPremium_ ) internal view returns ( uint256 principalAmount_, uint256[3] memory interest_, uint256[2] memory fees_ ) { ( principalAmount_, interest_[0] ) = _getInstallment( principal_, endingPrincipal_, interestRate_, paymentInterval_, paymentsRemaining_ ); principalAmount_ = paymentsRemaining_ == uint256(1) ? principal_ : principalAmount_; interest_[1] = _getLateInterest( currentTime_, principal_, interestRate_, nextPaymentDueDate_, lateFeeRate_, lateInterestPremium_ ); interest_[2] = _refinanceInterest; ( uint256 delegateServiceFee_, uint256 delegateRefinanceFee_, uint256 platformServiceFee_, uint256 platformRefinanceFee_ ) = IMapleLoanFeeManager(_feeManager).getServiceFeeBreakdown(address(this), 1); fees_[0] = delegateServiceFee_ + delegateRefinanceFee_; fees_[1] = platformServiceFee_ + platformRefinanceFee_; } function _getRefinanceInterest( uint256 currentTime_, uint256 paymentInterval_, uint256 principal_, uint256 endingPrincipal_, uint256 interestRate_, uint256 paymentsRemaining_, uint256 nextPaymentDueDate_, uint256 lateFeeRate_, uint256 lateInterestPremium_ ) internal pure returns (uint256 refinanceInterest_) { // If the user has made an early payment, there is no refinance interest owed. if (currentTime_ + paymentInterval_ < nextPaymentDueDate_) return 0; uint256 timeSinceLastPaymentDueDate_ = currentTime_ - (nextPaymentDueDate_ - paymentInterval_); ( , refinanceInterest_ ) = _getInstallment( principal_, endingPrincipal_, interestRate_, timeSinceLastPaymentDueDate_, paymentsRemaining_ ); refinanceInterest_ += _getLateInterest( currentTime_, principal_, interestRate_, nextPaymentDueDate_, lateFeeRate_, lateInterestPremium_ ); } function _getLateInterest( uint256 currentTime_, uint256 principal_, uint256 interestRate_, uint256 nextPaymentDueDate_, uint256 lateFeeRate_, uint256 lateInterestPremium_ ) internal pure returns (uint256 lateInterest_) { if (currentTime_ <= nextPaymentDueDate_) return 0; // Calculates the number of full days late in seconds (will always be multiples of 86,400). // Rounds up and is inclusive so that if a payment is 1s late or 24h0m0s late it is 1 full day late. // 24h0m1s late would be two full days late. // ((86400n - 0n + (86400n - 1n)) / 86400n) * 86400n = 86400n // ((86401n - 0n + (86400n - 1n)) / 86400n) * 86400n = 172800n uint256 fullDaysLate = ((currentTime_ - nextPaymentDueDate_ + (1 days - 1)) / 1 days) * 1 days; lateInterest_ += _getInterest(principal_, interestRate_ + lateInterestPremium_, fullDaysLate); lateInterest_ += (lateFeeRate_ * principal_) / SCALED_ONE; } /// @dev Returns the interest rate over an interval, given an annualized interest rate. function _getPeriodicInterestRate(uint256 interestRate_, uint256 interval_) internal pure returns (uint256 periodicInterestRate_) { return (interestRate_ * interval_) / uint256(365 days); } /// @dev Returns refinance commitment given refinance parameters. function _getRefinanceCommitment(address refinancer_, uint256 deadline_, bytes[] calldata calls_) internal pure returns (bytes32 refinanceCommitment_) { return keccak256(abi.encode(refinancer_, deadline_, calls_)); } function _handleServiceFeePayment(uint256 numberOfPayments_) internal returns (uint256 fees_) { uint256 balanceBeforeServiceFees_ = IERC20(_fundsAsset).balanceOf(address(this)); IMapleLoanFeeManager(_feeManager).payServiceFees(_fundsAsset, numberOfPayments_); uint256 balanceAfterServiceFees_ = IERC20(_fundsAsset).balanceOf(address(this)); if (balanceBeforeServiceFees_ > balanceAfterServiceFees_) { _drawableFunds -= (fees_ = balanceBeforeServiceFees_ - balanceAfterServiceFees_); } else { _drawableFunds += balanceAfterServiceFees_ - balanceBeforeServiceFees_; } } function _handleImpairment() internal { if (!isImpaired()) return; _originalNextPaymentDueDate = uint256(0); } /** * @dev Returns exponentiation of a scaled base value. * * Walk through example: * LINE | base_ | exponent_ | one_ | result_ * | 3_00 | 18 | 1_00 | 0_00 * A | 3_00 | 18 | 1_00 | 1_00 * B | 3_00 | 9 | 1_00 | 1_00 * C | 9_00 | 9 | 1_00 | 1_00 * D | 9_00 | 9 | 1_00 | 9_00 * B | 9_00 | 4 | 1_00 | 9_00 * C | 81_00 | 4 | 1_00 | 9_00 * B | 81_00 | 2 | 1_00 | 9_00 * C | 6_561_00 | 2 | 1_00 | 9_00 * B | 6_561_00 | 1 | 1_00 | 9_00 * C | 43_046_721_00 | 1 | 1_00 | 9_00 * D | 43_046_721_00 | 1 | 1_00 | 387_420_489_00 * B | 43_046_721_00 | 0 | 1_00 | 387_420_489_00 * * Another implementation of this algorithm can be found in Dapphub's DSMath contract: * https://github.com/dapphub/ds-math/blob/ce67c0fa9f8262ecd3d76b9e4c026cda6045e96c/src/math.sol#L77 */ function _scaledExponent(uint256 base_, uint256 exponent_, uint256 one_) internal pure returns (uint256 result_) { // If exponent_ is odd, set result_ to base_, else set to one_. result_ = exponent_ & uint256(1) != uint256(0) ? base_ : one_; // A // Divide exponent_ by 2 (overwriting itself) and proceed if not zero. while ((exponent_ >>= uint256(1)) != uint256(0)) { // B base_ = (base_ * base_) / one_; // C // If exponent_ is even, go back to top. if (exponent_ & uint256(1) == uint256(0)) continue; // If exponent_ is odd, multiply result_ is multiplied by base_. result_ = (result_ * base_) / one_; // D } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.7; /// @title MapleLoanStorage defines the storage layout of MapleLoan. abstract contract MapleLoanStorage { // Roles address internal _borrower; // The address of the borrower. address internal _lender; // The address of the lender. address internal _pendingBorrower; // The address of the pendingBorrower, the only address that can accept the borrower role. address internal _pendingLender; // The address of the pendingLender, the only address that can accept the lender role. // Assets address internal _collateralAsset; // The address of the asset used as collateral. address internal _fundsAsset; // The address of the asset used as funds. // Loan Term Parameters uint256 internal _gracePeriod; // The number of seconds a payment can be late. uint256 internal _paymentInterval; // The number of seconds between payments. // Rates uint256 internal _interestRate; // The annualized interest rate of the loan. uint256 internal _closingRate; // The fee rate (applied to principal) to close the loan. uint256 internal _lateFeeRate; // The fee rate for late payments. uint256 internal _lateInterestPremium; // The amount to increase the interest rate by for late payments. // Requested Amounts uint256 internal _collateralRequired; // The collateral the borrower is expected to put up to draw down all _principalRequested. uint256 internal _principalRequested; // The funds the borrowers wants to borrow. uint256 internal _endingPrincipal; // The principal to remain at end of loan. // State uint256 internal _drawableFunds; // The amount of funds that can be drawn down. uint256 internal __deprecated_claimableFunds; // Deprecated storage slot for `claimableFunds`. uint256 internal _collateral; // The amount of collateral, in collateral asset, that is currently posted. uint256 internal _nextPaymentDueDate; // The timestamp of due date of next payment. uint256 internal _paymentsRemaining; // The number of payments remaining. uint256 internal _principal; // The amount of principal yet to be paid down. // Refinance bytes32 internal _refinanceCommitment; // Keccak-256 hash of the parameters of proposed terms of a refinance: `refinancer_`, `deadline_`, and `calls_`. uint256 internal _refinanceInterest; // Amount of accrued interest between the last payment on a loan and the time the refinance takes effect. // Establishment fees uint256 internal __deprecated_delegateFee; // Deprecated storage slot for `delegateFee`. uint256 internal __deprecated_treasuryFee; // Deprecated storage slot for `treasuryFee`. // Pool V2 dependencies address internal _feeManager; // Address responsible for calculating and handling fees // Triggered defaults uint256 internal _originalNextPaymentDueDate; // Stores the original `nextPaymentDueDate` in order to allow triggered defaults to be reverted. }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.7; import { IMapleProxied } from "../../modules/maple-proxy-factory/contracts/interfaces/IMapleProxied.sol"; import { IMapleLoanEvents } from "./IMapleLoanEvents.sol"; /// @title MapleLoan implements a primitive loan with additional functionality, and is intended to be proxied. interface IMapleLoan is IMapleProxied, IMapleLoanEvents { /******************************************************************************************************************************/ /*** State Variables ***/ /******************************************************************************************************************************/ /** * @dev The borrower of the loan, responsible for repayments. */ function borrower() external view returns (address borrower_); /** * @dev The fee rate (applied to principal) to close the loan. * This value should be configured so that it is less expensive to close a loan with more than one payment remaining, but * more expensive to close it if on the last payment. */ function closingRate() external view returns (uint256 closingRate_); /** * @dev The amount of collateral posted against outstanding (drawn down) principal. */ function collateral() external view returns (uint256 collateral_); /** * @dev The address of the asset deposited by the borrower as collateral, if needed. */ function collateralAsset() external view returns (address collateralAsset_); /** * @dev The amount of collateral required if all of the principal required is drawn down. */ function collateralRequired() external view returns (uint256 collateralRequired_); /** * @dev The amount of funds that have yet to be drawn down by the borrower. */ function drawableFunds() external view returns (uint256 drawableFunds_); /** * @dev The portion of principal to not be paid down as part of payment installments, which would need to be paid back upon final payment. * If endingPrincipal = principal, loan is interest-only. */ function endingPrincipal() external view returns (uint256 endingPrincipal_); /** * @dev The address of the contract that handles payments of fees on behalf of the loan. */ function feeManager() external view returns (address feeManager_); /** * @dev The asset deposited by the lender to fund the loan. */ function fundsAsset() external view returns (address fundsAsset_); /** * @dev The Maple globals address */ function globals() external view returns (address globals_); /** * @dev The address of the Maple Governor. */ function governor() external view returns (address governor_); /** * @dev The amount of time the borrower has, after a payment is due, to make a payment before being in default. */ function gracePeriod() external view returns (uint256 gracePeriod_); /** * @dev The annualized interest rate (APR), in units of 1e18, (i.e. 1% is 0.01e18). */ function interestRate() external view returns (uint256 interestRate_); /** * @dev The rate charged at late payments. */ function lateFeeRate() external view returns (uint256 lateFeeRate_); /** * @dev The premium over the regular interest rate applied when paying late. */ function lateInterestPremium() external view returns (uint256 lateInterestPremium_); /** * @dev The lender of the Loan. */ function lender() external view returns (address lender_); /** * @dev The timestamp due date of the next payment. */ function nextPaymentDueDate() external view returns (uint256 nextPaymentDueDate_); /** * @dev The saved original payment due date from a loan impairment. */ function originalNextPaymentDueDate() external view returns (uint256 originalNextPaymentDueDate_); /** * @dev The specified time between loan payments. */ function paymentInterval() external view returns (uint256 paymentInterval_); /** * @dev The number of payment installments remaining for the loan. */ function paymentsRemaining() external view returns (uint256 paymentsRemaining_); /** * @dev The address of the pending borrower. */ function pendingBorrower() external view returns (address pendingBorrower_); /** * @dev The address of the pending lender. */ function pendingLender() external view returns (address pendingLender_); /** * @dev The amount of principal owed (initially, the requested amount), which needs to be paid back. */ function principal() external view returns (uint256 principal_); /** * @dev The initial principal amount requested by the borrower. */ function principalRequested() external view returns (uint256 principalRequested_); /** * @dev The hash of the proposed refinance agreement. */ function refinanceCommitment() external view returns (bytes32 refinanceCommitment_); /** * @dev Amount of unpaid interest that has accrued before a refinance was accepted. */ function refinanceInterest() external view returns (uint256 refinanceInterest_); /******************************************************************************************************************************/ /*** State Changing Functions ***/ /******************************************************************************************************************************/ /** * @dev Accept the borrower role, must be called by pendingBorrower. */ function acceptBorrower() external; /** * @dev Accept the lender role, must be called by pendingLender. */ function acceptLender() external; /** * @dev Accept the proposed terms ans trigger refinance execution * @param refinancer_ The address of the refinancer contract. * @param deadline_ The deadline for accepting the new terms. * @param calls_ The encoded arguments to be passed to refinancer. * @return refinanceCommitment_ The hash of the accepted refinance agreement. */ function acceptNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_) external returns (bytes32 refinanceCommitment_); /** * @dev Repay all principal and interest and close a loan. * FUNDS SHOULD NOT BE TRANSFERRED TO THIS CONTRACT NON-ATOMICALLY. IF THEY ARE, THE BALANCE MAY BE STOLEN USING `skim`. * @param amount_ An amount to pull from the caller, if any. * @return principal_ The portion of the amount paying back principal. * @return interest_ The portion of the amount paying interest. * @return fees_ The portion of the amount paying service fees. */ function closeLoan(uint256 amount_) external returns (uint256 principal_, uint256 interest_, uint256 fees_); /** * @dev Draw down funds from the loan. * @param amount_ The amount to draw down. * @param destination_ The address to send the funds. * @return collateralPosted_ The amount of additional collateral posted, if any. */ function drawdownFunds(uint256 amount_, address destination_) external returns (uint256 collateralPosted_); /** * @dev Lend funds to the loan/borrower. * @param lender_ The address to be registered as the lender. * @return fundsLent_ The amount funded. */ function fundLoan(address lender_) external returns (uint256 fundsLent_); /** * @dev Make a payment to the loan. * FUNDS SHOULD NOT BE TRANSFERRED TO THIS CONTRACT NON-ATOMICALLY. IF THEY ARE, THE BALANCE MAY BE STOLEN USING `skim`. * @param amount_ An amount to pull from the caller, if any. * @return principal_ The portion of the amount paying back principal. * @return interest_ The portion of the amount paying interest fees. * @return fees_ The portion of the amount paying service fees. */ function makePayment(uint256 amount_) external returns (uint256 principal_, uint256 interest_, uint256 fees_); /** * @dev Post collateral to the loan. * FUNDS SHOULD NOT BE TRANSFERRED TO THIS CONTRACT NON-ATOMICALLY. IF THEY ARE, THE BALANCE MAY BE STOLEN USING `skim`. * @param amount_ An amount to pull from the caller, if any. * @return collateralPosted_ The amount posted. */ function postCollateral(uint256 amount_) external returns (uint256 collateralPosted_); /** * @dev Propose new terms for refinance. * @param refinancer_ The address of the refinancer contract. * @param deadline_ The deadline for accepting the new terms. * @param calls_ The encoded arguments to be passed to refinancer. * @return refinanceCommitment_ The hash of the proposed refinance agreement. */ function proposeNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_) external returns (bytes32 refinanceCommitment_); /** * @dev Nullify the current proposed terms. * @param refinancer_ The address of the refinancer contract. * @param deadline_ The deadline for accepting the new terms. * @param calls_ The encoded arguments to be passed to refinancer. * @return refinanceCommitment_ The hash of the rejected refinance agreement. */ function rejectNewTerms(address refinancer_, uint256 deadline_, bytes[] calldata calls_) external returns (bytes32 refinanceCommitment_); /** * @dev Remove collateral from the loan (opposite of posting collateral). * @param amount_ The amount removed. * @param destination_ The destination to send the removed collateral. */ function removeCollateral(uint256 amount_, address destination_) external; /** * @dev Remove the loan impairment by restoring the original payment due date. */ function removeLoanImpairment() external; /** * @dev Return funds to the loan (opposite of drawing down). * FUNDS SHOULD NOT BE TRANSFERRED TO THIS CONTRACT NON-ATOMICALLY. IF THEY ARE, THE BALANCE MAY BE STOLEN USING `skim`. * @param amount_ An amount to pull from the caller, if any. * @return fundsReturned_ The amount returned. */ function returnFunds(uint256 amount_) external returns (uint256 fundsReturned_); /** * @dev Repossess collateral, and any funds, for a loan in default. * @param destination_ The address where the collateral and funds asset is to be sent, if any. * @return collateralRepossessed_ The amount of collateral asset repossessed. * @return fundsRepossessed_ The amount of funds asset repossessed. */ function repossess(address destination_) external returns (uint256 collateralRepossessed_, uint256 fundsRepossessed_); /** * @dev Set the pendingBorrower to a new account. * @param pendingBorrower_ The address of the new pendingBorrower. */ function setPendingBorrower(address pendingBorrower_) external; /** * @dev Set the pendingLender to a new account. * @param pendingLender_ The address of the new pendingLender. */ function setPendingLender(address pendingLender_) external; /** * @dev Remove all token that is not accounted for by the loan (i.e. not `collateral` or `drawableFunds`). * @param token_ The address of the token contract. * @param destination_ The recipient of the token. * @return skimmed_ The amount of token removed from the loan. */ function skim(address token_, address destination_) external returns (uint256 skimmed_); /** * @dev Fast forward the next payment due date to the current time. * This enables the pool delegate to force a payment (or default). */ function impairLoan() external; /******************************************************************************************************************************/ /*** View Functions ***/ /******************************************************************************************************************************/ /** * @dev Returns the excess collateral that can be removed. * @return excessCollateral_ The excess collateral that can be removed, if any. */ function excessCollateral() external view returns (uint256 excessCollateral_); /** * @dev Get the additional collateral to be posted to drawdown some amount. * @param drawdown_ The amount desired to be drawn down. * @return additionalCollateral_ The additional collateral that must be posted, if any. */ function getAdditionalCollateralRequiredFor(uint256 drawdown_) external view returns (uint256 additionalCollateral_); /** * @dev Get the breakdown of the total payment needed to satisfy an early repayment to close the loan. * @return principal_ The portion of the total amount that will go towards principal. * @return interest_ The portion of the total amount that will go towards interest fees. * @return fees_ The portion of the total amount that will go towards fees. */ function getClosingPaymentBreakdown() external view returns (uint256 principal_, uint256 interest_, uint256 fees_); /** * @dev Get the breakdown of the total payment needed to satisfy the next payment installment. * @return principal_ The portion of the total amount that will go towards principal. * @return interest_ The portion of the total amount that will go towards interest fees. * @return fees_ The portion of the total amount that will go towards paying administrative fees. */ function getNextPaymentBreakdown() external view returns (uint256 principal_, uint256 interest_, uint256 fees_); /** * @dev Get the detailed breakdown of the total payment needed to satisfy the next payment installment. * @return principal_ The portion of the total amount that will go towards principal. * @return interest_ The portion of the total amount that will go towards interest fees. * [0] Interest from the payment interval. * [1] Late interest. * [2] Refinance interest. * @return fees_ The portion of the total amount that will go towards paying administrative fees. * [0] Delegate fees. * [1] Platform fees. */ function getNextPaymentDetailedBreakdown() external view returns (uint256 principal_, uint256[3] memory interest_, uint256[2] memory fees_); /** * @dev Get the extra interest that will be charged according to loan terms before refinance, based on a given timestamp. * @param timestamp_ The timestamp when the new terms will be accepted. * @return proRataInterest_ The interest portion to be added in the next payment. */ function getRefinanceInterest(uint256 timestamp_) external view returns (uint256 proRataInterest_); /** * @dev Get the amount on an asset that in not accounted for by the accounting variables (and thus can be skimmed). * @param asset_ The address of a asset contract. * @return unaccountedAmount_ The amount that is not accounted for. */ function getUnaccountedAmount(address asset_) external view returns (uint256 unaccountedAmount_); /** * @dev Return if the loan has been impaired. * @return isImpaired_ Is the loan impaired or not. */ function isImpaired() external view returns (bool isImpaired_); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.7; /// @title IMapleLoanEvents defines the events for a MapleLoan. interface IMapleLoanEvents { /** * @dev Borrower was accepted, and set to a new account. * @param borrower_ The address of the new borrower. */ event BorrowerAccepted(address indexed borrower_); /** * @dev Collateral was posted. * @param amount_ The amount of collateral posted. */ event CollateralPosted(uint256 amount_); /** * @dev Collateral was removed. * @param amount_ The amount of collateral removed. * @param destination_ The recipient of the collateral removed. */ event CollateralRemoved(uint256 amount_, address indexed destination_); /** * @dev The loan was funded. * @param lender_ The address of the lender. * @param amount_ The amount funded. * @param nextPaymentDueDate_ The due date of the next payment. */ event Funded(address indexed lender_, uint256 amount_, uint256 nextPaymentDueDate_); /** * @dev Funds were claimed. * @param amount_ The amount of funds claimed. * @param destination_ The recipient of the funds claimed. */ event FundsClaimed(uint256 amount_, address indexed destination_); /** * @dev Funds were drawn. * @param amount_ The amount of funds drawn. * @param destination_ The recipient of the funds drawn down. */ event FundsDrawnDown(uint256 amount_, address indexed destination_); /** * @dev Funds were returned. * @param amount_ The amount of funds returned. */ event FundsReturned(uint256 amount_); /** * @dev Loan was initialized. * @param borrower_ The address of the borrower. * @param feeManager_ The address of the entity responsible for calculating fees * @param assets_ Array of asset addresses. * [0]: collateralAsset, * [1]: fundsAsset. * @param termDetails_ Array of loan parameters: * [0]: gracePeriod, * [1]: paymentInterval, * [2]: payments, * @param amounts_ Requested amounts: * [0]: collateralRequired, * [1]: principalRequested, * [2]: endingPrincipal. * @param rates_ Fee parameters: * [0]: interestRate, * [1]: closingFeeRate, * [2]: lateFeeRate, * [3]: lateInterestPremium * @param fees_ Array of fees: * [0]: delegateOriginationFee, * [1]: delegateServiceFee */ event Initialized( address indexed borrower_, address indexed feeManager_, address[2] assets_, uint256[3] termDetails_, uint256[3] amounts_, uint256[4] rates_, uint256[2] fees_ ); /** * @dev Lender was accepted, and set to a new account. * @param lender_ The address of the new lender. */ event LenderAccepted(address indexed lender_); /** * @dev The next payment due date was fast forwarded to the current time, activating the grace period. * This is emitted when the pool delegate wants to force a payment (or default). * @param nextPaymentDueDate_ The new next payment due date. */ event LoanImpaired(uint256 nextPaymentDueDate_); /** * @dev Loan was repaid early and closed. * @param principalPaid_ The portion of the total amount that went towards principal. * @param interestPaid_ The portion of the total amount that went towards interest. * @param feesPaid_ The portion of the total amount that went towards fees. */ event LoanClosed(uint256 principalPaid_, uint256 interestPaid_, uint256 feesPaid_); /** * @dev The terms of the refinance proposal were accepted. * @param refinanceCommitment_ The hash of the refinancer, deadline, and calls proposed. * @param refinancer_ The address that will execute the refinance. * @param deadline_ The deadline for accepting the new terms. * @param calls_ The individual calls for the refinancer contract. */ event NewTermsAccepted(bytes32 refinanceCommitment_, address refinancer_, uint256 deadline_, bytes[] calls_); /** * @dev A refinance was proposed. * @param refinanceCommitment_ The hash of the refinancer, deadline, and calls proposed. * @param refinancer_ The address that will execute the refinance. * @param deadline_ The deadline for accepting the new terms. * @param calls_ The individual calls for the refinancer contract. */ event NewTermsProposed(bytes32 refinanceCommitment_, address refinancer_, uint256 deadline_, bytes[] calls_); /** * @dev The terms of the refinance proposal were rejected. * @param refinanceCommitment_ The hash of the refinancer, deadline, and calls proposed. * @param refinancer_ The address that will execute the refinance. * @param deadline_ The deadline for accepting the new terms. * @param calls_ The individual calls for the refinancer contract. */ event NewTermsRejected(bytes32 refinanceCommitment_, address refinancer_, uint256 deadline_, bytes[] calls_); /** * @dev The next payment due date was restored to it's original value, reverting the action of loan impairment. * @param nextPaymentDueDate_ The new next payment due date. */ event NextPaymentDueDateRestored(uint256 nextPaymentDueDate_); /** * @dev Payments were made. * @param principalPaid_ The portion of the total amount that went towards principal. * @param interestPaid_ The portion of the total amount that went towards interest. * @param fees_ The portion of the total amount that went towards fees. */ event PaymentMade(uint256 principalPaid_, uint256 interestPaid_, uint256 fees_); /** * @dev Pending borrower was set. * @param pendingBorrower_ Address that can accept the borrower role. */ event PendingBorrowerSet(address pendingBorrower_); /** * @dev Pending lender was set. * @param pendingLender_ Address that can accept the lender role. */ event PendingLenderSet(address pendingLender_); /** * @dev The loan was in default and funds and collateral was repossessed by the lender. * @param collateralRepossessed_ The amount of collateral asset repossessed. * @param fundsRepossessed_ The amount of funds asset repossessed. * @param destination_ The recipient of the collateral and funds, if any. */ event Repossessed(uint256 collateralRepossessed_, uint256 fundsRepossessed_, address indexed destination_); /** * @dev Some token (neither fundsAsset nor collateralAsset) was removed from the loan. * @param token_ The address of the token contract. * @param amount_ The amount of token remove from the loan. * @param destination_ The recipient of the token. */ event Skimmed(address indexed token_, uint256 amount_, address indexed destination_); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.7; interface IMapleLoanFeeManager { /******************************************************************************************************************************/ /*** Events ***/ /******************************************************************************************************************************/ /** * @dev New fee terms have been set. * @param loan_ The address of the loan contract. * @param delegateOriginationFee_ The new value for delegate origination fee. * @param delegateServiceFee_ The new value for delegate service fee. */ event FeeTermsUpdated(address loan_, uint256 delegateOriginationFee_, uint256 delegateServiceFee_); /** * @dev A fee payment was made. * @param loan_ The address of the loan contract. * @param delegateOriginationFee_ The amount of delegate origination fee paid. * @param platformOriginationFee_ The amount of platform origination fee paid. */ event OriginationFeesPaid(address loan_, uint256 delegateOriginationFee_, uint256 platformOriginationFee_); /** * @dev New fee terms have been set. * @param loan_ The address of the loan contract. * @param platformServiceFee_ The new value for the platform service fee. */ event PlatformServiceFeeUpdated(address loan_, uint256 platformServiceFee_); /** * @dev New fee terms have been set. * @param loan_ The address of the loan contract. * @param partialPlatformServiceFee_ The value for the platform service fee. * @param partialDelegateServiceFee_ The value for the delegate service fee. */ event PartialRefinanceServiceFeesUpdated(address loan_, uint256 partialPlatformServiceFee_, uint256 partialDelegateServiceFee_); /** * @dev A fee payment was made. * @param loan_ The address of the loan contract. * @param delegateServiceFee_ The amount of delegate service fee paid. * @param partialRefinanceDelegateServiceFee_ The amount of partial delegate service fee from refinance paid. * @param platformServiceFee_ The amount of platform service fee paid. * @param partialRefinancePlatformServiceFee_ The amount of partial platform service fee from refinance paid. */ event ServiceFeesPaid(address loan_, uint256 delegateServiceFee_, uint256 partialRefinanceDelegateServiceFee_, uint256 platformServiceFee_, uint256 partialRefinancePlatformServiceFee_); /******************************************************************************************************************************/ /*** Payment Functions ***/ /******************************************************************************************************************************/ /** * @dev Called during `makePayment`, performs fee payments to the pool delegate and treasury. * @param asset_ The address asset in which fees were paid. * @param numberOfPayments_ The number of payments for which service fees will be paid. */ function payServiceFees(address asset_, uint256 numberOfPayments_) external returns (uint256 feePaid_); /** * @dev Called during `fundLoan`, performs fee payments to poolDelegate and treasury. * @param asset_ The address asset in which fees were paid. * @param principalRequested_ The total amount of principal requested, which will be used to calculate fees. * @return feePaid_ The total amount of fees paid. */ function payOriginationFees(address asset_, uint256 principalRequested_) external returns (uint256 feePaid_); /******************************************************************************************************************************/ /*** Fee Update Functions ***/ /******************************************************************************************************************************/ /** * @dev Called during loan creation or refinance, sets the fee terms. * @param delegateOriginationFee_ The amount of delegate origination fee to be paid. * @param delegateServiceFee_ The amount of delegate service fee to be paid. */ function updateDelegateFeeTerms(uint256 delegateOriginationFee_, uint256 delegateServiceFee_) external; /** * @dev Called during loan refinance to save the partial service fees accrued. * @param principalRequested_ The amount of principal pre-refinance requested. * @param timeSinceLastDueDate_ The amount of time since last payment due date. */ function updateRefinanceServiceFees(uint256 principalRequested_, uint256 timeSinceLastDueDate_) external; /** * @dev Function called by loans to update the saved platform service fee rate. */ function updatePlatformServiceFee(uint256 principalRequested_, uint256 paymentInterval_) external; /******************************************************************************************************************************/ /*** View Functions ***/ /******************************************************************************************************************************/ /** * @dev Gets the delegate origination fee for the given loan. * @param loan_ The address of the loan contract. * @return delegateOriginationFee_ The amount of origination to be paid to delegate. */ function delegateOriginationFee(address loan_) external view returns (uint256 delegateOriginationFee_); /** * @dev Gets the delegate service fee rate for the given loan. * @param loan_ The address of the loan contract. * @return delegateServiceFee_ The amount of delegate service fee to be paid. */ function delegateServiceFee(address loan_) external view returns (uint256 delegateServiceFee_); /** * @dev Gets the delegate service fee rate for the given loan. * @param loan_ The address of the loan contract. * @return delegateRefinanceServiceFee_ The amount of delegate service fee to be paid. */ function delegateRefinanceServiceFee(address loan_) external view returns (uint256 delegateRefinanceServiceFee_); /** * @dev Gets the delegate service fee for the given loan. * @param loan_ The address of the loan contract. * @param interval_ The time, in seconds, to get the proportional fee for * @return delegateServiceFee_ The amount of delegate service fee to be paid. */ function getDelegateServiceFeesForPeriod(address loan_, uint256 interval_) external view returns (uint256 delegateServiceFee_); /** * @dev Gets the sum of all origination fees for the given loan. * @param loan_ The address of the loan contract. * @param principalRequested_ The amount of principal requested in the loan. * @return originationFees_ The amount of origination fees to be paid. */ function getOriginationFees(address loan_, uint256 principalRequested_) external view returns (uint256 originationFees_); /** * @dev Gets the platform origination fee value for the given loan. * @param loan_ The address of the loan contract. * @param principalRequested_ The amount of principal requested in the loan. * @return platformOriginationFee_ The amount of platform origination fee to be paid. */ function getPlatformOriginationFee(address loan_, uint256 principalRequested_) external view returns (uint256 platformOriginationFee_); /** * @dev Gets the delegate service fee for the given loan. * @param loan_ The address of the loan contract. * @param principalRequested_ The amount of principal requested in the loan. * @param interval_ The time, in seconds, to get the proportional fee for * @return platformServiceFee_ The amount of platform service fee to be paid. */ function getPlatformServiceFeeForPeriod(address loan_, uint256 principalRequested_, uint256 interval_) external view returns (uint256 platformServiceFee_); /** * @dev Gets the service fees for the given interval. * @param loan_ The address of the loan contract. * @param numberOfPayments_ The number of payments being paid. * @return delegateServiceFee_ The amount of delegate service fee to be paid. * @return delegateRefinanceFee_ The amount of delegate refinance fee to be paid. * @return platformServiceFee_ The amount of platform service fee to be paid. * @return platformRefinanceFee_ The amount of platform refinance fee to be paid. */ function getServiceFeeBreakdown(address loan_, uint256 numberOfPayments_) external view returns ( uint256 delegateServiceFee_, uint256 delegateRefinanceFee_, uint256 platformServiceFee_, uint256 platformRefinanceFee_ ); /** * @dev Gets the service fees for the given interval. * @param loan_ The address of the loan contract. * @param numberOfPayments_ The number of payments being paid. * @return serviceFees_ The amount of platform service fee to be paid. */ function getServiceFees(address loan_, uint256 numberOfPayments_) external view returns (uint256 serviceFees_); /** * @dev Gets the service fees for the given interval. * @param loan_ The address of the loan contract. * @param interval_ The time, in seconds, to get the proportional fee for * @return serviceFees_ The amount of platform service fee to be paid. */ function getServiceFeesForPeriod(address loan_, uint256 interval_) external view returns (uint256 serviceFees_); /** * @dev Gets the global contract address. * @return globals_ The address of the global contract. */ function globals() external view returns (address globals_); /** * @dev Gets the platform fee rate for the given loan. * @param loan_ The address of the loan contract. * @return platformRefinanceServiceFee_ The amount of platform service fee to be paid. */ function platformRefinanceServiceFee(address loan_) external view returns (uint256 platformRefinanceServiceFee_); /** * @dev Gets the platform fee rate for the given loan. * @param loan_ The address of the loan contract. * @return platformServiceFee The amount of platform service fee to be paid. */ function platformServiceFee(address loan_) external view returns (uint256 platformServiceFee); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.7; interface IMapleGlobalsLike { function governor() external view returns (address governor_); function isBorrower(address account_) external view returns (bool isBorrower_); function isCollateralAsset(address collateralAsset_) external view returns (bool isCollateralAsset_); function isFactory(bytes32 factoryId_, address factory_) external view returns (bool isValid_); function isPoolAsset(address poolAsset_) external view returns (bool isValid_); function mapleTreasury() external view returns (address governor_); function platformOriginationFeeRate(address pool_) external view returns (uint256 platformOriginationFeeRate_); function platformServiceFeeRate(address pool_) external view returns (uint256 platformFee_); function protocolPaused() external view returns (bool protocolPaused_); function securityAdmin() external view returns (address securityAdmin_); } interface ILenderLike { function claim(uint256 principal_, uint256 interest_, uint256 previousPaymentDueDate_, uint256 nextPaymentDueDate_) external; function factory() external view returns (address factory_); } interface ILoanLike { function factory() external view returns (address factory_); function fundsAsset() external view returns (address asset_); function lender() external view returns (address lender_); function paymentInterval() external view returns (uint256 paymentInterval_); function paymentsRemaining() external view returns (uint256 paymentsRemaining_); function principal() external view returns (uint256 principal_); function principalRequested() external view returns (uint256 principalRequested_); } interface ILoanManagerLike { function owner() external view returns (address owner_); function poolManager() external view returns (address poolManager_); } interface IMapleFeeManagerLike { function updateDelegateFeeTerms(uint256 delegateOriginationFee_, uint256 delegateServiceFee_) external; function updatePlatformServiceFee(uint256 principalRequested_, uint256 paymentInterval_) external; } interface IMapleProxyFactoryLike { function isInstance(address instance_) external view returns (bool isInstance_); function mapleGlobals() external view returns (address mapleGlobals_); } interface IPoolManagerLike { function poolDelegate() external view returns (address poolDelegate_); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.7; /// @title Interface of the ERC20 standard as defined in the EIP, including EIP-2612 permit functionality. interface IERC20 { /**************/ /*** Events ***/ /**************/ /** * @dev Emitted when one account has set the allowance of another account over their tokens. * @param owner_ Account that tokens are approved from. * @param spender_ Account that tokens are approved for. * @param amount_ Amount of tokens that have been approved. */ event Approval(address indexed owner_, address indexed spender_, uint256 amount_); /** * @dev Emitted when tokens have moved from one account to another. * @param owner_ Account that tokens have moved from. * @param recipient_ Account that tokens have moved to. * @param amount_ Amount of tokens that have been transferred. */ event Transfer(address indexed owner_, address indexed recipient_, uint256 amount_); /**************************/ /*** External Functions ***/ /**************************/ /** * @dev Function that allows one account to set the allowance of another account over their tokens. * Emits an {Approval} event. * @param spender_ Account that tokens are approved for. * @param amount_ Amount of tokens that have been approved. * @return success_ Boolean indicating whether the operation succeeded. */ function approve(address spender_, uint256 amount_) external returns (bool success_); /** * @dev Function that allows one account to decrease the allowance of another account over their tokens. * Emits an {Approval} event. * @param spender_ Account that tokens are approved for. * @param subtractedAmount_ Amount to decrease approval by. * @return success_ Boolean indicating whether the operation succeeded. */ function decreaseAllowance(address spender_, uint256 subtractedAmount_) external returns (bool success_); /** * @dev Function that allows one account to increase the allowance of another account over their tokens. * Emits an {Approval} event. * @param spender_ Account that tokens are approved for. * @param addedAmount_ Amount to increase approval by. * @return success_ Boolean indicating whether the operation succeeded. */ function increaseAllowance(address spender_, uint256 addedAmount_) external returns (bool success_); /** * @dev Approve by signature. * @param owner_ Owner address that signed the permit. * @param spender_ Spender of the permit. * @param amount_ Permit approval spend limit. * @param deadline_ Deadline after which the permit is invalid. * @param v_ ECDSA signature v component. * @param r_ ECDSA signature r component. * @param s_ ECDSA signature s component. */ function permit(address owner_, address spender_, uint amount_, uint deadline_, uint8 v_, bytes32 r_, bytes32 s_) external; /** * @dev Moves an amount of tokens from `msg.sender` to a specified account. * Emits a {Transfer} event. * @param recipient_ Account that receives tokens. * @param amount_ Amount of tokens that are transferred. * @return success_ Boolean indicating whether the operation succeeded. */ function transfer(address recipient_, uint256 amount_) external returns (bool success_); /** * @dev Moves a pre-approved amount of tokens from a sender to a specified account. * Emits a {Transfer} event. * Emits an {Approval} event. * @param owner_ Account that tokens are moving from. * @param recipient_ Account that receives tokens. * @param amount_ Amount of tokens that are transferred. * @return success_ Boolean indicating whether the operation succeeded. */ function transferFrom(address owner_, address recipient_, uint256 amount_) external returns (bool success_); /**********************/ /*** View Functions ***/ /**********************/ /** * @dev Returns the allowance that one account has given another over their tokens. * @param owner_ Account that tokens are approved from. * @param spender_ Account that tokens are approved for. * @return allowance_ Allowance that one account has given another over their tokens. */ function allowance(address owner_, address spender_) external view returns (uint256 allowance_); /** * @dev Returns the amount of tokens owned by a given account. * @param account_ Account that owns the tokens. * @return balance_ Amount of tokens owned by a given account. */ function balanceOf(address account_) external view returns (uint256 balance_); /** * @dev Returns the decimal precision used by the token. * @return decimals_ The decimal precision used by the token. */ function decimals() external view returns (uint8 decimals_); /** * @dev Returns the signature domain separator. * @return domainSeparator_ The signature domain separator. */ function DOMAIN_SEPARATOR() external view returns (bytes32 domainSeparator_); /** * @dev Returns the name of the token. * @return name_ The name of the token. */ function name() external view returns (string memory name_); /** * @dev Returns the nonce for the given owner. * @param owner_ The address of the owner account. * @return nonce_ The nonce for the given owner. */ function nonces(address owner_) external view returns (uint256 nonce_); /** * @dev Returns the permit type hash. * @return permitTypehash_ The permit type hash. */ function PERMIT_TYPEHASH() external view returns (bytes32 permitTypehash_); /** * @dev Returns the symbol of the token. * @return symbol_ The symbol of the token. */ function symbol() external view returns (string memory symbol_); /** * @dev Returns the total amount of tokens in existence. * @return totalSupply_ The total amount of tokens in existence. */ function totalSupply() external view returns (uint256 totalSupply_); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.7; import { IERC20Like } from "./interfaces/IERC20Like.sol"; /** * @title Small Library to standardize erc20 token interactions. */ library ERC20Helper { /**************************/ /*** Internal Functions ***/ /**************************/ function transfer(address token_, address to_, uint256 amount_) internal returns (bool success_) { return _call(token_, abi.encodeWithSelector(IERC20Like.transfer.selector, to_, amount_)); } function transferFrom(address token_, address from_, address to_, uint256 amount_) internal returns (bool success_) { return _call(token_, abi.encodeWithSelector(IERC20Like.transferFrom.selector, from_, to_, amount_)); } function approve(address token_, address spender_, uint256 amount_) internal returns (bool success_) { // If setting approval to zero fails, return false. if (!_call(token_, abi.encodeWithSelector(IERC20Like.approve.selector, spender_, uint256(0)))) return false; // If `amount_` is zero, return true as the previous step already did this. if (amount_ == uint256(0)) return true; // Return the result of setting the approval to `amount_`. return _call(token_, abi.encodeWithSelector(IERC20Like.approve.selector, spender_, amount_)); } function _call(address token_, bytes memory data_) private returns (bool success_) { if (token_.code.length == uint256(0)) return false; bytes memory returnData; ( success_, returnData ) = token_.call(data_); return success_ && (returnData.length == uint256(0) || abi.decode(returnData, (bool))); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.7; /// @title Interface of the ERC20 standard as needed by ERC20Helper. interface IERC20Like { function approve(address spender_, uint256 amount_) external returns (bool success_); function transfer(address recipient_, uint256 amount_) external returns (bool success_); function transferFrom(address owner_, address recipient_, uint256 amount_) external returns (bool success_); }
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.8.7; import { ProxiedInternals } from "../modules/proxy-factory/contracts/ProxiedInternals.sol"; /// @title A Maple implementation that is to be proxied, will need MapleProxiedInternals. abstract contract MapleProxiedInternals is ProxiedInternals {}
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.8.7; import { IProxied } from "../../modules/proxy-factory/contracts/interfaces/IProxied.sol"; /// @title A Maple implementation that is to be proxied, must implement IMapleProxied. interface IMapleProxied is IProxied { /** * @dev The instance was upgraded. * @param toVersion_ The new version of the loan. * @param arguments_ The upgrade arguments, if any. */ event Upgraded(uint256 toVersion_, bytes arguments_); /** * @dev Upgrades a contract implementation to a specific version. * Access control logic critical since caller can force a selfdestruct via a malicious `migrator_` which is delegatecalled. * @param toVersion_ The version to upgrade to. * @param arguments_ Some encoded arguments to use for the upgrade. */ function upgrade(uint256 toVersion_, bytes calldata arguments_) external; }
// SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity 0.8.7; import { IDefaultImplementationBeacon } from "../../modules/proxy-factory/contracts/interfaces/IDefaultImplementationBeacon.sol"; /// @title A Maple factory for Proxy contracts that proxy MapleProxied implementations. interface IMapleProxyFactory is IDefaultImplementationBeacon { /**************/ /*** Events ***/ /**************/ /** * @dev A default version was set. * @param version_ The default version. */ event DefaultVersionSet(uint256 indexed version_); /** * @dev A version of an implementation, at some address, was registered, with an optional initializer. * @param version_ The version registered. * @param implementationAddress_ The address of the implementation. * @param initializer_ The address of the initializer, if any. */ event ImplementationRegistered(uint256 indexed version_, address indexed implementationAddress_, address indexed initializer_); /** * @dev A proxy contract was deployed with some initialization arguments. * @param version_ The version of the implementation being proxied by the deployed proxy contract. * @param instance_ The address of the proxy contract deployed. * @param initializationArguments_ The arguments used to initialize the proxy contract, if any. */ event InstanceDeployed(uint256 indexed version_, address indexed instance_, bytes initializationArguments_); /** * @dev A instance has upgraded by proxying to a new implementation, with some migration arguments. * @param instance_ The address of the proxy contract. * @param fromVersion_ The initial implementation version being proxied. * @param toVersion_ The new implementation version being proxied. * @param migrationArguments_ The arguments used to migrate, if any. */ event InstanceUpgraded(address indexed instance_, uint256 indexed fromVersion_, uint256 indexed toVersion_, bytes migrationArguments_); /** * @dev The MapleGlobals was set. * @param mapleGlobals_ The address of a Maple Globals contract. */ event MapleGlobalsSet(address indexed mapleGlobals_); /** * @dev An upgrade path was disabled, with an optional migrator contract. * @param fromVersion_ The starting version of the upgrade path. * @param toVersion_ The destination version of the upgrade path. */ event UpgradePathDisabled(uint256 indexed fromVersion_, uint256 indexed toVersion_); /** * @dev An upgrade path was enabled, with an optional migrator contract. * @param fromVersion_ The starting version of the upgrade path. * @param toVersion_ The destination version of the upgrade path. * @param migrator_ The address of the migrator, if any. */ event UpgradePathEnabled(uint256 indexed fromVersion_, uint256 indexed toVersion_, address indexed migrator_); /***********************/ /*** State Variables ***/ /***********************/ /** * @dev The default version. */ function defaultVersion() external view returns (uint256 defaultVersion_); /** * @dev The address of the MapleGlobals contract. */ function mapleGlobals() external view returns (address mapleGlobals_); /** * @dev Whether the upgrade is enabled for a path from a version to another version. * @param toVersion_ The initial version. * @param fromVersion_ The destination version. * @return allowed_ Whether the upgrade is enabled. */ function upgradeEnabledForPath(uint256 toVersion_, uint256 fromVersion_) external view returns (bool allowed_); /********************************/ /*** State Changing Functions ***/ /********************************/ /** * @dev Deploys a new instance proxying the default implementation version, with some initialization arguments. * Uses a nonce and `msg.sender` as a salt for the CREATE2 opcode during instantiation to produce deterministic addresses. * @param arguments_ The initialization arguments to use for the instance deployment, if any. * @param salt_ The salt to use in the contract creation process. * @return instance_ The address of the deployed proxy contract. */ function createInstance(bytes calldata arguments_, bytes32 salt_) external returns (address instance_); /** * @dev Enables upgrading from a version to a version of an implementation, with an optional migrator. * Only the Governor can call this function. * @param fromVersion_ The starting version of the upgrade path. * @param toVersion_ The destination version of the upgrade path. * @param migrator_ The address of the migrator, if any. */ function enableUpgradePath(uint256 fromVersion_, uint256 toVersion_, address migrator_) external; /** * @dev Disables upgrading from a version to a version of a implementation. * Only the Governor can call this function. * @param fromVersion_ The starting version of the upgrade path. * @param toVersion_ The destination version of the upgrade path. */ function disableUpgradePath(uint256 fromVersion_, uint256 toVersion_) external; /** * @dev Registers the address of an implementation contract as a version, with an optional initializer. * Only the Governor can call this function. * @param version_ The version to register. * @param implementationAddress_ The address of the implementation. * @param initializer_ The address of the initializer, if any. */ function registerImplementation(uint256 version_, address implementationAddress_, address initializer_) external; /** * @dev Sets the default version. * Only the Governor can call this function. * @param version_ The implementation version to set as the default. */ function setDefaultVersion(uint256 version_) external; /** * @dev Sets the Maple Globals contract. * Only the Governor can call this function. * @param mapleGlobals_ The address of a Maple Globals contract. */ function setGlobals(address mapleGlobals_) external; /** * @dev Upgrades the calling proxy contract's implementation, with some migration arguments. * @param toVersion_ The implementation version to upgrade the proxy contract to. * @param arguments_ The migration arguments, if any. */ function upgradeInstance(uint256 toVersion_, bytes calldata arguments_) external; /**********************/ /*** View Functions ***/ /**********************/ /** * @dev Returns the deterministic address of a potential proxy, given some arguments and salt. * @param arguments_ The initialization arguments to be used when deploying the proxy. * @param salt_ The salt to be used when deploying the proxy. * @return instanceAddress_ The deterministic address of a potential proxy. */ function getInstanceAddress(bytes calldata arguments_, bytes32 salt_) external view returns (address instanceAddress_); /** * @dev Returns the address of an implementation version. * @param version_ The implementation version. * @return implementation_ The address of the implementation. */ function implementationOf(uint256 version_) external view returns (address implementation_); /** * @dev Returns the address of a migrator contract for a migration path (from version, to version). * If oldVersion_ == newVersion_, the migrator is an initializer. * @param oldVersion_ The old version. * @param newVersion_ The new version. * @return migrator_ The address of a migrator contract. */ function migratorForPath(uint256 oldVersion_, uint256 newVersion_) external view returns (address migrator_); /** * @dev Returns the version of an implementation contract. * @param implementation_ The address of an implementation contract. * @return version_ The version of the implementation contract. */ function versionOf(address implementation_) external view returns (uint256 version_); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.7; import { SlotManipulatable } from "./SlotManipulatable.sol"; /// @title An implementation that is to be proxied, will need ProxiedInternals. abstract contract ProxiedInternals is SlotManipulatable { /// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.factory') - 1`. bytes32 private constant FACTORY_SLOT = bytes32(0x7a45a402e4cb6e08ebc196f20f66d5d30e67285a2a8aa80503fa409e727a4af1); /// @dev Storage slot with the address of the current factory. `keccak256('eip1967.proxy.implementation') - 1`. bytes32 private constant IMPLEMENTATION_SLOT = bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc); /// @dev Delegatecalls to a migrator contract to manipulate storage during an initialization or migration. function _migrate(address migrator_, bytes calldata arguments_) internal virtual returns (bool success_) { uint256 size; assembly { size := extcodesize(migrator_) } if (size == uint256(0)) return false; ( success_, ) = migrator_.delegatecall(arguments_); } /// @dev Sets the factory address in storage. function _setFactory(address factory_) internal virtual returns (bool success_) { _setSlotValue(FACTORY_SLOT, bytes32(uint256(uint160(factory_)))); return true; } /// @dev Sets the implementation address in storage. function _setImplementation(address implementation_) internal virtual returns (bool success_) { _setSlotValue(IMPLEMENTATION_SLOT, bytes32(uint256(uint160(implementation_)))); return true; } /// @dev Returns the factory address. function _factory() internal view virtual returns (address factory_) { return address(uint160(uint256(_getSlotValue(FACTORY_SLOT)))); } /// @dev Returns the implementation address. function _implementation() internal view virtual returns (address implementation_) { return address(uint160(uint256(_getSlotValue(IMPLEMENTATION_SLOT)))); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.7; abstract contract SlotManipulatable { function _getReferenceTypeSlot(bytes32 slot_, bytes32 key_) internal pure returns (bytes32 value_) { return keccak256(abi.encodePacked(key_, slot_)); } function _getSlotValue(bytes32 slot_) internal view returns (bytes32 value_) { assembly { value_ := sload(slot_) } } function _setSlotValue(bytes32 slot_, bytes32 value_) internal { assembly { sstore(slot_, value_) } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.7; /// @title An beacon that provides a default implementation for proxies, must implement IDefaultImplementationBeacon. interface IDefaultImplementationBeacon { /// @dev The address of an implementation for proxies. function defaultImplementation() external view returns (address defaultImplementation_); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity ^0.8.7; /// @title An implementation that is to be proxied, must implement IProxied. interface IProxied { /** * @dev The address of the proxy factory. */ function factory() external view returns (address factory_); /** * @dev The address of the implementation contract being proxied. */ function implementation() external view returns (address implementation_); /** * @dev Modifies the proxy's implementation address. * @param newImplementation_ The address of an implementation contract. */ function setImplementation(address newImplementation_) external; /** * @dev Modifies the proxy's storage by delegate-calling a migrator contract with some arguments. * Access control logic critical since caller can force a selfdestruct via a malicious `migrator_` which is delegatecalled. * @param migrator_ The address of a migrator contract. * @param arguments_ Some encoded arguments to use for the migration. */ function migrate(address migrator_, bytes calldata arguments_) external; }
{ "remappings": [ "contract-test-utils/=modules/contract-test-utils/contracts/", "erc20-helper/=modules/erc20-helper/src/", "erc20/=modules/erc20/", "maple-proxy-factory/=modules/maple-proxy-factory/modules/proxy-factory/modules/ds-test/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower_","type":"address"}],"name":"BorrowerAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"CollateralPosted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"},{"indexed":true,"internalType":"address","name":"destination_","type":"address"}],"name":"CollateralRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"lender_","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nextPaymentDueDate_","type":"uint256"}],"name":"Funded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"},{"indexed":true,"internalType":"address","name":"destination_","type":"address"}],"name":"FundsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"},{"indexed":true,"internalType":"address","name":"destination_","type":"address"}],"name":"FundsDrawnDown","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"FundsReturned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"borrower_","type":"address"},{"indexed":true,"internalType":"address","name":"feeManager_","type":"address"},{"indexed":false,"internalType":"address[2]","name":"assets_","type":"address[2]"},{"indexed":false,"internalType":"uint256[3]","name":"termDetails_","type":"uint256[3]"},{"indexed":false,"internalType":"uint256[3]","name":"amounts_","type":"uint256[3]"},{"indexed":false,"internalType":"uint256[4]","name":"rates_","type":"uint256[4]"},{"indexed":false,"internalType":"uint256[2]","name":"fees_","type":"uint256[2]"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"lender_","type":"address"}],"name":"LenderAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"principalPaid_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestPaid_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feesPaid_","type":"uint256"}],"name":"LoanClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nextPaymentDueDate_","type":"uint256"}],"name":"LoanImpaired","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"refinanceCommitment_","type":"bytes32"},{"indexed":false,"internalType":"address","name":"refinancer_","type":"address"},{"indexed":false,"internalType":"uint256","name":"deadline_","type":"uint256"},{"indexed":false,"internalType":"bytes[]","name":"calls_","type":"bytes[]"}],"name":"NewTermsAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"refinanceCommitment_","type":"bytes32"},{"indexed":false,"internalType":"address","name":"refinancer_","type":"address"},{"indexed":false,"internalType":"uint256","name":"deadline_","type":"uint256"},{"indexed":false,"internalType":"bytes[]","name":"calls_","type":"bytes[]"}],"name":"NewTermsProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"refinanceCommitment_","type":"bytes32"},{"indexed":false,"internalType":"address","name":"refinancer_","type":"address"},{"indexed":false,"internalType":"uint256","name":"deadline_","type":"uint256"},{"indexed":false,"internalType":"bytes[]","name":"calls_","type":"bytes[]"}],"name":"NewTermsRejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nextPaymentDueDate_","type":"uint256"}],"name":"NextPaymentDueDateRestored","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"principalPaid_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interestPaid_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees_","type":"uint256"}],"name":"PaymentMade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pendingBorrower_","type":"address"}],"name":"PendingBorrowerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pendingLender_","type":"address"}],"name":"PendingLenderSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"collateralRepossessed_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fundsRepossessed_","type":"uint256"},{"indexed":true,"internalType":"address","name":"destination_","type":"address"}],"name":"Repossessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token_","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount_","type":"uint256"},{"indexed":true,"internalType":"address","name":"destination_","type":"address"}],"name":"Skimmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"toVersion_","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"arguments_","type":"bytes"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"acceptBorrower","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptLender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"refinancer_","type":"address"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"bytes[]","name":"calls_","type":"bytes[]"}],"name":"acceptNewTerms","outputs":[{"internalType":"bytes32","name":"refinanceCommitment_","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrower","outputs":[{"internalType":"address","name":"borrower_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"closeLoan","outputs":[{"internalType":"uint256","name":"principal_","type":"uint256"},{"internalType":"uint256","name":"interest_","type":"uint256"},{"internalType":"uint256","name":"fees_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"closingRate","outputs":[{"internalType":"uint256","name":"closingRate_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"uint256","name":"collateral_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralAsset","outputs":[{"internalType":"address","name":"collateralAsset_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralRequired","outputs":[{"internalType":"uint256","name":"collateralRequired_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"drawableFunds","outputs":[{"internalType":"uint256","name":"drawableFunds_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"address","name":"destination_","type":"address"}],"name":"drawdownFunds","outputs":[{"internalType":"uint256","name":"collateralPosted_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endingPrincipal","outputs":[{"internalType":"uint256","name":"endingPrincipal_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"excessCollateral","outputs":[{"internalType":"uint256","name":"excessCollateral_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"factory_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeManager","outputs":[{"internalType":"address","name":"feeManager_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lender_","type":"address"}],"name":"fundLoan","outputs":[{"internalType":"uint256","name":"fundsLent_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fundsAsset","outputs":[{"internalType":"address","name":"fundsAsset_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"drawdown_","type":"uint256"}],"name":"getAdditionalCollateralRequiredFor","outputs":[{"internalType":"uint256","name":"collateral_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClosingPaymentBreakdown","outputs":[{"internalType":"uint256","name":"principal_","type":"uint256"},{"internalType":"uint256","name":"interest_","type":"uint256"},{"internalType":"uint256","name":"fees_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNextPaymentBreakdown","outputs":[{"internalType":"uint256","name":"principal_","type":"uint256"},{"internalType":"uint256","name":"interest_","type":"uint256"},{"internalType":"uint256","name":"fees_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNextPaymentDetailedBreakdown","outputs":[{"internalType":"uint256","name":"principal_","type":"uint256"},{"internalType":"uint256[3]","name":"interest_","type":"uint256[3]"},{"internalType":"uint256[2]","name":"fees_","type":"uint256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp_","type":"uint256"}],"name":"getRefinanceInterest","outputs":[{"internalType":"uint256","name":"proRataInterest_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset_","type":"address"}],"name":"getUnaccountedAmount","outputs":[{"internalType":"uint256","name":"unaccountedAmount_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globals","outputs":[{"internalType":"address","name":"globals_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"governor_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gracePeriod","outputs":[{"internalType":"uint256","name":"gracePeriod_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"impairLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"implementation_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestRate","outputs":[{"internalType":"uint256","name":"interestRate_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isImpaired","outputs":[{"internalType":"bool","name":"isImpaired_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lateFeeRate","outputs":[{"internalType":"uint256","name":"lateFeeRate_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lateInterestPremium","outputs":[{"internalType":"uint256","name":"lateInterestPremium_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lender","outputs":[{"internalType":"address","name":"lender_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"makePayment","outputs":[{"internalType":"uint256","name":"principal_","type":"uint256"},{"internalType":"uint256","name":"interest_","type":"uint256"},{"internalType":"uint256","name":"fees_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"migrator_","type":"address"},{"internalType":"bytes","name":"arguments_","type":"bytes"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nextPaymentDueDate","outputs":[{"internalType":"uint256","name":"nextPaymentDueDate_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"originalNextPaymentDueDate","outputs":[{"internalType":"uint256","name":"originalNextPaymentDueDate_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paymentInterval","outputs":[{"internalType":"uint256","name":"paymentInterval_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paymentsRemaining","outputs":[{"internalType":"uint256","name":"paymentsRemaining_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingBorrower","outputs":[{"internalType":"address","name":"pendingBorrower_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingLender","outputs":[{"internalType":"address","name":"pendingLender_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"postCollateral","outputs":[{"internalType":"uint256","name":"collateralPosted_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"principal","outputs":[{"internalType":"uint256","name":"principal_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"principalRequested","outputs":[{"internalType":"uint256","name":"principalRequested_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"refinancer_","type":"address"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"bytes[]","name":"calls_","type":"bytes[]"}],"name":"proposeNewTerms","outputs":[{"internalType":"bytes32","name":"refinanceCommitment_","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refinanceCommitment","outputs":[{"internalType":"bytes32","name":"refinanceCommitment_","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refinanceInterest","outputs":[{"internalType":"uint256","name":"refinanceInterest_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"refinancer_","type":"address"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"bytes[]","name":"calls_","type":"bytes[]"}],"name":"rejectNewTerms","outputs":[{"internalType":"bytes32","name":"refinanceCommitment_","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"address","name":"destination_","type":"address"}],"name":"removeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"removeLoanImpairment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"destination_","type":"address"}],"name":"repossess","outputs":[{"internalType":"uint256","name":"collateralRepossessed_","type":"uint256"},{"internalType":"uint256","name":"fundsRepossessed_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"returnFunds","outputs":[{"internalType":"uint256","name":"fundsReturned_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation_","type":"address"}],"name":"setImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingBorrower_","type":"address"}],"name":"setPendingBorrower","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingLender_","type":"address"}],"name":"setPendingLender","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"},{"internalType":"address","name":"destination_","type":"address"}],"name":"skim","outputs":[{"internalType":"uint256","name":"skimmed_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"toVersion_","type":"uint256"},{"internalType":"bytes","name":"arguments_","type":"bytes"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50614822806100206000396000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c80637c3a00fd116101de578063ba5d30781161010f578063d05951a0116100ad578063d4754d5f1161007c578063d4754d5f146106a8578063d784d426146106b0578063d8dfeb45146106c3578063e48f6faf146106cb57600080fd5b8063d05951a01461065a578063d0fb02031461066d578063d3bcd5e21461067e578063d41ddc961461069557600080fd5b8063c3124525116100e9578063c312452514610624578063c3fbb6fd1461062c578063c45a01551461063f578063ccc044841461064757600080fd5b8063ba5d307814610603578063ba83276b1461060b578063bcead63e1461061357600080fd5b8063a29d7aab1161017c578063acb522b411610156578063acb522b4146105d8578063b86a513e146105eb578063b96b5c99146105f3578063b9b1f4e3146105fb57600080fd5b8063a29d7aab146105ac578063a97d1161146105bf578063aabaecd6146105c757600080fd5b80638ffc9215116101b85780638ffc92151461058157806396663914146105895780639e10320b14610591578063a06db7dc146105a457600080fd5b80637c3a00fd146105555780637df1f1b91461055d57806387accaf11461056e57600080fd5b806345755dd6116102b85780636174b27211610256578063712b772f11610230578063712b772f1461052a57806375a206761461053d57806377b3c55c146105455780637a0e6fa11461054d57600080fd5b80636174b272146104f3578063700f50061461050657806370a10c891461051757600080fd5b806350f2012f1161029257806350f2012f146104995780635114cb52146104ac5780635c60da1b146104da5780635eeb53b4146104e257600080fd5b806345755dd61461044b57806347350e9f1461045e5780634eac42351461048657600080fd5b8063227000371161032557806339ba9f86116102ff57806339ba9f861461041757806339d65834146104285780633b99bcee146104305780634003f34d1461044357600080fd5b806322700037146103f4578063267f4ac3146103fc5780632ead10981461040f57600080fd5b80630fe3d9b7116103615780630fe3d9b7146103c9578063144ee4b5146103d15780631cc1cf46146103d95780631f3f19ab146103e157600080fd5b806301daa38f146103885780630895326f146103925780630c340a24146103a9575b600080fd5b6103906106de565b005b6013545b6040519081526020015b60405180910390f35b6103b161081d565b6040516001600160a01b0390911681526020016103a0565b61039061089c565b6103906109d4565b600754610396565b6103906103ef366004614266565b610aec565b601a54610396565b61039061040a366004614266565b610cee565b600b54610396565b6005546001600160a01b03166103b1565b600954610396565b61039061043e366004614433565b610d8a565b601254610396565b6103966104593660046143dc565b610fa0565b61047161046c366004614266565b61110a565b604080519283526020830191909152016103a0565b6103966104943660046143dc565b6112fb565b6103966104a73660046143dc565b611343565b6104bf6104ba3660046143dc565b6114a4565b604080519384526020840192909252908201526060016103a0565b6103b1611ae4565b6003546001600160a01b03166103b1565b610396610501366004614266565b611aee565b6002546001600160a01b03166103b1565b61039661052536600461432e565b611bc2565b6103966105383660046142a0565b6120d6565b600c54610396565b600a54610396565b61039661220d565b600854610396565b6000546001600160a01b03166103b1565b61039661057c36600461432e565b612249565b600d54610396565b6104bf6123e6565b61039661059f3660046143dc565b6124e3565b600654610396565b601a5460405190151581526020016103a0565b601654610396565b6004546001600160a01b03166103b1565b6103966105e636600461432e565b612506565b600e54610396565b6104bf612699565b600f54610396565b601454610396565b601554610396565b6001546001600160a01b03166103b1565b6103b1612715565b61039061063a3660046142d9565b612757565b6103b16127fc565b61039661065536600461440e565b612806565b6104bf6106683660046143dc565b612a48565b6019546001600160a01b03166103b1565b61068661306b565b6040516103a093929190614659565b6103906106a336600461440e565b6130aa565b61039061329b565b6103906106be366004614266565b61333f565b601154610396565b6103966106d9366004614266565b6133cb565b6106e6612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561071e57600080fd5b505afa158015610732573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075691906143ba565b1561077c5760405162461bcd60e51b81526004016107739061462e565b60405180910390fd5b6002546001600160a01b031633146107d65760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a41423a4e4f545f50454e44494e475f424f52524f5745520000000000006044820152606401610773565b600280546001600160a01b031990811690915560008054339216821781556040517f29bac0ac2b15405bfcc160bb74b6ae7a559b7674ce33db80785ada73e38204d29190a2565b6000610827612715565b6001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561085f57600080fd5b505afa158015610873573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108979190614283565b905090565b6108a4612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b1580156108dc57600080fd5b505afa1580156108f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091491906143ba565b156109315760405162461bcd60e51b81526004016107739061462e565b6003546001600160a01b0316331461098b5760405162461bcd60e51b815260206004820152601860248201527f4d4c3a414c3a4e4f545f50454e44494e475f4c454e44455200000000000000006044820152606401610773565b600380546001600160a01b031990811690915560018054339216821790556040517fd6165838d2e3db87aa1002b548048673fc6427eefbd1b914e100f3a0deae23e390600090a2565b601a546001546001600160a01b03163314610a255760405162461bcd60e51b815260206004820152601160248201527026a61d2926249d2727aa2fa622a72222a960791b6044820152606401610773565b80610a685760405162461bcd60e51b815260206004820152601360248201527213530e9493124e9393d517d253541052549151606a1b6044820152606401610773565b80421115610aab5760405162461bcd60e51b815260206004820152601060248201526f4d4c3a524c493a504153545f4441544560801b6044820152606401610773565b60128190556000601a556040518181527f962d5a38dc48af765ecb4f177a88713b592b5bf59e64f497ab33af13b7c0e9de906020015b60405180910390a150565b610af4612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015610b2c57600080fd5b505afa158015610b40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6491906143ba565b15610b815760405162461bcd60e51b81526004016107739061462e565b6000546001600160a01b03163314610bd15760405162461bcd60e51b815260206004820152601360248201527226a61d29a8211d2727aa2fa127a92927aba2a960691b6044820152606401610773565b610bd9612715565b60405163eaf6e48360e01b81526001600160a01b038381166004830152919091169063eaf6e4839060240160206040518083038186803b158015610c1c57600080fd5b505afa158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5491906143ba565b610ca05760405162461bcd60e51b815260206004820152601760248201527f4d4c3a5350423a494e56414c49445f424f52524f5745520000000000000000006044820152606401610773565b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f10f06072822ef73860fedb88933f968d20bb4aadce8a8d360d1124cb6ce1e0b290602001610ae1565b6001546001600160a01b03163314610d3c5760405162461bcd60e51b815260206004820152601160248201527026a61d29a8261d2727aa2fa622a72222a960791b6044820152606401610773565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527fa3ab02442c80a4102475683f16513c9139a89142be9db9804edfcfbb379fc49290602001610ae1565b610d92612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015610dca57600080fd5b505afa158015610dde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0291906143ba565b15610e1f5760405162461bcd60e51b81526004016107739061462e565b610e27612715565b6001600160a01b031663be7c13f76040518163ffffffff1660e01b815260040160206040518083038186803b158015610e5f57600080fd5b505afa158015610e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e979190614283565b6001600160a01b0316336001600160a01b031614610ef75760405162461bcd60e51b815260206004820152601760248201527f4d4c3a553a4e4f545f53454355524954595f41444d494e0000000000000000006044820152606401610773565b7faaaa7ee6b0c2f4ee1fa7312c7d5b3623a434da5a1a9ce3cb6e629caa23454ab6838383604051610f2a939291906146ba565b60405180910390a1610f3a6138ac565b6001600160a01b031663fe69f7088484846040518463ffffffff1660e01b8152600401610f69939291906146ba565b600060405180830381600087803b158015610f8357600080fd5b505af1158015610f97573d6000803e3d6000fd5b50505050505050565b6000610faa612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015610fe257600080fd5b505afa158015610ff6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101a91906143ba565b156110375760405162461bcd60e51b81526004016107739061462e565b8115806110575750600554611057906001600160a01b03163330856138db565b6110a35760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a52463a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b6005546110b8906001600160a01b0316611aee565b905080600f60008282546110cc919061471b565b90915550506040518181527f278e51d3323fbf18b9fb8df3f8b97e31b145bc1146c52e764cf4aa1bfc4ba17d906020015b60405180910390a1919050565b60015460009081906001600160a01b0316331461115b5760405162461bcd60e51b815260206004820152600f60248201526e26a61d291d2727aa2fa622a72222a960891b6044820152606401610773565b60125480158015906111785750600654611175908261471b565b42115b6111ba5760405162461bcd60e51b815260206004820152601360248201527213530e948e9393d517d25397d1115190555315606a1b6044820152606401610773565b6111c2613952565b60006011819055600f8190556004546001600160a01b0316906111e482611aee565b94508414806111f957506111f981868661398b565b61123e5760405162461bcd60e51b815260206004820152601660248201527513530e948e90d7d514905394d1915497d1905253115160521b6044820152606401610773565b6005546001600160a01b0316600061125582611aee565b945084148061126a575061126a81878661398b565b6112af5760405162461bcd60e51b815260206004820152601660248201527513530e948e9197d514905394d1915497d1905253115160521b6044820152606401610773565b60408051868152602081018690526001600160a01b038816917f027e623aab0b174da270ff529cad1c54f09182651e07437d2ac557929b9e5b49910160405180910390a2505050915091565b60008061131d60145484600f546113129190614774565b600d54600c546139c8565b60115490915080821161133157600061133b565b61133b8183614774565b949350505050565b600061134d612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561138557600080fd5b505afa158015611399573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bd91906143ba565b156113da5760405162461bcd60e51b81526004016107739061462e565b8115806113fa57506004546113fa906001600160a01b03163330856138db565b6114465760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a50433a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b60045461145b906001600160a01b0316611aee565b9050806011600082825461146f919061471b565b90915550506040518181527f437d44b2c697fb69e2b2f25f57fd844e376c25ed28ed5a9c4be88aa1e5c87d12906020016110fd565b60008054819081906001600160a01b03163314156117a7576114c4612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b1580156114fc57600080fd5b505afa158015611510573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153491906143ba565b156115515760405162461bcd60e51b81526004016107739061462e565b8315806115715750600554611571906001600160a01b03163330876138db565b6115bd5760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a4d503a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b6115c5613a18565b6115cd612699565b506000601681905591945092506115e4838561471b565b60055490915081906115fe906001600160a01b0316611aee565b600f5461160b919061471b565b6116159190614774565b600f556116226001613a28565b60135460125491935090600060018314156116445761163f613952565b611681565b600754611651908361471b565b905080601281905550866014600082825461166c9190614774565b9091555061167d9050600184614774565b6013555b60408051888152602081018890529081018690527fcf358e925a8e033c6db877f18d10df6f21cd04ef165537bad5fc814eb23af9609060600160405180910390a16005546001546116df916001600160a01b0390811691168661398b565b6116fb5760405162461bcd60e51b8152600401610773906145ff565b60015460405163b5add71760e01b8152600481018990526024810188905260448101849052606481018390526001600160a01b039091169063b5add71790608401600060405180830381600087803b15801561175657600080fd5b505af115801561176a573d6000803e3d6000fd5b50506001546040518781526001600160a01b0390911692506000805160206147cd833981519152915060200160405180910390a250505050611add565b600f546117b2612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b1580156117ea57600080fd5b505afa1580156117fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182291906143ba565b1561183f5760405162461bcd60e51b81526004016107739061462e565b84158061185f575060055461185f906001600160a01b03163330886138db565b6118ab5760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a4d503a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b6118b3613a18565b6118bb612699565b506000601681905591955093506118d2848661471b565b60055490915081906118ec906001600160a01b0316611aee565b600f546118f9919061471b565b6119039190614774565b600f556119106001613a28565b60135460125491945090600060018314156119325761192d613952565b61196f565b60075461193f908361471b565b905080601281905550876014600082825461195a9190614774565b9091555061196b9050600184614774565b6013555b60408051898152602081018990529081018790527fcf358e925a8e033c6db877f18d10df6f21cd04ef165537bad5fc814eb23af9609060600160405180910390a16005546001546119cd916001600160a01b0390811691168661398b565b6119e95760405162461bcd60e51b8152600401610773906145ff565b60015460405163b5add71760e01b8152600481018a90526024810189905260448101849052606481018390526001600160a01b039091169063b5add71790608401600060405180830381600087803b158015611a4457600080fd5b505af1158015611a58573d6000803e3d6000fd5b50506001546040518781526001600160a01b0390911692506000805160206147cd833981519152915060200160405180910390a25050505080600f541015611adb5760405162461bcd60e51b81526020600482015260166024820152754d4c3a43414e4e4f545f5553455f4452415741424c4560501b6044820152606401610773565b505b9193909250565b6000610897613c0a565b6005546000906001600160a01b03838116911614611b0d576000611b11565b600f545b6004546001600160a01b03848116911614611b2d576000611b31565b6011545b6040516370a0823160e01b81523060048201526001600160a01b038516906370a082319060240160206040518083038186803b158015611b7057600080fd5b505afa158015611b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba891906143f5565b611bb29190614774565b611bbc9190614774565b92915050565b6001546000906001600160a01b03163314611c135760405162461bcd60e51b815260206004820152601160248201527026a61d20a72a1d2727aa2fa622a72222a960791b6044820152606401610773565b611c1f85858585613c34565b90508060155414611c725760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a414e543a434f4d4d49544d454e545f4d49534d415443480000000000006044820152606401610773565b6001600160a01b0385163b611cc95760405162461bcd60e51b815260206004820152601960248201527f4d4c3a414e543a494e56414c49445f524546494e414e434552000000000000006044820152606401610773565b83421115611d195760405162461bcd60e51b815260206004820152601960248201527f4d4c3a414e543a455850495245445f434f4d4d49544d454e54000000000000006044820152606401610773565b600754601254600d54600082611d2f854261471b565b10611d4d57611d3e8484614774565b611d489042614774565b611d50565b60005b6019546040516341a703bb60e01b815260048101859052602481018390529192506001600160a01b03169081906341a703bb90604401600060405180830381600087803b158015611da057600080fd5b505af1158015611db4573d6000803e3d6000fd5b505050506000611dc3426124e3565b90508060166000828254611dd7919061471b565b9091555050600060158190555b88811015611eb45760008c6001600160a01b03168b8b84818110611e0a57611e0a6147a1565b9050602002810190611e1c91906146d4565b604051611e2a929190614553565b600060405180830381855af49150503d8060008114611e65576040519150601f19603f3d011682016040523d82523d6000602084013e611e6a565b606091505b5050905080611eab5760405162461bcd60e51b815260206004820152600d60248201526c13530e9053950e919052531151609a1b6044820152606401610773565b50600101611de4565b507f7150c332bd889236b6ab42cc34f0853631ceb58827f58a8697b682f13e390a8c878c8c8c8c604051611eec9594939291906145c6565b60405180910390a1600554600d5460075497506001600160a01b0390911690611f15884261471b565b601255611f20613a18565b6040516377cf0ddb60e11b815260048101829052602481018990526001600160a01b0385169063ef9e1bb690604401600060405180830381600087803b158015611f6957600080fd5b505af1158015611f7d573d6000803e3d6000fd5b50506040516327d180b560e01b81526001600160a01b03858116600483015260248201859052871692506327d180b59150604401602060405180830381600087803b158015611fcb57600080fd5b505af1158015611fdf573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200391906143f5565b600f60008282546120149190614774565b909155506120229050613c6d565b61206e5760405162461bcd60e51b815260206004820152601e60248201527f4d4c3a414e543a494e53554646494349454e545f434f4c4c41544552414c00006044820152606401610773565b600061207983611aee565b146120c65760405162461bcd60e51b815260206004820152601760248201527f4d4c3a414e543a554e45585045435445445f46554e44530000000000000000006044820152606401610773565b5050505050505050949350505050565b60006120e0612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561211857600080fd5b505afa15801561212c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215091906143ba565b1561216d5760405162461bcd60e51b81526004016107739061462e565b816001600160a01b0316836001600160a01b03167ff1f6a55e7ad487ac8dd8e1d4517348d3b410a7a0bc405ef87b09078dc51b23b66121ab86611aee565b60405181815290945060200160405180910390a36121ca83838361398b565b611bbc5760405162461bcd60e51b815260206004820152601460248201527313530e94ce9514905394d1915497d1905253115160621b6044820152606401610773565b600080612224601454600f54600d54600c546139c8565b601154909150818111612238576000612242565b6122428282614774565b9250505090565b6000612253612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561228b57600080fd5b505afa15801561229f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c391906143ba565b156122e05760405162461bcd60e51b81526004016107739061462e565b6000546001600160a01b031633146123305760405162461bcd60e51b815260206004820152601360248201527226a61d28272a1d2727aa2fa127a92927aba2a960691b6044820152606401610773565b428410156123805760405162461bcd60e51b815260206004820152601760248201527f4d4c3a504e543a494e56414c49445f444541444c494e450000000000000000006044820152606401610773565b7ff94d2f0322894aaf1bce14561461a8b8b6c9b11a77bbe80f20b804da8a95e4b7826123ad5760006123b9565b6123b986868686613c34565b6015819055915081868686866040516123d69594939291906145c6565b60405180910390a1949350505050565b60195460135460405163e0b58e0d60e01b815230600482015260248101919091526000918291829182918291829182916001600160a01b03169063e0b58e0d9060440160806040518083038186803b15801561244157600080fd5b505afa158015612455573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124799190614466565b93509350935093508083838661248f919061471b565b612499919061471b565b6124a3919061471b565b9450601654670de0b6b3a76400006009546014549950896124c49190614755565b6124ce9190614733565b6124d8919061471b565b955050505050909192565b6000611bbc82600754601454600e54600854601354601254600a54600b54613c8d565b6000612510612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561254857600080fd5b505afa15801561255c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061258091906143ba565b1561259d5760405162461bcd60e51b81526004016107739061462e565b6000546001600160a01b03163314806125c057506001546001600160a01b031633145b6125fd5760405162461bcd60e51b815260206004820152600e60248201526d09a9874a49ca8749c9ebe82aaa8960931b6044820152606401610773565b61260985858585613c34565b9050806015541461265c5760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a524e543a434f4d4d49544d454e545f4d49534d415443480000000000006044820152606401610773565b60006015556040517f47244a449377da5fd10e98d86d118dee442e842fc34f05179c973cfcff6acba7906123d690839088908890889088906145c6565b60008060006126a66141e1565b6126ae6141ff565b6126cf42601254600754601454600e54601354600854600a54600b54613cfa565b604082015160208301518351949950929550909350916126ef919061471b565b6126f9919061471b565b6020820151825191955061270c9161471b565b92505050909192565b600061271f6138ac565b6001600160a01b0316633a60339a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561085f57600080fd5b61275f6138ac565b6001600160a01b0316336001600160a01b0316146127b25760405162461bcd60e51b815260206004820152601060248201526f4d4c3a4d3a4e4f545f464143544f525960801b6044820152606401610773565b6127bd838383613e17565b6127f75760405162461bcd60e51b815260206004820152600b60248201526a13530e934e91905253115160aa1b6044820152606401610773565b505050565b60006108976138ac565b6000612810612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561284857600080fd5b505afa15801561285c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288091906143ba565b1561289d5760405162461bcd60e51b81526004016107739061462e565b6000546001600160a01b031633146128ec5760405162461bcd60e51b815260206004820152601260248201527126a61d22231d2727aa2fa127a92927aba2a960711b6044820152606401610773565b816001600160a01b03167f7578fe8c4d9f6fc38fdad20d219b0ce47d38bbf8a72bdb26867809f24119363d8460405161292791815260200190565b60405180910390a2600061293a846112fb565b9050801561297b5760045460009061295a906001600160a01b0316611aee565b905061297781831161296d576000611343565b6104a78284614774565b9250505b83600f600082825461298d9190614774565b90915550506005546129a9906001600160a01b0316848661398b565b6129ed5760405162461bcd60e51b815260206004820152601560248201527413530e91118e9514905394d1915497d19052531151605a1b6044820152606401610773565b6129f5613c6d565b612a415760405162461bcd60e51b815260206004820152601d60248201527f4d4c3a44463a494e53554646494349454e545f434f4c4c41544552414c0000006044820152606401610773565b5092915050565b60008054819081906001600160a01b0316331415612d4157612a68612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015612aa057600080fd5b505afa158015612ab4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad891906143ba565b15612af55760405162461bcd60e51b81526004016107739061462e565b831580612b155750600554612b15906001600160a01b03163330876138db565b612b615760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a434c3a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b60125442811015612bac5760405162461bcd60e51b81526020600482015260156024820152744d4c3a434c3a5041594d454e545f49535f4c41544560581b6044820152606401610773565b612bb4613a18565b612bbc6123e6565b50600060168190559195509350612bd3848661471b565b6005549091508190612bed906001600160a01b0316611aee565b600f54612bfa919061471b565b612c049190614774565b600f55601354612c1390613a28565b9250612c1d613952565b60408051868152602081018690529081018490527f4acb957de3799dd3d95bb7da6bcfbca6f5a33812d69ad37816ed87e79b6327d69060600160405180910390a1600554600154612c7b916001600160a01b0390811691168361398b565b612c975760405162461bcd60e51b8152600401610773906145ff565b60015460405163b5add71760e01b8152600481018790526024810186905260448101849052600060648201526001600160a01b039091169063b5add71790608401600060405180830381600087803b158015612cf257600080fd5b505af1158015612d06573d6000803e3d6000fd5b50506001546040518481526001600160a01b0390911692506000805160206147cd833981519152915060200160405180910390a25050611add565b600f54612d4c612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015612d8457600080fd5b505afa158015612d98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbc91906143ba565b15612dd95760405162461bcd60e51b81526004016107739061462e565b841580612df95750600554612df9906001600160a01b03163330886138db565b612e455760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a434c3a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b60125442811015612e905760405162461bcd60e51b81526020600482015260156024820152744d4c3a434c3a5041594d454e545f49535f4c41544560581b6044820152606401610773565b612e98613a18565b612ea06123e6565b50600060168190559196509450612eb7858761471b565b6005549091508190612ed1906001600160a01b0316611aee565b600f54612ede919061471b565b612ee89190614774565b600f55601354612ef790613a28565b9350612f01613952565b60408051878152602081018790529081018590527f4acb957de3799dd3d95bb7da6bcfbca6f5a33812d69ad37816ed87e79b6327d69060600160405180910390a1600554600154612f5f916001600160a01b0390811691168361398b565b612f7b5760405162461bcd60e51b8152600401610773906145ff565b60015460405163b5add71760e01b8152600481018890526024810187905260448101849052600060648201526001600160a01b039091169063b5add71790608401600060405180830381600087803b158015612fd657600080fd5b505af1158015612fea573d6000803e3d6000fd5b50506001546040518481526001600160a01b0390911692506000805160206147cd833981519152915060200160405180910390a2505080600f541015611adb5760405162461bcd60e51b81526020600482015260166024820152754d4c3a43414e4e4f545f5553455f4452415741424c4560501b6044820152606401610773565b60006130756141e1565b61307d6141ff565b61309e42601254600754601454600e54601354600854600a54600b54613cfa565b91959094509092509050565b6130b2612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b1580156130ea57600080fd5b505afa1580156130fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312291906143ba565b1561313f5760405162461bcd60e51b81526004016107739061462e565b6000546001600160a01b0316331461318e5760405162461bcd60e51b815260206004820152601260248201527126a61d29219d2727aa2fa127a92927aba2a960711b6044820152606401610773565b806001600160a01b03167f97b446ee2df422b7273fe6d658674835f9de3319d131c229f9a2f8ed62a76193836040516131c991815260200190565b60405180910390a281601160008282546131e39190614774565b90915550506004546131ff906001600160a01b0316828461398b565b6132435760405162461bcd60e51b815260206004820152601560248201527413530e9490ce9514905394d1915497d19052531151605a1b6044820152606401610773565b61324b613c6d565b6132975760405162461bcd60e51b815260206004820152601d60248201527f4d4c3a52433a494e53554646494349454e545f434f4c4c41544552414c0000006044820152606401610773565b5050565b6012546001546001600160a01b031633146132eb5760405162461bcd60e51b815260206004820152601060248201526f26a61d24a61d2727aa2fa622a72222a960811b6044820152606401610773565b60008142116132fa57426132fc565b815b90507f54c4bb2a061eac3afc1daf65bd7a75a0cdb4ac02824757f40019dff2da5849358160405161332f91815260200190565b60405180910390a1601255601a55565b6133476138ac565b6001600160a01b0316336001600160a01b03161461339b5760405162461bcd60e51b81526020600482015260116024820152704d4c3a53493a4e4f545f464143544f525960781b6044820152606401610773565b6001600160a01b03167f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b50565b600180546001600160a01b0319166001600160a01b03831690811790915560009061342f5760405162461bcd60e51b815260206004820152601460248201527326a61d23261d24a72b20a624a22fa622a72222a960611b6044820152606401610773565b6000826001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b15801561346a57600080fd5b505afa15801561347e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a29190614283565b90506134ac612715565b604051636167f93160e01b81526b2627a0a72fa6a0a720a3a2a960a11b60048201526001600160a01b0383811660248301529190911690636167f9319060440160206040518083038186803b15801561350457600080fd5b505afa158015613518573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061353c91906143ba565b6135805760405162461bcd60e51b81526020600482015260156024820152744d4c3a464c3a494e56414c49445f464143544f525960581b6044820152606401610773565b6040516335a2735f60e11b81526001600160a01b038481166004830152821690636b44e6be9060240160206040518083038186803b1580156135c157600080fd5b505afa1580156135d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f991906143ba565b61363e5760405162461bcd60e51b81526020600482015260166024820152754d4c3a464c3a494e56414c49445f494e5354414e434560501b6044820152606401610773565b60125415801561364f575060135415155b61368f5760405162461bcd60e51b81526020600482015260116024820152704d4c3a464c3a4c4f414e5f41435449564560781b6044820152606401610773565b600554600754600d546019546001600160a01b03938416936136b691859116600019613e90565b6136f75760405162461bcd60e51b815260206004820152601260248201527113530e91930e9054141493d59157d190525360721b6044820152606401610773565b6019546040516377cf0ddb60e11b815260048101839052602481018490526001600160a01b039091169063ef9e1bb690604401600060405180830381600087803b15801561374457600080fd5b505af1158015613758573d6000803e3d6000fd5b50506019546040516327d180b560e01b81526001600160a01b038781166004830152602482018690526000945090911691506327d180b590604401602060405180830381600087803b1580156137ad57600080fd5b505af11580156137c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e591906143f5565b90506137f18183614774565b600f5560006137ff85611aee565b146138455760405162461bcd60e51b81526020600482015260166024820152754d4c3a464c3a554e45585045435445445f46554e445360501b6044820152606401610773565b866001600160a01b03167fcd909ec339185c4598a4096e174308fbdf136d117f230960f873a2f2e81f63af8360148190559750878542613885919061471b565b60128190556040805192835260208301919091520160405180910390a25050505050919050565b60006138d67f7a45a402e4cb6e08ebc196f20f66d5d30e67285a2a8aa80503fa409e727a4af15490565b919050565b6040516001600160a01b03808516602483015283166044820152606481018290526000906139499086906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613f0c565b95945050505050565b60006006819055600781905560088190556009819055600a819055600b819055600e819055601281905560138190556014819055601a55565b6040516001600160a01b0383166024820152604481018290526000906139be90859063a9059cbb60e01b90606401613912565b90505b9392505050565b600083851115613a0d57826001816139e08789614774565b6139ea9086614755565b6139f4919061471b565b6139fe9190614774565b613a089190614733565b613949565b506000949350505050565b601a54613a2157565b6000601a55565b6005546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a082319060240160206040518083038186803b158015613a7057600080fd5b505afa158015613a84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa891906143f5565b6019546005546040516376bd6e5160e01b81526001600160a01b0391821660048201526024810187905292935016906376bd6e5190604401602060405180830381600087803b158015613afa57600080fd5b505af1158015613b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b3291906143f5565b506005546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015613b7757600080fd5b505afa158015613b8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613baf91906143f5565b905080821115613be257613bc38183614774565b925082600f6000828254613bd79190614774565b90915550613c039050565b613bec8282614774565b600f6000828254613bfd919061471b565b90915550505b5050919050565b60006138d67f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b600084848484604051602001613c4d949392919061459e565b604051602081830303815290604052805190602001209050949350505050565b6000613c83601454600f54600d54600c546139c8565b6011541015905090565b600083613c9a8a8c61471b565b1015613ca857506000613ced565b6000613cb48a86614774565b613cbe908c614774565b9050613ccd898989848a613fac565b9250613cdf90508b8a8988888861409f565b613ce9908361471b565b9150505b9998505050505050505050565b6000613d046141e1565b613d0c6141ff565b613d198989888d8b613fac565b8352925060018714613d2b5782613d2d565b885b9250613d3d8c8a888e898961409f565b8260016020020152601654826002602002015260195460405163e0b58e0d60e01b8152306004820152600160248201526000918291829182916001600160a01b039091169063e0b58e0d9060440160806040518083038186803b158015613da357600080fd5b505afa158015613db7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ddb9190614466565b93509350935093508284613def919061471b565b8552613dfb818361471b565b602086015250949e939d50919b50919950505050505050505050565b6000833b80613e2a5760009150506139c1565b846001600160a01b03168484604051613e44929190614553565b600060405180830381855af49150503d8060008114613e7f576040519150601f19603f3d011682016040523d82523d6000602084013e613e84565b606091505b50909695505050505050565b6040516001600160a01b038316602482015260006044820181905290613ec390859063095ea7b360e01b90606401613912565b613ecf575060006139c1565b81613edc575060016139c1565b6040516001600160a01b0384166024820152604481018390526139be90859063095ea7b360e01b90606401613912565b60006001600160a01b0383163b613f2557506000611bbc565b6060836001600160a01b031683604051613f3f9190614563565b6000604051808303816000865af19150503d8060008114613f7c576040519150601f19603f3d011682016040523d82523d6000602084013e613f81565b606091505b50909250905081801561133b57508051158061133b57508080602001905181019061133b91906143ba565b6000806000613fbb868661413b565b90506000613fe3613fd483670de0b6b3a764000061471b565b86670de0b6b3a7640000614156565b9050670de0b6b3a764000081116140165784613fff898b614774565b6140099190614733565b6000935093505050614095565b600061402a670de0b6b3a764000083614774565b838a670de0b6b3a764000061403f868f614755565b6140499190614733565b6140539190614774565b61405d9190614755565b6140679190614733565b90506140748a89896141b8565b93508381101561408557600061408f565b61408f8482614774565b94505050505b9550959350505050565b60008387116140b057506000614131565b6000620151806140c0868a614774565b6140cd906201517f61471b565b6140d79190614733565b6140e49062015180614755565b90506140fa876140f4858961471b565b836141b8565b614104908361471b565b9150670de0b6b3a76400006141198886614755565b6141239190614733565b61412d908361471b565b9150505b9695505050505050565b60006301e1338061414c8385614755565b6139c19190614733565b6000600183166141665781614168565b835b90505b60019290921c9182156139c157816141838580614755565b61418d9190614733565b93506001831661419c5761416b565b816141a78583614755565b6141b19190614733565b905061416b565b6000670de0b6b3a76400006141cd848461413b565b6141d79086614755565b6139be9190614733565b60405180606001604052806003906020820280368337509192915050565b60405180604001604052806002906020820280368337509192915050565b60008083601f84011261422f57600080fd5b50813567ffffffffffffffff81111561424757600080fd5b60208301915083602082850101111561425f57600080fd5b9250929050565b60006020828403121561427857600080fd5b81356139c1816147b7565b60006020828403121561429557600080fd5b81516139c1816147b7565b600080604083850312156142b357600080fd5b82356142be816147b7565b915060208301356142ce816147b7565b809150509250929050565b6000806000604084860312156142ee57600080fd5b83356142f9816147b7565b9250602084013567ffffffffffffffff81111561431557600080fd5b6143218682870161421d565b9497909650939450505050565b6000806000806060858703121561434457600080fd5b843561434f816147b7565b935060208501359250604085013567ffffffffffffffff8082111561437357600080fd5b818701915087601f83011261438757600080fd5b81358181111561439657600080fd5b8860208260051b85010111156143ab57600080fd5b95989497505060200194505050565b6000602082840312156143cc57600080fd5b815180151581146139c157600080fd5b6000602082840312156143ee57600080fd5b5035919050565b60006020828403121561440757600080fd5b5051919050565b6000806040838503121561442157600080fd5b8235915060208301356142ce816147b7565b60008060006040848603121561444857600080fd5b83359250602084013567ffffffffffffffff81111561431557600080fd5b6000806000806080858703121561447c57600080fd5b505082516020840151604085015160609095015191969095509092509050565b818352600060208085019450848460051b86018460005b8781101561451d5783830389528135601e198836030181126144d457600080fd5b8701803567ffffffffffffffff8111156144ed57600080fd5b8036038913156144fc57600080fd5b614509858289850161452a565b9a87019a94505050908401906001016144b3565b5090979650505050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8183823760009101908152919050565b6000825160005b81811015614584576020818601810151858301520161456a565b81811115614593576000828501525b509190910192915050565b60018060a01b038516815283602082015260606040820152600061413160608301848661449c565b85815260018060a01b03851660208201528360408201526080606082015260006145f460808301848661449c565b979650505050505050565b60208082526015908201527413530e93540e9514905394d1915497d19052531151605a1b604082015260600190565b602080825260119082015270130e941493d513d0d3d317d4105554d151607a1b604082015260600190565b83815260c0810160208083018560005b600381101561468657815183529183019190830190600101614669565b505050608083018460005b60028110156146ae57815183529183019190830190600101614691565b50505050949350505050565b83815260406020820152600061394960408301848661452a565b6000808335601e198436030181126146eb57600080fd5b83018035915067ffffffffffffffff82111561470657600080fd5b60200191503681900382131561425f57600080fd5b6000821982111561472e5761472e61478b565b500190565b60008261475057634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561476f5761476f61478b565b500290565b6000828210156147865761478661478b565b500390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6001600160a01b03811681146133c857600080fdfe6bd56533ce1c8ea03f7b858ac441b5a86d140a793a7c9e3faecbbe517c2c8791a26469706673582212204a309c37cbae06ae4046df36b05aa1ac996ec534c14d5709848916960b7ff5da64736f6c63430008070033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103835760003560e01c80637c3a00fd116101de578063ba5d30781161010f578063d05951a0116100ad578063d4754d5f1161007c578063d4754d5f146106a8578063d784d426146106b0578063d8dfeb45146106c3578063e48f6faf146106cb57600080fd5b8063d05951a01461065a578063d0fb02031461066d578063d3bcd5e21461067e578063d41ddc961461069557600080fd5b8063c3124525116100e9578063c312452514610624578063c3fbb6fd1461062c578063c45a01551461063f578063ccc044841461064757600080fd5b8063ba5d307814610603578063ba83276b1461060b578063bcead63e1461061357600080fd5b8063a29d7aab1161017c578063acb522b411610156578063acb522b4146105d8578063b86a513e146105eb578063b96b5c99146105f3578063b9b1f4e3146105fb57600080fd5b8063a29d7aab146105ac578063a97d1161146105bf578063aabaecd6146105c757600080fd5b80638ffc9215116101b85780638ffc92151461058157806396663914146105895780639e10320b14610591578063a06db7dc146105a457600080fd5b80637c3a00fd146105555780637df1f1b91461055d57806387accaf11461056e57600080fd5b806345755dd6116102b85780636174b27211610256578063712b772f11610230578063712b772f1461052a57806375a206761461053d57806377b3c55c146105455780637a0e6fa11461054d57600080fd5b80636174b272146104f3578063700f50061461050657806370a10c891461051757600080fd5b806350f2012f1161029257806350f2012f146104995780635114cb52146104ac5780635c60da1b146104da5780635eeb53b4146104e257600080fd5b806345755dd61461044b57806347350e9f1461045e5780634eac42351461048657600080fd5b8063227000371161032557806339ba9f86116102ff57806339ba9f861461041757806339d65834146104285780633b99bcee146104305780634003f34d1461044357600080fd5b806322700037146103f4578063267f4ac3146103fc5780632ead10981461040f57600080fd5b80630fe3d9b7116103615780630fe3d9b7146103c9578063144ee4b5146103d15780631cc1cf46146103d95780631f3f19ab146103e157600080fd5b806301daa38f146103885780630895326f146103925780630c340a24146103a9575b600080fd5b6103906106de565b005b6013545b6040519081526020015b60405180910390f35b6103b161081d565b6040516001600160a01b0390911681526020016103a0565b61039061089c565b6103906109d4565b600754610396565b6103906103ef366004614266565b610aec565b601a54610396565b61039061040a366004614266565b610cee565b600b54610396565b6005546001600160a01b03166103b1565b600954610396565b61039061043e366004614433565b610d8a565b601254610396565b6103966104593660046143dc565b610fa0565b61047161046c366004614266565b61110a565b604080519283526020830191909152016103a0565b6103966104943660046143dc565b6112fb565b6103966104a73660046143dc565b611343565b6104bf6104ba3660046143dc565b6114a4565b604080519384526020840192909252908201526060016103a0565b6103b1611ae4565b6003546001600160a01b03166103b1565b610396610501366004614266565b611aee565b6002546001600160a01b03166103b1565b61039661052536600461432e565b611bc2565b6103966105383660046142a0565b6120d6565b600c54610396565b600a54610396565b61039661220d565b600854610396565b6000546001600160a01b03166103b1565b61039661057c36600461432e565b612249565b600d54610396565b6104bf6123e6565b61039661059f3660046143dc565b6124e3565b600654610396565b601a5460405190151581526020016103a0565b601654610396565b6004546001600160a01b03166103b1565b6103966105e636600461432e565b612506565b600e54610396565b6104bf612699565b600f54610396565b601454610396565b601554610396565b6001546001600160a01b03166103b1565b6103b1612715565b61039061063a3660046142d9565b612757565b6103b16127fc565b61039661065536600461440e565b612806565b6104bf6106683660046143dc565b612a48565b6019546001600160a01b03166103b1565b61068661306b565b6040516103a093929190614659565b6103906106a336600461440e565b6130aa565b61039061329b565b6103906106be366004614266565b61333f565b601154610396565b6103966106d9366004614266565b6133cb565b6106e6612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561071e57600080fd5b505afa158015610732573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075691906143ba565b1561077c5760405162461bcd60e51b81526004016107739061462e565b60405180910390fd5b6002546001600160a01b031633146107d65760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a41423a4e4f545f50454e44494e475f424f52524f5745520000000000006044820152606401610773565b600280546001600160a01b031990811690915560008054339216821781556040517f29bac0ac2b15405bfcc160bb74b6ae7a559b7674ce33db80785ada73e38204d29190a2565b6000610827612715565b6001600160a01b0316630c340a246040518163ffffffff1660e01b815260040160206040518083038186803b15801561085f57600080fd5b505afa158015610873573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108979190614283565b905090565b6108a4612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b1580156108dc57600080fd5b505afa1580156108f0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091491906143ba565b156109315760405162461bcd60e51b81526004016107739061462e565b6003546001600160a01b0316331461098b5760405162461bcd60e51b815260206004820152601860248201527f4d4c3a414c3a4e4f545f50454e44494e475f4c454e44455200000000000000006044820152606401610773565b600380546001600160a01b031990811690915560018054339216821790556040517fd6165838d2e3db87aa1002b548048673fc6427eefbd1b914e100f3a0deae23e390600090a2565b601a546001546001600160a01b03163314610a255760405162461bcd60e51b815260206004820152601160248201527026a61d2926249d2727aa2fa622a72222a960791b6044820152606401610773565b80610a685760405162461bcd60e51b815260206004820152601360248201527213530e9493124e9393d517d253541052549151606a1b6044820152606401610773565b80421115610aab5760405162461bcd60e51b815260206004820152601060248201526f4d4c3a524c493a504153545f4441544560801b6044820152606401610773565b60128190556000601a556040518181527f962d5a38dc48af765ecb4f177a88713b592b5bf59e64f497ab33af13b7c0e9de906020015b60405180910390a150565b610af4612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015610b2c57600080fd5b505afa158015610b40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6491906143ba565b15610b815760405162461bcd60e51b81526004016107739061462e565b6000546001600160a01b03163314610bd15760405162461bcd60e51b815260206004820152601360248201527226a61d29a8211d2727aa2fa127a92927aba2a960691b6044820152606401610773565b610bd9612715565b60405163eaf6e48360e01b81526001600160a01b038381166004830152919091169063eaf6e4839060240160206040518083038186803b158015610c1c57600080fd5b505afa158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5491906143ba565b610ca05760405162461bcd60e51b815260206004820152601760248201527f4d4c3a5350423a494e56414c49445f424f52524f5745520000000000000000006044820152606401610773565b600280546001600160a01b0319166001600160a01b0383169081179091556040519081527f10f06072822ef73860fedb88933f968d20bb4aadce8a8d360d1124cb6ce1e0b290602001610ae1565b6001546001600160a01b03163314610d3c5760405162461bcd60e51b815260206004820152601160248201527026a61d29a8261d2727aa2fa622a72222a960791b6044820152606401610773565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527fa3ab02442c80a4102475683f16513c9139a89142be9db9804edfcfbb379fc49290602001610ae1565b610d92612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015610dca57600080fd5b505afa158015610dde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0291906143ba565b15610e1f5760405162461bcd60e51b81526004016107739061462e565b610e27612715565b6001600160a01b031663be7c13f76040518163ffffffff1660e01b815260040160206040518083038186803b158015610e5f57600080fd5b505afa158015610e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e979190614283565b6001600160a01b0316336001600160a01b031614610ef75760405162461bcd60e51b815260206004820152601760248201527f4d4c3a553a4e4f545f53454355524954595f41444d494e0000000000000000006044820152606401610773565b7faaaa7ee6b0c2f4ee1fa7312c7d5b3623a434da5a1a9ce3cb6e629caa23454ab6838383604051610f2a939291906146ba565b60405180910390a1610f3a6138ac565b6001600160a01b031663fe69f7088484846040518463ffffffff1660e01b8152600401610f69939291906146ba565b600060405180830381600087803b158015610f8357600080fd5b505af1158015610f97573d6000803e3d6000fd5b50505050505050565b6000610faa612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015610fe257600080fd5b505afa158015610ff6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101a91906143ba565b156110375760405162461bcd60e51b81526004016107739061462e565b8115806110575750600554611057906001600160a01b03163330856138db565b6110a35760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a52463a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b6005546110b8906001600160a01b0316611aee565b905080600f60008282546110cc919061471b565b90915550506040518181527f278e51d3323fbf18b9fb8df3f8b97e31b145bc1146c52e764cf4aa1bfc4ba17d906020015b60405180910390a1919050565b60015460009081906001600160a01b0316331461115b5760405162461bcd60e51b815260206004820152600f60248201526e26a61d291d2727aa2fa622a72222a960891b6044820152606401610773565b60125480158015906111785750600654611175908261471b565b42115b6111ba5760405162461bcd60e51b815260206004820152601360248201527213530e948e9393d517d25397d1115190555315606a1b6044820152606401610773565b6111c2613952565b60006011819055600f8190556004546001600160a01b0316906111e482611aee565b94508414806111f957506111f981868661398b565b61123e5760405162461bcd60e51b815260206004820152601660248201527513530e948e90d7d514905394d1915497d1905253115160521b6044820152606401610773565b6005546001600160a01b0316600061125582611aee565b945084148061126a575061126a81878661398b565b6112af5760405162461bcd60e51b815260206004820152601660248201527513530e948e9197d514905394d1915497d1905253115160521b6044820152606401610773565b60408051868152602081018690526001600160a01b038816917f027e623aab0b174da270ff529cad1c54f09182651e07437d2ac557929b9e5b49910160405180910390a2505050915091565b60008061131d60145484600f546113129190614774565b600d54600c546139c8565b60115490915080821161133157600061133b565b61133b8183614774565b949350505050565b600061134d612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561138557600080fd5b505afa158015611399573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bd91906143ba565b156113da5760405162461bcd60e51b81526004016107739061462e565b8115806113fa57506004546113fa906001600160a01b03163330856138db565b6114465760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a50433a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b60045461145b906001600160a01b0316611aee565b9050806011600082825461146f919061471b565b90915550506040518181527f437d44b2c697fb69e2b2f25f57fd844e376c25ed28ed5a9c4be88aa1e5c87d12906020016110fd565b60008054819081906001600160a01b03163314156117a7576114c4612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b1580156114fc57600080fd5b505afa158015611510573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153491906143ba565b156115515760405162461bcd60e51b81526004016107739061462e565b8315806115715750600554611571906001600160a01b03163330876138db565b6115bd5760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a4d503a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b6115c5613a18565b6115cd612699565b506000601681905591945092506115e4838561471b565b60055490915081906115fe906001600160a01b0316611aee565b600f5461160b919061471b565b6116159190614774565b600f556116226001613a28565b60135460125491935090600060018314156116445761163f613952565b611681565b600754611651908361471b565b905080601281905550866014600082825461166c9190614774565b9091555061167d9050600184614774565b6013555b60408051888152602081018890529081018690527fcf358e925a8e033c6db877f18d10df6f21cd04ef165537bad5fc814eb23af9609060600160405180910390a16005546001546116df916001600160a01b0390811691168661398b565b6116fb5760405162461bcd60e51b8152600401610773906145ff565b60015460405163b5add71760e01b8152600481018990526024810188905260448101849052606481018390526001600160a01b039091169063b5add71790608401600060405180830381600087803b15801561175657600080fd5b505af115801561176a573d6000803e3d6000fd5b50506001546040518781526001600160a01b0390911692506000805160206147cd833981519152915060200160405180910390a250505050611add565b600f546117b2612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b1580156117ea57600080fd5b505afa1580156117fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061182291906143ba565b1561183f5760405162461bcd60e51b81526004016107739061462e565b84158061185f575060055461185f906001600160a01b03163330886138db565b6118ab5760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a4d503a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b6118b3613a18565b6118bb612699565b506000601681905591955093506118d2848661471b565b60055490915081906118ec906001600160a01b0316611aee565b600f546118f9919061471b565b6119039190614774565b600f556119106001613a28565b60135460125491945090600060018314156119325761192d613952565b61196f565b60075461193f908361471b565b905080601281905550876014600082825461195a9190614774565b9091555061196b9050600184614774565b6013555b60408051898152602081018990529081018790527fcf358e925a8e033c6db877f18d10df6f21cd04ef165537bad5fc814eb23af9609060600160405180910390a16005546001546119cd916001600160a01b0390811691168661398b565b6119e95760405162461bcd60e51b8152600401610773906145ff565b60015460405163b5add71760e01b8152600481018a90526024810189905260448101849052606481018390526001600160a01b039091169063b5add71790608401600060405180830381600087803b158015611a4457600080fd5b505af1158015611a58573d6000803e3d6000fd5b50506001546040518781526001600160a01b0390911692506000805160206147cd833981519152915060200160405180910390a25050505080600f541015611adb5760405162461bcd60e51b81526020600482015260166024820152754d4c3a43414e4e4f545f5553455f4452415741424c4560501b6044820152606401610773565b505b9193909250565b6000610897613c0a565b6005546000906001600160a01b03838116911614611b0d576000611b11565b600f545b6004546001600160a01b03848116911614611b2d576000611b31565b6011545b6040516370a0823160e01b81523060048201526001600160a01b038516906370a082319060240160206040518083038186803b158015611b7057600080fd5b505afa158015611b84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba891906143f5565b611bb29190614774565b611bbc9190614774565b92915050565b6001546000906001600160a01b03163314611c135760405162461bcd60e51b815260206004820152601160248201527026a61d20a72a1d2727aa2fa622a72222a960791b6044820152606401610773565b611c1f85858585613c34565b90508060155414611c725760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a414e543a434f4d4d49544d454e545f4d49534d415443480000000000006044820152606401610773565b6001600160a01b0385163b611cc95760405162461bcd60e51b815260206004820152601960248201527f4d4c3a414e543a494e56414c49445f524546494e414e434552000000000000006044820152606401610773565b83421115611d195760405162461bcd60e51b815260206004820152601960248201527f4d4c3a414e543a455850495245445f434f4d4d49544d454e54000000000000006044820152606401610773565b600754601254600d54600082611d2f854261471b565b10611d4d57611d3e8484614774565b611d489042614774565b611d50565b60005b6019546040516341a703bb60e01b815260048101859052602481018390529192506001600160a01b03169081906341a703bb90604401600060405180830381600087803b158015611da057600080fd5b505af1158015611db4573d6000803e3d6000fd5b505050506000611dc3426124e3565b90508060166000828254611dd7919061471b565b9091555050600060158190555b88811015611eb45760008c6001600160a01b03168b8b84818110611e0a57611e0a6147a1565b9050602002810190611e1c91906146d4565b604051611e2a929190614553565b600060405180830381855af49150503d8060008114611e65576040519150601f19603f3d011682016040523d82523d6000602084013e611e6a565b606091505b5050905080611eab5760405162461bcd60e51b815260206004820152600d60248201526c13530e9053950e919052531151609a1b6044820152606401610773565b50600101611de4565b507f7150c332bd889236b6ab42cc34f0853631ceb58827f58a8697b682f13e390a8c878c8c8c8c604051611eec9594939291906145c6565b60405180910390a1600554600d5460075497506001600160a01b0390911690611f15884261471b565b601255611f20613a18565b6040516377cf0ddb60e11b815260048101829052602481018990526001600160a01b0385169063ef9e1bb690604401600060405180830381600087803b158015611f6957600080fd5b505af1158015611f7d573d6000803e3d6000fd5b50506040516327d180b560e01b81526001600160a01b03858116600483015260248201859052871692506327d180b59150604401602060405180830381600087803b158015611fcb57600080fd5b505af1158015611fdf573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061200391906143f5565b600f60008282546120149190614774565b909155506120229050613c6d565b61206e5760405162461bcd60e51b815260206004820152601e60248201527f4d4c3a414e543a494e53554646494349454e545f434f4c4c41544552414c00006044820152606401610773565b600061207983611aee565b146120c65760405162461bcd60e51b815260206004820152601760248201527f4d4c3a414e543a554e45585045435445445f46554e44530000000000000000006044820152606401610773565b5050505050505050949350505050565b60006120e0612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561211857600080fd5b505afa15801561212c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215091906143ba565b1561216d5760405162461bcd60e51b81526004016107739061462e565b816001600160a01b0316836001600160a01b03167ff1f6a55e7ad487ac8dd8e1d4517348d3b410a7a0bc405ef87b09078dc51b23b66121ab86611aee565b60405181815290945060200160405180910390a36121ca83838361398b565b611bbc5760405162461bcd60e51b815260206004820152601460248201527313530e94ce9514905394d1915497d1905253115160621b6044820152606401610773565b600080612224601454600f54600d54600c546139c8565b601154909150818111612238576000612242565b6122428282614774565b9250505090565b6000612253612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561228b57600080fd5b505afa15801561229f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c391906143ba565b156122e05760405162461bcd60e51b81526004016107739061462e565b6000546001600160a01b031633146123305760405162461bcd60e51b815260206004820152601360248201527226a61d28272a1d2727aa2fa127a92927aba2a960691b6044820152606401610773565b428410156123805760405162461bcd60e51b815260206004820152601760248201527f4d4c3a504e543a494e56414c49445f444541444c494e450000000000000000006044820152606401610773565b7ff94d2f0322894aaf1bce14561461a8b8b6c9b11a77bbe80f20b804da8a95e4b7826123ad5760006123b9565b6123b986868686613c34565b6015819055915081868686866040516123d69594939291906145c6565b60405180910390a1949350505050565b60195460135460405163e0b58e0d60e01b815230600482015260248101919091526000918291829182918291829182916001600160a01b03169063e0b58e0d9060440160806040518083038186803b15801561244157600080fd5b505afa158015612455573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124799190614466565b93509350935093508083838661248f919061471b565b612499919061471b565b6124a3919061471b565b9450601654670de0b6b3a76400006009546014549950896124c49190614755565b6124ce9190614733565b6124d8919061471b565b955050505050909192565b6000611bbc82600754601454600e54600854601354601254600a54600b54613c8d565b6000612510612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561254857600080fd5b505afa15801561255c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061258091906143ba565b1561259d5760405162461bcd60e51b81526004016107739061462e565b6000546001600160a01b03163314806125c057506001546001600160a01b031633145b6125fd5760405162461bcd60e51b815260206004820152600e60248201526d09a9874a49ca8749c9ebe82aaa8960931b6044820152606401610773565b61260985858585613c34565b9050806015541461265c5760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a524e543a434f4d4d49544d454e545f4d49534d415443480000000000006044820152606401610773565b60006015556040517f47244a449377da5fd10e98d86d118dee442e842fc34f05179c973cfcff6acba7906123d690839088908890889088906145c6565b60008060006126a66141e1565b6126ae6141ff565b6126cf42601254600754601454600e54601354600854600a54600b54613cfa565b604082015160208301518351949950929550909350916126ef919061471b565b6126f9919061471b565b6020820151825191955061270c9161471b565b92505050909192565b600061271f6138ac565b6001600160a01b0316633a60339a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561085f57600080fd5b61275f6138ac565b6001600160a01b0316336001600160a01b0316146127b25760405162461bcd60e51b815260206004820152601060248201526f4d4c3a4d3a4e4f545f464143544f525960801b6044820152606401610773565b6127bd838383613e17565b6127f75760405162461bcd60e51b815260206004820152600b60248201526a13530e934e91905253115160aa1b6044820152606401610773565b505050565b60006108976138ac565b6000612810612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b15801561284857600080fd5b505afa15801561285c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061288091906143ba565b1561289d5760405162461bcd60e51b81526004016107739061462e565b6000546001600160a01b031633146128ec5760405162461bcd60e51b815260206004820152601260248201527126a61d22231d2727aa2fa127a92927aba2a960711b6044820152606401610773565b816001600160a01b03167f7578fe8c4d9f6fc38fdad20d219b0ce47d38bbf8a72bdb26867809f24119363d8460405161292791815260200190565b60405180910390a2600061293a846112fb565b9050801561297b5760045460009061295a906001600160a01b0316611aee565b905061297781831161296d576000611343565b6104a78284614774565b9250505b83600f600082825461298d9190614774565b90915550506005546129a9906001600160a01b0316848661398b565b6129ed5760405162461bcd60e51b815260206004820152601560248201527413530e91118e9514905394d1915497d19052531151605a1b6044820152606401610773565b6129f5613c6d565b612a415760405162461bcd60e51b815260206004820152601d60248201527f4d4c3a44463a494e53554646494349454e545f434f4c4c41544552414c0000006044820152606401610773565b5092915050565b60008054819081906001600160a01b0316331415612d4157612a68612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015612aa057600080fd5b505afa158015612ab4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ad891906143ba565b15612af55760405162461bcd60e51b81526004016107739061462e565b831580612b155750600554612b15906001600160a01b03163330876138db565b612b615760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a434c3a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b60125442811015612bac5760405162461bcd60e51b81526020600482015260156024820152744d4c3a434c3a5041594d454e545f49535f4c41544560581b6044820152606401610773565b612bb4613a18565b612bbc6123e6565b50600060168190559195509350612bd3848661471b565b6005549091508190612bed906001600160a01b0316611aee565b600f54612bfa919061471b565b612c049190614774565b600f55601354612c1390613a28565b9250612c1d613952565b60408051868152602081018690529081018490527f4acb957de3799dd3d95bb7da6bcfbca6f5a33812d69ad37816ed87e79b6327d69060600160405180910390a1600554600154612c7b916001600160a01b0390811691168361398b565b612c975760405162461bcd60e51b8152600401610773906145ff565b60015460405163b5add71760e01b8152600481018790526024810186905260448101849052600060648201526001600160a01b039091169063b5add71790608401600060405180830381600087803b158015612cf257600080fd5b505af1158015612d06573d6000803e3d6000fd5b50506001546040518481526001600160a01b0390911692506000805160206147cd833981519152915060200160405180910390a25050611add565b600f54612d4c612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015612d8457600080fd5b505afa158015612d98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbc91906143ba565b15612dd95760405162461bcd60e51b81526004016107739061462e565b841580612df95750600554612df9906001600160a01b03163330886138db565b612e455760405162461bcd60e51b815260206004820152601a60248201527f4d4c3a434c3a5452414e534645525f46524f4d5f4641494c45440000000000006044820152606401610773565b60125442811015612e905760405162461bcd60e51b81526020600482015260156024820152744d4c3a434c3a5041594d454e545f49535f4c41544560581b6044820152606401610773565b612e98613a18565b612ea06123e6565b50600060168190559196509450612eb7858761471b565b6005549091508190612ed1906001600160a01b0316611aee565b600f54612ede919061471b565b612ee89190614774565b600f55601354612ef790613a28565b9350612f01613952565b60408051878152602081018790529081018590527f4acb957de3799dd3d95bb7da6bcfbca6f5a33812d69ad37816ed87e79b6327d69060600160405180910390a1600554600154612f5f916001600160a01b0390811691168361398b565b612f7b5760405162461bcd60e51b8152600401610773906145ff565b60015460405163b5add71760e01b8152600481018890526024810187905260448101849052600060648201526001600160a01b039091169063b5add71790608401600060405180830381600087803b158015612fd657600080fd5b505af1158015612fea573d6000803e3d6000fd5b50506001546040518481526001600160a01b0390911692506000805160206147cd833981519152915060200160405180910390a2505080600f541015611adb5760405162461bcd60e51b81526020600482015260166024820152754d4c3a43414e4e4f545f5553455f4452415741424c4560501b6044820152606401610773565b60006130756141e1565b61307d6141ff565b61309e42601254600754601454600e54601354600854600a54600b54613cfa565b91959094509092509050565b6130b2612715565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b1580156130ea57600080fd5b505afa1580156130fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312291906143ba565b1561313f5760405162461bcd60e51b81526004016107739061462e565b6000546001600160a01b0316331461318e5760405162461bcd60e51b815260206004820152601260248201527126a61d29219d2727aa2fa127a92927aba2a960711b6044820152606401610773565b806001600160a01b03167f97b446ee2df422b7273fe6d658674835f9de3319d131c229f9a2f8ed62a76193836040516131c991815260200190565b60405180910390a281601160008282546131e39190614774565b90915550506004546131ff906001600160a01b0316828461398b565b6132435760405162461bcd60e51b815260206004820152601560248201527413530e9490ce9514905394d1915497d19052531151605a1b6044820152606401610773565b61324b613c6d565b6132975760405162461bcd60e51b815260206004820152601d60248201527f4d4c3a52433a494e53554646494349454e545f434f4c4c41544552414c0000006044820152606401610773565b5050565b6012546001546001600160a01b031633146132eb5760405162461bcd60e51b815260206004820152601060248201526f26a61d24a61d2727aa2fa622a72222a960811b6044820152606401610773565b60008142116132fa57426132fc565b815b90507f54c4bb2a061eac3afc1daf65bd7a75a0cdb4ac02824757f40019dff2da5849358160405161332f91815260200190565b60405180910390a1601255601a55565b6133476138ac565b6001600160a01b0316336001600160a01b03161461339b5760405162461bcd60e51b81526020600482015260116024820152704d4c3a53493a4e4f545f464143544f525960781b6044820152606401610773565b6001600160a01b03167f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55565b50565b600180546001600160a01b0319166001600160a01b03831690811790915560009061342f5760405162461bcd60e51b815260206004820152601460248201527326a61d23261d24a72b20a624a22fa622a72222a960611b6044820152606401610773565b6000826001600160a01b031663c45a01556040518163ffffffff1660e01b815260040160206040518083038186803b15801561346a57600080fd5b505afa15801561347e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134a29190614283565b90506134ac612715565b604051636167f93160e01b81526b2627a0a72fa6a0a720a3a2a960a11b60048201526001600160a01b0383811660248301529190911690636167f9319060440160206040518083038186803b15801561350457600080fd5b505afa158015613518573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061353c91906143ba565b6135805760405162461bcd60e51b81526020600482015260156024820152744d4c3a464c3a494e56414c49445f464143544f525960581b6044820152606401610773565b6040516335a2735f60e11b81526001600160a01b038481166004830152821690636b44e6be9060240160206040518083038186803b1580156135c157600080fd5b505afa1580156135d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f991906143ba565b61363e5760405162461bcd60e51b81526020600482015260166024820152754d4c3a464c3a494e56414c49445f494e5354414e434560501b6044820152606401610773565b60125415801561364f575060135415155b61368f5760405162461bcd60e51b81526020600482015260116024820152704d4c3a464c3a4c4f414e5f41435449564560781b6044820152606401610773565b600554600754600d546019546001600160a01b03938416936136b691859116600019613e90565b6136f75760405162461bcd60e51b815260206004820152601260248201527113530e91930e9054141493d59157d190525360721b6044820152606401610773565b6019546040516377cf0ddb60e11b815260048101839052602481018490526001600160a01b039091169063ef9e1bb690604401600060405180830381600087803b15801561374457600080fd5b505af1158015613758573d6000803e3d6000fd5b50506019546040516327d180b560e01b81526001600160a01b038781166004830152602482018690526000945090911691506327d180b590604401602060405180830381600087803b1580156137ad57600080fd5b505af11580156137c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137e591906143f5565b90506137f18183614774565b600f5560006137ff85611aee565b146138455760405162461bcd60e51b81526020600482015260166024820152754d4c3a464c3a554e45585045435445445f46554e445360501b6044820152606401610773565b866001600160a01b03167fcd909ec339185c4598a4096e174308fbdf136d117f230960f873a2f2e81f63af8360148190559750878542613885919061471b565b60128190556040805192835260208301919091520160405180910390a25050505050919050565b60006138d67f7a45a402e4cb6e08ebc196f20f66d5d30e67285a2a8aa80503fa409e727a4af15490565b919050565b6040516001600160a01b03808516602483015283166044820152606481018290526000906139499086906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613f0c565b95945050505050565b60006006819055600781905560088190556009819055600a819055600b819055600e819055601281905560138190556014819055601a55565b6040516001600160a01b0383166024820152604481018290526000906139be90859063a9059cbb60e01b90606401613912565b90505b9392505050565b600083851115613a0d57826001816139e08789614774565b6139ea9086614755565b6139f4919061471b565b6139fe9190614774565b613a089190614733565b613949565b506000949350505050565b601a54613a2157565b6000601a55565b6005546040516370a0823160e01b815230600482015260009182916001600160a01b03909116906370a082319060240160206040518083038186803b158015613a7057600080fd5b505afa158015613a84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa891906143f5565b6019546005546040516376bd6e5160e01b81526001600160a01b0391821660048201526024810187905292935016906376bd6e5190604401602060405180830381600087803b158015613afa57600080fd5b505af1158015613b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b3291906143f5565b506005546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015613b7757600080fd5b505afa158015613b8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613baf91906143f5565b905080821115613be257613bc38183614774565b925082600f6000828254613bd79190614774565b90915550613c039050565b613bec8282614774565b600f6000828254613bfd919061471b565b90915550505b5050919050565b60006138d67f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b600084848484604051602001613c4d949392919061459e565b604051602081830303815290604052805190602001209050949350505050565b6000613c83601454600f54600d54600c546139c8565b6011541015905090565b600083613c9a8a8c61471b565b1015613ca857506000613ced565b6000613cb48a86614774565b613cbe908c614774565b9050613ccd898989848a613fac565b9250613cdf90508b8a8988888861409f565b613ce9908361471b565b9150505b9998505050505050505050565b6000613d046141e1565b613d0c6141ff565b613d198989888d8b613fac565b8352925060018714613d2b5782613d2d565b885b9250613d3d8c8a888e898961409f565b8260016020020152601654826002602002015260195460405163e0b58e0d60e01b8152306004820152600160248201526000918291829182916001600160a01b039091169063e0b58e0d9060440160806040518083038186803b158015613da357600080fd5b505afa158015613db7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ddb9190614466565b93509350935093508284613def919061471b565b8552613dfb818361471b565b602086015250949e939d50919b50919950505050505050505050565b6000833b80613e2a5760009150506139c1565b846001600160a01b03168484604051613e44929190614553565b600060405180830381855af49150503d8060008114613e7f576040519150601f19603f3d011682016040523d82523d6000602084013e613e84565b606091505b50909695505050505050565b6040516001600160a01b038316602482015260006044820181905290613ec390859063095ea7b360e01b90606401613912565b613ecf575060006139c1565b81613edc575060016139c1565b6040516001600160a01b0384166024820152604481018390526139be90859063095ea7b360e01b90606401613912565b60006001600160a01b0383163b613f2557506000611bbc565b6060836001600160a01b031683604051613f3f9190614563565b6000604051808303816000865af19150503d8060008114613f7c576040519150601f19603f3d011682016040523d82523d6000602084013e613f81565b606091505b50909250905081801561133b57508051158061133b57508080602001905181019061133b91906143ba565b6000806000613fbb868661413b565b90506000613fe3613fd483670de0b6b3a764000061471b565b86670de0b6b3a7640000614156565b9050670de0b6b3a764000081116140165784613fff898b614774565b6140099190614733565b6000935093505050614095565b600061402a670de0b6b3a764000083614774565b838a670de0b6b3a764000061403f868f614755565b6140499190614733565b6140539190614774565b61405d9190614755565b6140679190614733565b90506140748a89896141b8565b93508381101561408557600061408f565b61408f8482614774565b94505050505b9550959350505050565b60008387116140b057506000614131565b6000620151806140c0868a614774565b6140cd906201517f61471b565b6140d79190614733565b6140e49062015180614755565b90506140fa876140f4858961471b565b836141b8565b614104908361471b565b9150670de0b6b3a76400006141198886614755565b6141239190614733565b61412d908361471b565b9150505b9695505050505050565b60006301e1338061414c8385614755565b6139c19190614733565b6000600183166141665781614168565b835b90505b60019290921c9182156139c157816141838580614755565b61418d9190614733565b93506001831661419c5761416b565b816141a78583614755565b6141b19190614733565b905061416b565b6000670de0b6b3a76400006141cd848461413b565b6141d79086614755565b6139be9190614733565b60405180606001604052806003906020820280368337509192915050565b60405180604001604052806002906020820280368337509192915050565b60008083601f84011261422f57600080fd5b50813567ffffffffffffffff81111561424757600080fd5b60208301915083602082850101111561425f57600080fd5b9250929050565b60006020828403121561427857600080fd5b81356139c1816147b7565b60006020828403121561429557600080fd5b81516139c1816147b7565b600080604083850312156142b357600080fd5b82356142be816147b7565b915060208301356142ce816147b7565b809150509250929050565b6000806000604084860312156142ee57600080fd5b83356142f9816147b7565b9250602084013567ffffffffffffffff81111561431557600080fd5b6143218682870161421d565b9497909650939450505050565b6000806000806060858703121561434457600080fd5b843561434f816147b7565b935060208501359250604085013567ffffffffffffffff8082111561437357600080fd5b818701915087601f83011261438757600080fd5b81358181111561439657600080fd5b8860208260051b85010111156143ab57600080fd5b95989497505060200194505050565b6000602082840312156143cc57600080fd5b815180151581146139c157600080fd5b6000602082840312156143ee57600080fd5b5035919050565b60006020828403121561440757600080fd5b5051919050565b6000806040838503121561442157600080fd5b8235915060208301356142ce816147b7565b60008060006040848603121561444857600080fd5b83359250602084013567ffffffffffffffff81111561431557600080fd5b6000806000806080858703121561447c57600080fd5b505082516020840151604085015160609095015191969095509092509050565b818352600060208085019450848460051b86018460005b8781101561451d5783830389528135601e198836030181126144d457600080fd5b8701803567ffffffffffffffff8111156144ed57600080fd5b8036038913156144fc57600080fd5b614509858289850161452a565b9a87019a94505050908401906001016144b3565b5090979650505050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b8183823760009101908152919050565b6000825160005b81811015614584576020818601810151858301520161456a565b81811115614593576000828501525b509190910192915050565b60018060a01b038516815283602082015260606040820152600061413160608301848661449c565b85815260018060a01b03851660208201528360408201526080606082015260006145f460808301848661449c565b979650505050505050565b60208082526015908201527413530e93540e9514905394d1915497d19052531151605a1b604082015260600190565b602080825260119082015270130e941493d513d0d3d317d4105554d151607a1b604082015260600190565b83815260c0810160208083018560005b600381101561468657815183529183019190830190600101614669565b505050608083018460005b60028110156146ae57815183529183019190830190600101614691565b50505050949350505050565b83815260406020820152600061394960408301848661452a565b6000808335601e198436030181126146eb57600080fd5b83018035915067ffffffffffffffff82111561470657600080fd5b60200191503681900382131561425f57600080fd5b6000821982111561472e5761472e61478b565b500190565b60008261475057634e487b7160e01b600052601260045260246000fd5b500490565b600081600019048311821515161561476f5761476f61478b565b500290565b6000828210156147865761478661478b565b500390565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b6001600160a01b03811681146133c857600080fdfe6bd56533ce1c8ea03f7b858ac441b5a86d140a793a7c9e3faecbbe517c2c8791a26469706673582212204a309c37cbae06ae4046df36b05aa1ac996ec534c14d5709848916960b7ff5da64736f6c63430008070033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.