{"sources":{"TokenHandler.sol":{"content":"// File: contracts/interfaces/IMarketHandler.sol\r\npragma solidity 0.6.12;\r\n\r\n/**\r\n * @title BiFi's market handler interface\r\n * @author BiFi(seinmyung25, Miller-kk, tlatkdgus1, dongchangYoo)\r\n */\r\ninterface IMarketHandler  {\r\n\tfunction setCircuitBreaker(bool _emergency) external returns (bool);\r\n\tfunction setCircuitBreakWithOwner(bool _emergency) external returns (bool);\r\n\r\n\tfunction getTokenName() external view returns (string memory);\r\n\r\n\tfunction ownershipTransfer(address payable newOwner) external returns (bool);\r\n\r\n\tfunction deposit(uint256 unifiedTokenAmount, bool allFlag) external payable returns (bool);\r\n\tfunction withdraw(uint256 unifiedTokenAmount, bool allFlag) external returns (bool);\r\n\tfunction borrow(uint256 unifiedTokenAmount, bool allFlag) external returns (bool);\r\n\tfunction repay(uint256 unifiedTokenAmount, bool allFlag) external payable returns (bool);\r\n\r\n\tfunction executeFlashloan(\r\n\t\taddress receiverAddress,\r\n\t\tuint256 amount\r\n  ) external returns (bool);\r\n\r\n\tfunction depositFlashloanFee(\r\n\t\tuint256 amount\r\n\t) external returns (bool);\r\n\r\n  function convertUnifiedToUnderlying(uint256 unifiedTokenAmount) external view returns (uint256);\r\n\tfunction partialLiquidationUser(address payable delinquentBorrower, uint256 liquidateAmount, address payable liquidator, uint256 rewardHandlerID) external returns (uint256, uint256, uint256);\r\n\tfunction partialLiquidationUserReward(address payable delinquentBorrower, uint256 liquidationAmountWithReward, address payable liquidator) external returns (uint256);\r\n\r\n\tfunction getTokenHandlerLimit() external view returns (uint256, uint256);\r\n  function getTokenHandlerBorrowLimit() external view returns (uint256);\r\n\tfunction getTokenHandlerMarginCallLimit() external view returns (uint256);\r\n\tfunction setTokenHandlerBorrowLimit(uint256 borrowLimit) external returns (bool);\r\n\tfunction setTokenHandlerMarginCallLimit(uint256 marginCallLimit) external returns (bool);\r\n\r\n  function getTokenLiquidityAmountWithInterest(address payable userAddr) external view returns (uint256);\r\n\r\n\tfunction getUserAmountWithInterest(address payable userAddr) external view returns (uint256, uint256);\r\n\tfunction getUserAmount(address payable userAddr) external view returns (uint256, uint256);\r\n\r\n\tfunction getUserMaxBorrowAmount(address payable userAddr) external view returns (uint256);\r\n\tfunction getUserMaxWithdrawAmount(address payable userAddr) external view returns (uint256);\r\n\tfunction getUserMaxRepayAmount(address payable userAddr) external view returns (uint256);\r\n\r\n\tfunction checkFirstAction() external returns (bool);\r\n\tfunction applyInterest(address payable userAddr) external returns (uint256, uint256);\r\n\r\n\tfunction reserveDeposit(uint256 unifiedTokenAmount) external payable returns (bool);\r\n\tfunction reserveWithdraw(uint256 unifiedTokenAmount) external returns (bool);\r\n\r\n\tfunction withdrawFlashloanFee(uint256 unifiedTokenAmount) external returns (bool);\r\n\r\n\tfunction getDepositTotalAmount() external view returns (uint256);\r\n\tfunction getBorrowTotalAmount() external view returns (uint256);\r\n\r\n\tfunction getSIRandBIR() external view returns (uint256, uint256);\r\n\r\n  function getERC20Addr() external view returns (address);\r\n}\r\n\r\n// File: contracts/interfaces/IMarketHandlerDataStorage.sol\r\npragma solidity 0.6.12;\r\n\r\n/**\r\n * @title BiFi's market handler data storage interface\r\n * @author BiFi(seinmyung25, Miller-kk, tlatkdgus1, dongchangYoo)\r\n */\r\ninterface IMarketHandlerDataStorage  {\r\n\tfunction setCircuitBreaker(bool _emergency) external returns (bool);\r\n\r\n\tfunction setNewCustomer(address payable userAddr) external returns (bool);\r\n\r\n\tfunction getUserAccessed(address payable userAddr) external view returns (bool);\r\n\tfunction setUserAccessed(address payable userAddr, bool _accessed) external returns (bool);\r\n\r\n\tfunction getReservedAddr() external view returns (address payable);\r\n\tfunction setReservedAddr(address payable reservedAddress) external returns (bool);\r\n\r\n\tfunction getReservedAmount() external view returns (int256);\r\n\tfunction addReservedAmount(uint256 amount) external returns (int256);\r\n\tfunction subReservedAmount(uint256 amount) external returns (int256);\r\n\tfunction updateSignedReservedAmount(int256 amount) external returns (int256);\r\n\r\n\tfunction setTokenHandler(address _marketHandlerAddr, address _interestModelAddr) external returns (bool);\r\n\tfunction setCoinHandler(address _marketHandlerAddr, address _interestModelAddr) external returns (bool);\r\n\r\n\tfunction getDepositTotalAmount() external view returns (uint256);\r\n\tfunction addDepositTotalAmount(uint256 amount) external returns (uint256);\r\n\tfunction subDepositTotalAmount(uint256 amount) external returns (uint256);\r\n\r\n\tfunction getBorrowTotalAmount() external view returns (uint256);\r\n\tfunction addBorrowTotalAmount(uint256 amount) external returns (uint256);\r\n\tfunction subBorrowTotalAmount(uint256 amount) external returns (uint256);\r\n\r\n\tfunction getUserIntraDepositAmount(address payable userAddr) external view returns (uint256);\r\n\tfunction addUserIntraDepositAmount(address payable userAddr, uint256 amount) external returns (uint256);\r\n\tfunction subUserIntraDepositAmount(address payable userAddr, uint256 amount) external returns (uint256);\r\n\r\n\tfunction getUserIntraBorrowAmount(address payable userAddr) external view returns (uint256);\r\n\tfunction addUserIntraBorrowAmount(address payable userAddr, uint256 amount) external returns (uint256);\r\n\tfunction subUserIntraBorrowAmount(address payable userAddr, uint256 amount) external returns (uint256);\r\n\r\n\tfunction addDepositAmount(address payable userAddr, uint256 amount) external returns (bool);\r\n\tfunction subDepositAmount(address payable userAddr, uint256 amount) external returns (bool);\r\n\r\n\tfunction addBorrowAmount(address payable userAddr, uint256 amount) external returns (bool);\r\n\tfunction subBorrowAmount(address payable userAddr, uint256 amount) external returns (bool);\r\n\r\n\tfunction getUserAmount(address payable userAddr) external view returns (uint256, uint256);\r\n\tfunction getHandlerAmount() external view returns (uint256, uint256);\r\n\r\n\tfunction getAmount(address payable userAddr) external view returns (uint256, uint256, uint256, uint256);\r\n\tfunction setAmount(address payable userAddr, uint256 depositTotalAmount, uint256 borrowTotalAmount, uint256 depositAmount, uint256 borrowAmount) external returns (uint256);\r\n\r\n\tfunction setBlocks(uint256 lastUpdatedBlock, uint256 inactiveActionDelta) external returns (bool);\r\n\r\n\tfunction getLastUpdatedBlock() external view returns (uint256);\r\n\tfunction setLastUpdatedBlock(uint256 _lastUpdatedBlock) external returns (bool);\r\n\r\n\tfunction getInactiveActionDelta() external view returns (uint256);\r\n\tfunction setInactiveActionDelta(uint256 inactiveActionDelta) external returns (bool);\r\n\r\n\tfunction syncActionEXR() external returns (bool);\r\n\r\n\tfunction getActionEXR() external view returns (uint256, uint256);\r\n\tfunction setActionEXR(uint256 actionDepositExRate, uint256 actionBorrowExRate) external returns (bool);\r\n\r\n\tfunction getGlobalDepositEXR() external view returns (uint256);\r\n\tfunction getGlobalBorrowEXR() external view returns (uint256);\r\n\r\n\tfunction setEXR(address payable userAddr, uint256 globalDepositEXR, uint256 globalBorrowEXR) external returns (bool);\r\n\r\n\tfunction getUserEXR(address payable userAddr) external view returns (uint256, uint256);\r\n\tfunction setUserEXR(address payable userAddr, uint256 depositEXR, uint256 borrowEXR) external returns (bool);\r\n\r\n\tfunction getGlobalEXR() external view returns (uint256, uint256);\r\n\r\n\tfunction getMarketHandlerAddr() external view returns (address);\r\n\tfunction setMarketHandlerAddr(address marketHandlerAddr) external returns (bool);\r\n\r\n\tfunction getInterestModelAddr() external view returns (address);\r\n\tfunction setInterestModelAddr(address interestModelAddr) external returns (bool);\r\n\r\n\r\n\tfunction getMinimumInterestRate() external view returns (uint256);\r\n\tfunction setMinimumInterestRate(uint256 _minimumInterestRate) external returns (bool);\r\n\r\n\tfunction getLiquiditySensitivity() external view returns (uint256);\r\n\tfunction setLiquiditySensitivity(uint256 _liquiditySensitivity) external returns (bool);\r\n\r\n\tfunction getLimit() external view returns (uint256, uint256);\r\n\r\n\tfunction getBorrowLimit() external view returns (uint256);\r\n\tfunction setBorrowLimit(uint256 _borrowLimit) external returns (bool);\r\n\r\n\tfunction getMarginCallLimit() external view returns (uint256);\r\n\tfunction setMarginCallLimit(uint256 _marginCallLimit) external returns (bool);\r\n\r\n\tfunction getLimitOfAction() external view returns (uint256);\r\n\tfunction setLimitOfAction(uint256 limitOfAction) external returns (bool);\r\n\r\n\tfunction getLiquidityLimit() external view returns (uint256);\r\n\tfunction setLiquidityLimit(uint256 liquidityLimit) external returns (bool);\r\n}\r\n\r\n// File: contracts/interfaces/IMarketManager.sol\r\npragma solidity 0.6.12;\r\n\r\n/**\r\n * @title BiFi's market manager interface\r\n * @author BiFi(seinmyung25, Miller-kk, tlatkdgus1, dongchangYoo)\r\n */\r\ninterface IMarketManager  {\r\n\tfunction setBreakerTable(address _target, bool _status) external returns (bool);\r\n\r\n\tfunction getCircuitBreaker() external view returns (bool);\r\n\tfunction setCircuitBreaker(bool _emergency) external returns (bool);\r\n\r\n\tfunction getTokenHandlerInfo(uint256 handlerID) external view returns (bool, address, string memory);\r\n\r\n\tfunction handlerRegister(uint256 handlerID, address tokenHandlerAddr, uint256 flashFeeRate) external returns (bool);\r\n\r\n\tfunction applyInterestHandlers(address payable userAddr, uint256 callerID, bool allFlag) external returns (uint256, uint256, uint256, uint256, uint256, uint256);\r\n\r\n\tfunction getTokenHandlerPrice(uint256 handlerID) external view returns (uint256);\r\n\tfunction getTokenHandlerBorrowLimit(uint256 handlerID) external view returns (uint256);\r\n\tfunction getTokenHandlerSupport(uint256 handlerID) external view returns (bool);\r\n\r\n\tfunction getTokenHandlersLength() external view returns (uint256);\r\n\tfunction setTokenHandlersLength(uint256 _tokenHandlerLength) external returns (bool);\r\n\r\n\tfunction getTokenHandlerID(uint256 index) external view returns (uint256);\r\n\tfunction getTokenHandlerMarginCallLimit(uint256 handlerID) external view returns (uint256);\r\n\r\n\tfunction getUserIntraHandlerAssetWithInterest(address payable userAddr, uint256 handlerID) external view returns (uint256, uint256);\r\n\r\n\tfunction getUserTotalIntraCreditAsset(address payable userAddr) external view returns (uint256, uint256);\r\n\r\n\tfunction getUserLimitIntraAsset(address payable userAddr) external view returns (uint256, uint256);\r\n\r\n\tfunction getUserCollateralizableAmount(address payable userAddr, uint256 handlerID) external view returns (uint256);\r\n\r\n\tfunction getUserExtraLiquidityAmount(address payable userAddr, uint256 handlerID) external view returns (uint256);\r\n\tfunction partialLiquidationUser(address payable delinquentBorrower, uint256 liquidateAmount, address payable liquidator, uint256 liquidateHandlerID, uint256 rewardHandlerID) external returns (uint256, uint256, uint256);\r\n\r\n\tfunction getMaxLiquidationReward(address payable delinquentBorrower, uint256 liquidateHandlerID, uint256 liquidateAmount, uint256 rewardHandlerID, uint256 rewardRatio) external view returns (uint256);\r\n\tfunction partialLiquidationUserReward(address payable delinquentBorrower, uint256 rewardAmount, address payable liquidator, uint256 handlerID) external returns (uint256);\r\n\r\n\tfunction setLiquidationManager(address liquidationManagerAddr) external returns (bool);\r\n\r\n\tfunction rewardClaimAll(address payable userAddr) external returns (uint256);\r\n\r\n\tfunction updateRewardParams(address payable userAddr) external returns (bool);\r\n\tfunction interestUpdateReward() external returns (bool);\r\n\tfunction getGlobalRewardInfo() external view returns (uint256, uint256, uint256);\r\n\r\n\tfunction setOracleProxy(address oracleProxyAddr) external returns (bool);\r\n\r\n\tfunction rewardUpdateOfInAction(address payable userAddr, uint256 callerID) external returns (bool);\r\n\tfunction ownerRewardTransfer(uint256 _amount) external returns (bool);\r\n \tfunction getFeeTotal(uint256 handlerID) external returns (uint256);\r\n  function getFeeFromArguments(uint256 handlerID, uint256 amount, uint256 bifiAmount) external returns (uint256);\r\n}\r\n\r\n// File: contracts/interfaces/IInterestModel.sol\r\npragma solidity 0.6.12;\r\n\r\n/**\r\n * @title BiFi's interest model interface\r\n * @author BiFi(seinmyung25, Miller-kk, tlatkdgus1, dongchangYoo)\r\n */\r\ninterface IInterestModel {\r\n\tfunction getInterestAmount(address handlerDataStorageAddr, address payable userAddr, bool isView) external view returns (bool, uint256, uint256, bool, uint256, uint256);\r\n\tfunction viewInterestAmount(address handlerDataStorageAddr, address payable userAddr) external view returns (bool, uint256, uint256, bool, uint256, uint256);\r\n\tfunction getSIRandBIR(uint256 depositTotalAmount, uint256 borrowTotalAmount) external view returns (uint256, uint256);\r\n}\r\n\r\n// File: contracts/interfaces/IMarketSIHandlerDataStorage.sol\r\npragma solidity 0.6.12;\r\n\r\n/**\r\n * @title BiFi's market si handler data storage interface\r\n * @author BiFi(seinmyung25, Miller-kk, tlatkdgus1, dongchangYoo)\r\n */\r\ninterface IMarketSIHandlerDataStorage  {\r\n\tfunction setCircuitBreaker(bool _emergency) external returns (bool);\r\n\r\n\tfunction updateRewardPerBlockStorage(uint256 _rewardPerBlock) external returns (bool);\r\n\r\n\tfunction getRewardInfo(address userAddr) external view returns (uint256, uint256, uint256, uint256, uint256, uint256);\r\n\r\n\tfunction getMarketRewardInfo() external view returns (uint256, uint256, uint256);\r\n\tfunction setMarketRewardInfo(uint256 _rewardLane, uint256 _rewardLaneUpdateAt, uint256 _rewardPerBlock) external returns (bool);\r\n\r\n\tfunction getUserRewardInfo(address userAddr) external view returns (uint256, uint256, uint256);\r\n\tfunction setUserRewardInfo(address userAddr, uint256 _rewardLane, uint256 _rewardLaneUpdateAt, uint256 _rewardAmount) external returns (bool);\r\n\r\n\tfunction getBetaRate() external view returns (uint256);\r\n\tfunction setBetaRate(uint256 _betaRate) external returns (bool);\r\n}\r\n\r\n// File: contracts/interfaces/IERC20.sol\r\n// from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol\r\npragma solidity 0.6.12;\r\ninterface IERC20 {\r\n    function totalSupply() external view returns (uint256);\r\n    function balanceOf(address account) external view returns (uint256);\r\n    function transfer(address recipient, uint256 amount) external ;\r\n    function allowance(address owner, address spender) external view returns (uint256);\r\n    function approve(address spender, uint256 amount) external returns (bool);\r\n    function transferFrom(address sender, address recipient, uint256 amount) external ;\r\n\r\n    event Transfer(address indexed from, address indexed to, uint256 value);\r\n    event Approval(address indexed owner, address indexed spender, uint256 value);\r\n}\r\n\r\n// File: contracts/interfaces/IProxy.sol\r\npragma solidity 0.6.12;\r\n\r\n/**\r\n * @title BiFi's proxy interface\r\n * @author BiFi(seinmyung25, Miller-kk, tlatkdgus1, dongchangYoo)\r\n */\r\ninterface IProxy  {\r\n\tfunction handlerProxy(bytes memory data) external returns (bool, bytes memory);\r\n\tfunction handlerViewProxy(bytes memory data) external view returns (bool, bytes memory);\r\n\tfunction siProxy(bytes memory data) external returns (bool, bytes memory);\r\n\tfunction siViewProxy(bytes memory data) external view returns (bool, bytes memory);\r\n}\r\n\r\n// File: contracts/interfaces/IServiceIncentive.sol\r\npragma solidity 0.6.12;\r\n\r\n/**\r\n * @title BiFi's si interface\r\n * @author BiFi(seinmyung25, Miller-kk, tlatkdgus1, dongchangYoo)\r\n */\r\ninterface IServiceIncentive  {\r\n\tfunction setCircuitBreakWithOwner(bool emergency) external returns (bool);\r\n\tfunction setCircuitBreaker(bool emergency) external returns (bool);\r\n\r\n\tfunction updateRewardPerBlockLogic(uint256 _rewardPerBlock) external returns (bool);\r\n\tfunction updateRewardLane(address payable userAddr) external returns (bool);\r\n\r\n\tfunction getBetaRateBaseTotalAmount() external view returns (uint256);\r\n\tfunction getBetaRateBaseUserAmount(address payable userAddr) external view returns (uint256);\r\n\r\n\tfunction getMarketRewardInfo() external view returns (uint256, uint256, uint256);\r\n\r\n\tfunction getUserRewardInfo(address payable userAddr) external view returns (uint256, uint256, uint256);\r\n\r\n\tfunction claimRewardAmountUser(address payable userAddr) external returns (uint256);\r\n}\r\n\r\n// File: contracts/interfaces/IFlashloanReceiver.sol\r\npragma solidity 0.6.12;\r\n\r\ninterface IFlashloanReceiver {\r\n    function executeOperation(\r\n      address reserve,\r\n      uint256 amount,\r\n      uint256 fee,\r\n      bytes calldata params\r\n    ) external returns (bool);\r\n}\r\n\r\n// File: contracts/Errors.sol\r\npragma solidity 0.6.12;\r\n\r\ncontract Modifier {\r\n    string internal constant ONLY_OWNER = \"O\";\r\n    string internal constant ONLY_MANAGER = \"M\";\r\n    string internal constant CIRCUIT_BREAKER = \"emergency\";\r\n}\r\n\r\ncontract ManagerModifier is Modifier {\r\n    string internal constant ONLY_HANDLER = \"H\";\r\n    string internal constant ONLY_LIQUIDATION_MANAGER = \"LM\";\r\n    string internal constant ONLY_BREAKER = \"B\";\r\n}\r\n\r\ncontract HandlerDataStorageModifier is Modifier {\r\n    string internal constant ONLY_BIFI_CONTRACT = \"BF\";\r\n}\r\n\r\ncontract SIDataStorageModifier is Modifier {\r\n    string internal constant ONLY_SI_HANDLER = \"SI\";\r\n}\r\n\r\ncontract HandlerErrors is Modifier {\r\n    string internal constant USE_VAULE = \"use value\";\r\n    string internal constant USE_ARG = \"use arg\";\r\n    string internal constant EXCEED_LIMIT = \"exceed limit\";\r\n    string internal constant NO_LIQUIDATION = \"no liquidation\";\r\n    string internal constant NO_LIQUIDATION_REWARD = \"no enough reward\";\r\n    string internal constant NO_EFFECTIVE_BALANCE = \"not enough balance\";\r\n    string internal constant TRANSFER = \"err transfer\";\r\n}\r\n\r\ncontract SIErrors is Modifier { }\r\n\r\ncontract InterestErrors is Modifier { }\r\n\r\ncontract LiquidationManagerErrors is Modifier {\r\n    string internal constant NO_DELINQUENT = \"not delinquent\";\r\n}\r\n\r\ncontract ManagerErrors is ManagerModifier {\r\n    string internal constant REWARD_TRANSFER = \"RT\";\r\n    string internal constant UNSUPPORTED_TOKEN = \"UT\";\r\n}\r\n\r\ncontract OracleProxyErrors is Modifier {\r\n    string internal constant ZERO_PRICE = \"price zero\";\r\n}\r\n\r\ncontract RequestProxyErrors is Modifier { }\r\n\r\ncontract ManagerDataStorageErrors is ManagerModifier {\r\n    string internal constant NULL_ADDRESS = \"err addr null\";\r\n}\r\n\r\n// File: contracts/context/BlockContext.sol\r\npragma solidity 0.6.12;\r\n\r\n/**\r\n * @title BiFi's BlockContext contract\r\n * @notice BiFi getter Contract for Block Context Information\r\n * @author BiFi(seinmyung25, Miller-kk, tlatkdgus1, dongchangYoo)\r\n */\r\ncontract BlockContext {\r\n    function _blockContext() internal view returns(uint256 context) {\r\n        // block number chain\r\n        context = block.number;\r\n\r\n        // block timestamp chain\r\n        // context = block.timestamp;\r\n    }\r\n}\r\n\r\n// File: contracts/marketHandler/TokenHandler.sol\r\n// SPDX-License-Identifier: BSD-3-Clause\r\npragma solidity 0.6.12;\r\n\r\n/**\r\n * @title BiFi's TokenHandler logic contract for ERC20 tokens\r\n * @author BiFi(seinmyung25, Miller-kk, tlatkdgus1, dongchangYoo)\r\n */\r\ncontract TokenHandler is IMarketHandler, HandlerErrors, BlockContext {\r\n\tevent MarketIn(address userAddr);\r\n\r\n\tevent Deposit(address depositor, uint256 depositAmount, uint256 handlerID);\r\n\tevent Withdraw(address redeemer, uint256 redeemAmount, uint256 handlerID);\r\n\tevent Borrow(address borrower, uint256 borrowAmount, uint256 handlerID);\r\n\tevent Repay(address repayer, uint256 repayAmount, uint256 handlerID);\r\n\r\n\tevent ReserveDeposit(uint256 reserveDepositAmount, uint256 handlerID);\r\n\tevent ReserveWithdraw(uint256 reserveWithdrawAmount, uint256 handlerID);\r\n\r\n\tevent FlashloanFeeWithdraw(uint256 flashloanFeeWithdrawAmount, uint256 handlerID);\r\n\r\n\tevent OwnershipTransferred(address owner, address newOwner);\r\n\r\n\tevent CircuitBreaked(bool breaked, uint256 blockNumber, uint256 handlerID);\r\n\r\n\taddress payable owner;\r\n\tuint256 handlerID;\r\n\tstring tokenName;\r\n\r\n\tuint256 constant unifiedPoint = 10 ** 18;\r\n\tuint256 unifiedTokenDecimal;\r\n\tuint256 underlyingTokenDecimal;\r\n\r\n\tIMarketManager marketManager;\r\n\tIInterestModel interestModelInstance;\r\n\tIMarketHandlerDataStorage handlerDataStorage;\r\n\tIMarketSIHandlerDataStorage SIHandlerDataStorage;\r\n\tIERC20 erc20Instance;\r\n\r\n\tstruct ProxyInfo {\r\n\t\tbool result;\r\n\t\tbytes returnData;\r\n\t\tbytes data;\r\n\t\tbytes proxyData;\r\n\t}\r\n\r\n\tmodifier onlyMarketManager {\r\n\t\taddress msgSender = msg.sender;\r\n\t\trequire((msgSender == address(marketManager)) || (msgSender == owner), ONLY_MANAGER);\r\n\t\t_;\r\n\t}\r\n\r\n\tmodifier onlyOwner {\r\n\t\trequire(msg.sender == address(owner), ONLY_OWNER);\r\n\t\t_;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Set circuitBreak to freeze all of handlers by owner\r\n\t* @param _emergency Boolean state of the circuit break.\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction setCircuitBreakWithOwner(bool _emergency) onlyOwner external override returns (bool)\r\n\t{\r\n\t\thandlerDataStorage.setCircuitBreaker(_emergency);\r\n\r\n\t\temit CircuitBreaked(_emergency, block.number, handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Set circuitBreak which freeze all of handlers by marketManager\r\n\t* @param _emergency Boolean state of the circuit break.\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction setCircuitBreaker(bool _emergency) onlyMarketManager external override returns (bool)\r\n\t{\r\n\t\thandlerDataStorage.setCircuitBreaker(_emergency);\r\n\r\n\t\temit CircuitBreaked(_emergency, block.number, handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Change the owner of the handler\r\n\t* @param newOwner the address of the owner to be replaced\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction ownershipTransfer(address payable newOwner) onlyOwner external override returns (bool)\r\n\t{\r\n\t\towner = newOwner;\r\n\r\n\t\temit OwnershipTransferred(owner, newOwner);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the token name\r\n   * @return the token name\r\n\t*/\r\n\tfunction getTokenName() external view override returns (string memory)\r\n\t{\r\n\t\treturn tokenName;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Deposit assets to the reserve of the handler.\r\n\t* @param unifiedTokenAmount The amount of token to deposit\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction reserveDeposit(uint256 unifiedTokenAmount) external payable override returns (bool)\r\n\t{\r\n\t\trequire(msg.value == 0, USE_ARG);\r\n\r\n\t\thandlerDataStorage.addReservedAmount(unifiedTokenAmount);\r\n\t\thandlerDataStorage.addDepositTotalAmount(unifiedTokenAmount);\r\n\r\n\t\t_transferFrom(msg.sender, unifiedTokenAmount);\r\n\r\n\t\temit ReserveDeposit(unifiedTokenAmount, handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Withdraw assets from the reserve of the handler.\r\n\t* @param unifiedTokenAmount The amount of token to withdraw\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction reserveWithdraw(uint256 unifiedTokenAmount) onlyOwner external override returns (bool)\r\n\t{\r\n\t\taddress payable reserveAddr = handlerDataStorage.getReservedAddr();\r\n\r\n\t\thandlerDataStorage.subReservedAmount(unifiedTokenAmount);\r\n\t\thandlerDataStorage.subDepositTotalAmount(unifiedTokenAmount);\r\n\r\n\t\t_transfer(reserveAddr, unifiedTokenAmount);\r\n\r\n\t\temit ReserveWithdraw(unifiedTokenAmount, handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\tfunction withdrawFlashloanFee(uint256 unifiedTokenAmount) onlyMarketManager external override returns (bool) {\r\n\t\taddress payable reserveAddr = handlerDataStorage.getReservedAddr();\r\n\r\n\t\thandlerDataStorage.subReservedAmount(unifiedTokenAmount);\r\n\t\thandlerDataStorage.subDepositTotalAmount(unifiedTokenAmount);\r\n\r\n\t\t_transfer(reserveAddr, unifiedTokenAmount);\r\n\r\n\t\temit FlashloanFeeWithdraw(unifiedTokenAmount, handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Deposit action\r\n\t* @param unifiedTokenAmount The deposit amount\r\n\t* @param flag Flag for the full calcuation mode\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction deposit(uint256 unifiedTokenAmount, bool flag) external payable override returns (bool)\r\n\t{\r\n\t\trequire(msg.value == 0, USE_ARG);\r\n\r\n\t\taddress payable userAddr = msg.sender;\r\n\t\tuint256 _handlerID = handlerID;\r\n\r\n\t\tif(flag) {\r\n\t\t\t// flag is true, update interest, reward all handlers\r\n\t\t\tmarketManager.applyInterestHandlers(userAddr, _handlerID, flag);\r\n\t\t} else {\r\n\t\t\tmarketManager.rewardUpdateOfInAction(userAddr, _handlerID);\r\n\t\t\t_applyInterest(userAddr);\r\n\t\t}\r\n\r\n\t\thandlerDataStorage.addDepositAmount(userAddr, unifiedTokenAmount);\r\n\r\n\t\t_transferFrom(userAddr, unifiedTokenAmount);\r\n\r\n\t\temit Deposit(userAddr, unifiedTokenAmount, _handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\tfunction depositTo(uint256 unifiedTokenAmount, address payable toUser, bool flag) external payable returns (bool)\r\n\t{\r\n\t\trequire(msg.value == 0, USE_ARG);\r\n\r\n\t\tuint256 _handlerID = handlerID;\r\n\r\n\t\tif(flag) {\r\n\t\t\t// flag is true, update interest, reward all handlers\r\n\t\t\tmarketManager.applyInterestHandlers(toUser, _handlerID, flag);\r\n\t\t} else {\r\n\t\t\tmarketManager.rewardUpdateOfInAction(toUser, _handlerID);\r\n\t\t\t_applyInterest(toUser);\r\n\t\t}\r\n\r\n\t\thandlerDataStorage.addDepositAmount(toUser, unifiedTokenAmount);\r\n\r\n\t\t_transferFrom(msg.sender, unifiedTokenAmount);\r\n\r\n\t\temit Deposit(toUser, unifiedTokenAmount, _handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Withdraw action\r\n\t* @param unifiedTokenAmount The withdraw amount\r\n\t* @param flag Flag for the full calcuation mode\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction withdraw(uint256 unifiedTokenAmount, bool flag) external override returns (bool)\r\n\t{\r\n\t\taddress payable userAddr = msg.sender;\r\n\t\tuint256 _handlerID = handlerID;\r\n\r\n\t\tuint256 userLiquidityAmount;\r\n\t\tuint256 userCollateralizableAmount;\r\n\t\tuint256 price;\r\n\t\t(userLiquidityAmount, userCollateralizableAmount, , , , price) = marketManager.applyInterestHandlers(userAddr, _handlerID, flag);\r\n\r\n\t\tuint256 adjustedAmount = _getUserActionMaxWithdrawAmount(userAddr, unifiedTokenAmount, userCollateralizableAmount);\r\n\t\trequire(unifiedMul(adjustedAmount, price) <= handlerDataStorage.getLimitOfAction(), EXCEED_LIMIT);\r\n\r\n\t\thandlerDataStorage.subDepositAmount(userAddr, adjustedAmount);\r\n\r\n\t\t_transfer(userAddr, adjustedAmount);\r\n\r\n\t\temit Withdraw(userAddr, adjustedAmount, _handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Borrow action\r\n\t* @param unifiedTokenAmount The borrow amount\r\n\t* @param flag Flag for the full calcuation mode\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction borrow(uint256 unifiedTokenAmount, bool flag) external override returns (bool)\r\n\t{\r\n\t\taddress payable userAddr = msg.sender;\r\n\t\tuint256 _handlerID = handlerID;\r\n\r\n\t\tuint256 userLiquidityAmount;\r\n\t\tuint256 userCollateralizableAmount;\r\n\t\tuint256 price;\r\n\t\t(userLiquidityAmount, userCollateralizableAmount, , , , price) = marketManager.applyInterestHandlers(userAddr, _handlerID, flag);\r\n\r\n\t\tuint256 adjustedAmount = _getUserActionMaxBorrowAmount(unifiedTokenAmount, userLiquidityAmount);\r\n\t\trequire(unifiedMul(adjustedAmount, price) <= handlerDataStorage.getLimitOfAction(), EXCEED_LIMIT);\r\n\r\n\t\thandlerDataStorage.addBorrowAmount(userAddr, adjustedAmount);\r\n\r\n\t\t_transfer(userAddr, adjustedAmount);\r\n\r\n\t\temit Borrow(userAddr, adjustedAmount, _handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Repay action\r\n\t* @param unifiedTokenAmount The repay amount\r\n\t* @param flag Flag for the full calcuation mode\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction repay(uint256 unifiedTokenAmount, bool flag) external payable override returns (bool)\r\n\t{\r\n\t\trequire(msg.value == 0, USE_ARG);\r\n\t\taddress payable userAddr = msg.sender;\r\n\t\tuint256 _handlerID = handlerID;\r\n\r\n\t\tif(flag) {\r\n\t\t\t// flag is true, update interest, reward all handlers\r\n\t\t\tmarketManager.applyInterestHandlers(userAddr, _handlerID, flag);\r\n\t\t} else {\r\n\t\t\tmarketManager.rewardUpdateOfInAction(userAddr, _handlerID);\r\n\t\t\t_applyInterest(userAddr);\r\n\t\t}\r\n\r\n\t\tuint256 userBorrowAmount = handlerDataStorage.getUserIntraBorrowAmount(userAddr);\r\n\r\n\t\tif (userBorrowAmount < unifiedTokenAmount)\r\n\t\t{\r\n\t\t\tunifiedTokenAmount = userBorrowAmount;\r\n\t\t}\r\n\r\n\t\thandlerDataStorage.subBorrowAmount(userAddr, unifiedTokenAmount);\r\n\r\n\t\t_transferFrom(userAddr, unifiedTokenAmount);\r\n\r\n\t\temit Repay(userAddr, unifiedTokenAmount, _handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\tfunction repayTo(uint256 unifiedTokenAmount, address payable toUser, bool flag) external payable returns (bool)\r\n\t{\r\n\t\trequire(msg.value == 0, USE_ARG);\r\n\t\tuint256 _handlerID = handlerID;\r\n\r\n\t\tif(flag) {\r\n\t\t\t// flag is true, update interest, reward all handlers\r\n\t\t\tmarketManager.applyInterestHandlers(toUser, _handlerID, flag);\r\n\t\t} else {\r\n\t\t\tmarketManager.rewardUpdateOfInAction(toUser, _handlerID);\r\n\t\t\t_applyInterest(toUser);\r\n\t\t}\r\n\r\n\t\tuint256 userBorrowAmount = handlerDataStorage.getUserIntraBorrowAmount(toUser);\r\n\r\n\t\tif (userBorrowAmount < unifiedTokenAmount)\r\n\t\t{\r\n\t\t\tunifiedTokenAmount = userBorrowAmount;\r\n\t\t}\r\n\r\n\t\thandlerDataStorage.subBorrowAmount(toUser, unifiedTokenAmount);\r\n\r\n\t\t_transferFrom(msg.sender, unifiedTokenAmount);\r\n\r\n\t\temit Repay(toUser, unifiedTokenAmount, _handlerID);\r\n\t\treturn true;\r\n\t}\r\n\r\n\tfunction executeFlashloan(\r\n\t\taddress receiverAddress,\r\n\t\tuint256 amount\r\n    ) external onlyMarketManager override returns (bool) {\r\n\t\t_transfer(payable(receiverAddress), amount);\r\n    \treturn true;\r\n\t}\r\n\r\n\tfunction depositFlashloanFee(\r\n\t\tuint256 amount\r\n\t) external onlyMarketManager override returns (bool) {\r\n\t\thandlerDataStorage.addReservedAmount(amount);\r\n\t\thandlerDataStorage.addDepositTotalAmount(amount);\r\n\r\n\t\temit ReserveDeposit(amount, handlerID);\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev liquidate delinquentBorrower's partial(or can total) asset\r\n\t* @param delinquentBorrower The user addresss of liquidation target\r\n\t* @param liquidateAmount The amount of liquidator request\r\n\t* @param liquidator The address of a user executing liquidate\r\n\t* @param rewardHandlerID The handler id of delinquentBorrower's collateral for receive\r\n\t* @return (liquidateAmount, delinquentDepositAsset, delinquentBorrowAsset), result of liquidate\r\n\t*/\r\n\tfunction partialLiquidationUser(address payable delinquentBorrower, uint256 liquidateAmount, address payable liquidator, uint256 rewardHandlerID) onlyMarketManager external override returns (uint256, uint256, uint256)\r\n\t{\r\n\t\t/* over paied amount compaction */\r\n\t\tuint256 tmp;\r\n\t\tuint256 delinquentMarginCallDeposit;\r\n\t\tuint256 delinquentDepositAsset;\r\n\t\tuint256 delinquentBorrowAsset;\r\n\t\tuint256 liquidatorLiquidityAmount;\r\n\r\n      /* apply interest for sync \"latest\" asset for delinquentBorrower and liquidator */\r\n\t\t(, , delinquentMarginCallDeposit, delinquentDepositAsset, delinquentBorrowAsset, ) = marketManager.applyInterestHandlers(delinquentBorrower, handlerID, false);\r\n\t\t(, liquidatorLiquidityAmount, , , , ) = marketManager.applyInterestHandlers(liquidator, handlerID, false);\r\n\r\n      /* check delinquentBorrower liquidatable */\r\n\t\trequire(delinquentMarginCallDeposit <= delinquentBorrowAsset, NO_LIQUIDATION);\r\n\r\n\t\ttmp = handlerDataStorage.getUserIntraDepositAmount(liquidator);\r\n\t\tif (tmp <= liquidateAmount)\r\n\t\t{\r\n\t\t\tliquidateAmount = tmp;\r\n\t\t}\r\n\r\n\t\ttmp = handlerDataStorage.getUserIntraBorrowAmount(delinquentBorrower);\r\n\t\tif (tmp <= liquidateAmount)\r\n\t\t{\r\n\t\t\tliquidateAmount = tmp;\r\n\t\t}\r\n\r\n      /* get maximum \"receive handler\" amount by liquidate amount */\r\n\t\tliquidateAmount = marketManager.getMaxLiquidationReward(delinquentBorrower, handlerID, liquidateAmount, rewardHandlerID, unifiedDiv(delinquentBorrowAsset, delinquentDepositAsset));\r\n\r\n      /* check liquidator has enough amount for liquidation */\r\n\t\trequire(liquidatorLiquidityAmount > liquidateAmount, NO_EFFECTIVE_BALANCE);\r\n\r\n      /* update storage for liquidate*/\r\n\t\thandlerDataStorage.subDepositAmount(liquidator, liquidateAmount);\r\n\r\n\t\thandlerDataStorage.subBorrowAmount(delinquentBorrower, liquidateAmount);\r\n\r\n\t\treturn (liquidateAmount, delinquentDepositAsset, delinquentBorrowAsset);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev liquidator receive delinquentBorrower's collateral after liquidate delinquentBorrower's asset\r\n\t* @param delinquentBorrower The user addresss of liquidation target\r\n\t* @param liquidationAmountWithReward The amount of liquidator receiving delinquentBorrower's collateral\r\n\t* @param liquidator The address of a user executing liquidate\r\n\t* @return The amount of token transfered(in storage)\r\n\t*/\r\n\tfunction partialLiquidationUserReward(address payable delinquentBorrower, uint256 liquidationAmountWithReward, address payable liquidator) onlyMarketManager external override returns (uint256)\r\n\t{\r\n\t\tmarketManager.rewardUpdateOfInAction(delinquentBorrower, handlerID);\r\n\t\t_applyInterest(delinquentBorrower);\r\n\t\t/* check delinquentBorrower's collateral enough */\r\n\t\tuint256 collateralAmount = handlerDataStorage.getUserIntraDepositAmount(delinquentBorrower);\r\n\t\trequire(collateralAmount >= liquidationAmountWithReward, NO_LIQUIDATION_REWARD);\r\n\r\n\t\t/* collateral transfer */\r\n\t\thandlerDataStorage.subDepositAmount(delinquentBorrower, liquidationAmountWithReward);\r\n\r\n\t\t_transfer(liquidator, liquidationAmountWithReward);\r\n\r\n\t\treturn liquidationAmountWithReward;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get borrowLimit and marginCallLimit\r\n\t* @return borrowLimit and marginCallLimit\r\n\t*/\r\n\tfunction getTokenHandlerLimit() external view override returns (uint256, uint256)\r\n\t{\r\n\t\treturn handlerDataStorage.getLimit();\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Set the borrow limit of the handler through a specific handlerID\r\n\t* @param borrowLimit The borrow limit\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction setTokenHandlerBorrowLimit(uint256 borrowLimit) onlyOwner external override returns (bool)\r\n\t{\r\n\t\thandlerDataStorage.setBorrowLimit(borrowLimit);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Set the liquidation limit of the handler through a specific handlerID\r\n\t* @param marginCallLimit The liquidation limit\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction setTokenHandlerMarginCallLimit(uint256 marginCallLimit) onlyOwner external override returns (bool)\r\n\t{\r\n\t\thandlerDataStorage.setMarginCallLimit(marginCallLimit);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the liquidation limit of handler through a specific handlerID\r\n\t* @return The liquidation limit\r\n\t*/\r\n\tfunction getTokenHandlerMarginCallLimit() external view override returns (uint256)\r\n\t{\r\n\t\treturn handlerDataStorage.getMarginCallLimit();\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the borrow limit of the handler through a specific handlerID\r\n\t* @return The borrow limit\r\n\t*/\r\n\tfunction getTokenHandlerBorrowLimit() external view override returns (uint256)\r\n\t{\r\n\t\treturn handlerDataStorage.getBorrowLimit();\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the maximum amount that user can borrow\r\n\t* @param userAddr The address of user\r\n\t* @return the maximum amount that user can borrow\r\n\t*/\r\n\tfunction getUserMaxBorrowAmount(address payable userAddr) external view override returns (uint256)\r\n\t{\r\n\t\treturn _getUserMaxBorrowAmount(userAddr);\r\n\t}\r\n\r\n  /**\r\n\t* @dev Get (total deposit - total borrow) of the handler including interest\r\n\t* @param userAddr The user address(for wrapping function, unused)\r\n\t* @return (total deposit - total borrow) of the handler including interest\r\n\t*/\r\n\tfunction getTokenLiquidityAmountWithInterest(address payable userAddr) external view override returns (uint256)\r\n  {\r\n    return _getTokenLiquidityAmountWithInterest(userAddr);\r\n  }\r\n\r\n\t/**\r\n\t* @dev Get the maximum amount that user can borrow\r\n\t* @param userAddr The address of user\r\n\t* @return the maximum amount that user can borrow\r\n\t*/\r\n\tfunction _getUserMaxBorrowAmount(address payable userAddr) internal view returns (uint256)\r\n\t{\r\n\t\t/* Prevent Action: over \"Token Liquidity\" amount*/\r\n\t\tuint256 handlerLiquidityAmount = _getTokenLiquidityLimitAmountWithInterest(userAddr);\r\n\t\t/* Prevent Action: over \"CREDIT\" amount */\r\n\t\tuint256 userLiquidityAmount = marketManager.getUserExtraLiquidityAmount(userAddr, handlerID);\r\n\t\tuint256 minAmount = userLiquidityAmount;\r\n\t\tif (handlerLiquidityAmount < minAmount)\r\n\t\t{\r\n\t\t\tminAmount = handlerLiquidityAmount;\r\n\t\t}\r\n\r\n\t\treturn minAmount;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the maximum amount that user can borrow\r\n\t* @param requestedAmount The amount of token to borrow\r\n\t* @param userLiquidityAmount The amount of liquidity that users can borrow\r\n\t* @return the maximum amount that user can borrow\r\n\t*/\r\n\tfunction _getUserActionMaxBorrowAmount(uint256 requestedAmount, uint256 userLiquidityAmount) internal view returns (uint256)\r\n\t{\r\n\t\t/* Prevent Action: over \"Token Liquidity\" amount*/\r\n\t\tuint256 handlerLiquidityAmount = _getTokenLiquidityLimitAmount();\r\n\r\n\t\t/* select minimum of handlerLiqudity and user liquidity */\r\n\t\tuint256 minAmount = requestedAmount;\r\n\r\n\t\tif (minAmount > handlerLiquidityAmount)\r\n\t\t{\r\n\t\t\tminAmount = handlerLiquidityAmount;\r\n\t\t}\r\n\r\n\t\tif (minAmount > userLiquidityAmount)\r\n\t\t{\r\n\t\t\tminAmount = userLiquidityAmount;\r\n\t\t}\r\n\r\n\t\treturn minAmount;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the maximum amount that users can withdraw\r\n\t* @param userAddr The address of user\r\n\t* @return the maximum amount that users can withdraw\r\n\t*/\r\n\tfunction getUserMaxWithdrawAmount(address payable userAddr) external view override returns (uint256)\r\n\t{\r\n\t\treturn _getUserMaxWithdrawAmount(userAddr);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the rate of SIR and BIR\r\n\t* @return The rate of SIR and BIR\r\n\t*/\r\n\tfunction getSIRandBIR() external view override returns (uint256, uint256)\r\n\t{\r\n\t\tuint256 totalDepositAmount = handlerDataStorage.getDepositTotalAmount();\r\n\t\tuint256 totalBorrowAmount = handlerDataStorage.getBorrowTotalAmount();\r\n\r\n\t\treturn interestModelInstance.getSIRandBIR(totalDepositAmount, totalBorrowAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the maximum amount that users can withdraw\r\n\t* @param userAddr The address of user\r\n\t* @return the maximum amount that users can withdraw\r\n\t*/\r\n\tfunction _getUserMaxWithdrawAmount(address payable userAddr) internal view returns (uint256)\r\n\t{\r\n\t\tuint256 depositAmountWithInterest;\r\n\t\tuint256 borrowAmountWithInterest;\r\n\t\t(depositAmountWithInterest, borrowAmountWithInterest) = _getUserAmountWithInterest(userAddr);\r\n\r\n\t\tuint256 handlerLiquidityAmount = _getTokenLiquidityAmountWithInterest(userAddr);\r\n\r\n\t\tuint256 userLiquidityAmount = marketManager.getUserCollateralizableAmount(userAddr, handlerID);\r\n\r\n\t\t/* Prevent Action: over \"DEPOSIT\" amount */\r\n\t\tuint256 minAmount = depositAmountWithInterest;\r\n\t\t/* Prevent Action: over \"CREDIT\" amount */\r\n\t\tif (minAmount > userLiquidityAmount)\r\n\t\t{\r\n\t\t\tminAmount = userLiquidityAmount;\r\n\t\t}\r\n\r\n\t\tif (minAmount > handlerLiquidityAmount)\r\n\t\t{\r\n\t\t\tminAmount = handlerLiquidityAmount;\r\n\t\t}\r\n\r\n\t\treturn minAmount;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the maximum amount that users can withdraw\r\n\t* @param userAddr The address of user\r\n\t* @param requestedAmount The amount of token to withdraw\r\n\t* @param collateralableAmount The amount of liquidity that users can borrow\r\n\t* @return the maximum amount that users can withdraw\r\n\t*/\r\n\tfunction _getUserActionMaxWithdrawAmount(address payable userAddr, uint256 requestedAmount, uint256 collateralableAmount) internal view returns (uint256)\r\n\t{\r\n\t\tuint256 depositAmount = handlerDataStorage.getUserIntraDepositAmount(userAddr);\r\n\r\n\t\tuint256 handlerLiquidityAmount = _getTokenLiquidityAmount();\r\n\r\n\t\t/* select minimum among deposited, requested and collateralable*/\r\n\t\tuint256 minAmount = depositAmount;\r\n\r\n\t\tif (minAmount > requestedAmount)\r\n\t\t{\r\n\t\t\tminAmount = requestedAmount;\r\n\t\t}\r\n\r\n\t\tif (minAmount > collateralableAmount)\r\n\t\t{\r\n\t\t\tminAmount = collateralableAmount;\r\n\t\t}\r\n\r\n\t\tif (minAmount > handlerLiquidityAmount)\r\n\t\t{\r\n\t\t\tminAmount = handlerLiquidityAmount;\r\n\t\t}\r\n\r\n\t\treturn minAmount;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the maximum amount that users can repay\r\n\t* @param userAddr The address of user\r\n\t* @return the maximum amount that users can repay\r\n\t*/\r\n\tfunction getUserMaxRepayAmount(address payable userAddr) external view override returns (uint256)\r\n\t{\r\n\t\tuint256 depositAmountWithInterest;\r\n\t\tuint256 borrowAmountWithInterest;\r\n\t\t(depositAmountWithInterest, borrowAmountWithInterest) = _getUserAmountWithInterest(userAddr);\r\n\r\n\t\treturn borrowAmountWithInterest;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Update (apply) interest entry point (external)\r\n\t* @param userAddr The user address\r\n\t* @return \"latest\" (userDepositAmount, userBorrowAmount)\r\n\t*/\r\n\tfunction applyInterest(address payable userAddr) external override returns (uint256, uint256)\r\n\t{\r\n\t\treturn _applyInterest(userAddr);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Update (apply) interest entry point (external)\r\n\t* @param userAddr The user address\r\n\t* @return \"latest\" (userDepositAmount, userBorrowAmount)\r\n\t*/\r\n\tfunction _applyInterest(address payable userAddr) internal returns (uint256, uint256)\r\n\t{\r\n\t\t_checkNewCustomer(userAddr);\r\n\t\t_checkFirstAction();\r\n\t\treturn _updateInterestAmount(userAddr);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Check whether a given userAddr is a new user or not\r\n\t* @param userAddr The user address\r\n\t* @return true if the user is a new user; false otherwise.\r\n\t*/\r\n\tfunction _checkNewCustomer(address payable userAddr) internal returns (bool)\r\n\t{\r\n\t\tIMarketHandlerDataStorage _handlerDataStorage = handlerDataStorage;\r\n\t\tif (_handlerDataStorage.getUserAccessed(userAddr))\r\n\t\t{\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\t/* hotfix */\r\n\t\t_handlerDataStorage.setUserAccessed(userAddr, true);\r\n\r\n\t\t(uint256 gDEXR, uint256 gBEXR) = _handlerDataStorage.getGlobalEXR();\r\n\t\t_handlerDataStorage.setUserEXR(userAddr, gDEXR, gBEXR);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the address of the token that the handler is dealing with\r\n\t* (CoinHandler don't deal with tokens in coin handlers)\r\n\t* @return The address of the token\r\n\t*/\r\n\tfunction getERC20Addr() external override view returns (address)\r\n\t{\r\n\t\treturn address(erc20Instance);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the amount of deposit and borrow of the user\r\n\t* @param userAddr The address of user\r\n\t* (depositAmount, borrowAmount)\r\n\t*/\r\n\tfunction getUserAmount(address payable userAddr) external view override returns (uint256, uint256)\r\n\t{\r\n\t\tuint256 depositAmount = handlerDataStorage.getUserIntraDepositAmount(userAddr);\r\n\t\tuint256 borrowAmount = handlerDataStorage.getUserIntraBorrowAmount(userAddr);\r\n\r\n\t\treturn (depositAmount, borrowAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the amount of user's deposit\r\n\t* @param userAddr The address of user\r\n\t* @return the amount of user's deposit\r\n\t*/\r\n\tfunction getUserIntraDepositAmount(address payable userAddr) external view returns (uint256)\r\n\t{\r\n\t\treturn handlerDataStorage.getUserIntraDepositAmount(userAddr);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the amount of user's borrow\r\n\t* @param userAddr The address of user\r\n\t* @return the amount of user's borrow\r\n\t*/\r\n\tfunction getUserIntraBorrowAmount(address payable userAddr) external view returns (uint256)\r\n\t{\r\n\t\treturn handlerDataStorage.getUserIntraBorrowAmount(userAddr);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the amount of handler's total deposit\r\n\t* @return the amount of handler's total deposit\r\n\t*/\r\n\tfunction getDepositTotalAmount() external view override returns (uint256)\r\n\t{\r\n\t\treturn handlerDataStorage.getDepositTotalAmount();\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the amount of handler's total borrow\r\n\t* @return the amount of handler's total borrow\r\n\t*/\r\n\tfunction getBorrowTotalAmount() external view override returns (uint256)\r\n\t{\r\n\t\treturn handlerDataStorage.getBorrowTotalAmount();\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the amount of deposit and borrow of user including interest\r\n\t* @param userAddr The user address\r\n\t* @return (userDepositAmount, userBorrowAmount)\r\n\t*/\r\n\tfunction getUserAmountWithInterest(address payable userAddr) external view override returns (uint256, uint256)\r\n\t{\r\n\t\treturn _getUserAmountWithInterest(userAddr);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the address of owner\r\n\t* @return the address of owner\r\n\t*/\r\n\tfunction getOwner() public view returns (address)\r\n\t{\r\n\t\treturn owner;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Check first action of user in the This Block (external)\r\n\t* @return true for first action\r\n\t*/\r\n\tfunction checkFirstAction() onlyMarketManager external override returns (bool)\r\n\t{\r\n\t\treturn _checkFirstAction();\r\n\t}\r\n\r\n  /**\r\n\t* @dev Convert amount of handler's unified decimals to amount of token's underlying decimals\r\n\t* @param unifiedTokenAmount The amount of unified decimals\r\n\t* @return (underlyingTokenAmount)\r\n\t*/\r\n\tfunction convertUnifiedToUnderlying(uint256 unifiedTokenAmount) external override view returns (uint256)\r\n\t{\r\n\t\treturn _convertUnifiedToUnderlying(unifiedTokenAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Check first action of user in the This Block (external)\r\n\t* @return true for first action\r\n\t*/\r\n\tfunction _checkFirstAction() internal returns (bool)\r\n\t{\r\n\t\tIMarketHandlerDataStorage _handlerDataStorage = handlerDataStorage;\r\n\r\n\t\tuint256 lastUpdatedBlock = _handlerDataStorage.getLastUpdatedBlock();\r\n\t\tuint256 currentBlockNumber = _blockContext();\r\n\t\tuint256 blockDelta = sub(currentBlockNumber, lastUpdatedBlock);\r\n\r\n\t\tif (blockDelta > 0)\r\n\t\t{\r\n\t\t\t_handlerDataStorage.setBlocks(currentBlockNumber, blockDelta);\r\n\t\t\t_handlerDataStorage.syncActionEXR();\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\treturn false;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev calculate (apply) interest (internal) and call storage update function\r\n\t* @param userAddr The user address\r\n\t* @return \"latest\" (userDepositAmount, userBorrowAmount)\r\n\t*/\r\n\tfunction _updateInterestAmount(address payable userAddr) internal returns (uint256, uint256)\r\n\t{\r\n\t\tbool depositNegativeFlag;\r\n\t\tuint256 deltaDepositAmount;\r\n\t\tuint256 globalDepositEXR;\r\n\r\n\t\tbool borrowNegativeFlag;\r\n\t\tuint256 deltaBorrowAmount;\r\n\t\tuint256 globalBorrowEXR;\r\n      /* calculate interest amount and params by call Interest Model */\r\n\t\t(depositNegativeFlag, deltaDepositAmount, globalDepositEXR, borrowNegativeFlag, deltaBorrowAmount, globalBorrowEXR) = interestModelInstance.getInterestAmount(address(handlerDataStorage), userAddr, false);\r\n\r\n\t\t/* update new global EXR to user EXR*/\r\n\t\thandlerDataStorage.setEXR(userAddr, globalDepositEXR, globalBorrowEXR);\r\n\r\n\t\t/* call storage update function for update \"latest\" interest information  */\r\n\t\treturn _setAmountReflectInterest(userAddr, depositNegativeFlag, deltaDepositAmount, borrowNegativeFlag, deltaBorrowAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Apply the user's interest\r\n\t* @param userAddr The user address\r\n\t* @param depositNegativeFlag the sign of deltaDepositAmount (true for negative)\r\n\t* @param deltaDepositAmount The delta amount of deposit\r\n\t* @param borrowNegativeFlag the sign of deltaBorrowAmount (true for negative)\r\n\t* @param deltaBorrowAmount The delta amount of borrow\r\n\t* @return \"latest\" (userDepositAmount, userBorrowAmount)\r\n\t*/\r\n\tfunction _setAmountReflectInterest(address payable userAddr, bool depositNegativeFlag, uint256 deltaDepositAmount, bool borrowNegativeFlag, uint256 deltaBorrowAmount) internal returns (uint256, uint256)\r\n\t{\r\n\t\tuint256 depositTotalAmount;\r\n\t\tuint256 userDepositAmount;\r\n\t\tuint256 borrowTotalAmount;\r\n\t\tuint256 userBorrowAmount;\r\n      /* call _getAmountWithInterest for adding user storage amount and interest delta amount (deposit and borrow)*/\r\n\t\t(depositTotalAmount, userDepositAmount, borrowTotalAmount, userBorrowAmount) = _getAmountWithInterest(userAddr, depositNegativeFlag, deltaDepositAmount, borrowNegativeFlag, deltaBorrowAmount);\r\n\r\n\t\t/* update user amount in storage*/\r\n\t\thandlerDataStorage.setAmount(userAddr, depositTotalAmount, borrowTotalAmount, userDepositAmount, userBorrowAmount);\r\n\r\n      /* update \"spread between deposits and borrows\" */\r\n\t\t_updateReservedAmount(depositNegativeFlag, deltaDepositAmount, borrowNegativeFlag, deltaBorrowAmount);\r\n\r\n\t\treturn (userDepositAmount, userBorrowAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the \"latest\" user amount of deposit and borrow including interest (internal, view)\r\n\t* @param userAddr The user address\r\n\t* @return \"latest\" (userDepositAmount, userBorrowAmount)\r\n\t*/\r\n\tfunction _getUserAmountWithInterest(address payable userAddr) internal view returns (uint256, uint256)\r\n\t{\r\n\t\tuint256 depositTotalAmount;\r\n\t\tuint256 userDepositAmount;\r\n\t\tuint256 borrowTotalAmount;\r\n\t\tuint256 userBorrowAmount;\r\n\t\t(depositTotalAmount, userDepositAmount, borrowTotalAmount, userBorrowAmount) = _calcAmountWithInterest(userAddr);\r\n\r\n\t\treturn (userDepositAmount, userBorrowAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the \"latest\" handler amount of deposit and borrow including interest (internal, view)\r\n\t* @param userAddr The user address\r\n\t* @return \"latest\" (depositTotalAmount, borrowTotalAmount)\r\n\t*/\r\n\tfunction _getTotalAmountWithInterest(address payable userAddr) internal view returns (uint256, uint256)\r\n\t{\r\n\t\tuint256 depositTotalAmount;\r\n\t\tuint256 userDepositAmount;\r\n\t\tuint256 borrowTotalAmount;\r\n\t\tuint256 userBorrowAmount;\r\n\t\t(depositTotalAmount, userDepositAmount, borrowTotalAmount, userBorrowAmount) = _calcAmountWithInterest(userAddr);\r\n\r\n\t\treturn (depositTotalAmount, borrowTotalAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev The deposit and borrow amount with interest for the user\r\n\t* @param userAddr The user address\r\n\t* @return \"latest\" (depositTotalAmount, userDepositAmount, borrowTotalAmount, userBorrowAmount)\r\n\t*/\r\n\tfunction _calcAmountWithInterest(address payable userAddr) internal view returns (uint256, uint256, uint256, uint256)\r\n\t{\r\n\t\tbool depositNegativeFlag;\r\n\t\tuint256 deltaDepositAmount;\r\n\t\tuint256 globalDepositEXR;\r\n\r\n\t\tbool borrowNegativeFlag;\r\n\t\tuint256 deltaBorrowAmount;\r\n\t\tuint256 globalBorrowEXR;\r\n\t\t(depositNegativeFlag, deltaDepositAmount, globalDepositEXR, borrowNegativeFlag, deltaBorrowAmount, globalBorrowEXR) = interestModelInstance.getInterestAmount(address(handlerDataStorage), userAddr, true);\r\n\r\n\t\treturn _getAmountWithInterest(userAddr, depositNegativeFlag, deltaDepositAmount, borrowNegativeFlag, deltaBorrowAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Calculate \"latest\" amount with interest for the block delta\r\n\t* @param userAddr The user address\r\n\t* @param depositNegativeFlag the sign of deltaDepositAmount (true for negative)\r\n\t* @param deltaDepositAmount The delta amount of deposit\r\n\t* @param borrowNegativeFlag the sign of deltaBorrowAmount (true for negative)\r\n\t* @param deltaBorrowAmount The delta amount of borrow\r\n\t* @return \"latest\" (depositTotalAmount, userDepositAmount, borrowTotalAmount, userBorrowAmount)\r\n\t*/\r\n\tfunction _getAmountWithInterest(address payable userAddr, bool depositNegativeFlag, uint256 deltaDepositAmount, bool borrowNegativeFlag, uint256 deltaBorrowAmount) internal view returns (uint256, uint256, uint256, uint256)\r\n\t{\r\n\t\tuint256 depositTotalAmount;\r\n\t\tuint256 userDepositAmount;\r\n\t\tuint256 borrowTotalAmount;\r\n\t\tuint256 userBorrowAmount;\r\n\t\t(depositTotalAmount, borrowTotalAmount, userDepositAmount, userBorrowAmount) = handlerDataStorage.getAmount(userAddr);\r\n\r\n\t\tif (depositNegativeFlag)\r\n\t\t{\r\n\t\t\tdepositTotalAmount = sub(depositTotalAmount, deltaDepositAmount);\r\n\t\t\tuserDepositAmount = sub(userDepositAmount, deltaDepositAmount);\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tdepositTotalAmount = add(depositTotalAmount, deltaDepositAmount);\r\n\t\t\tuserDepositAmount = add(userDepositAmount, deltaDepositAmount);\r\n\t\t}\r\n\r\n\t\tif (borrowNegativeFlag)\r\n\t\t{\r\n\t\t\tborrowTotalAmount = sub(borrowTotalAmount, deltaBorrowAmount);\r\n\t\t\tuserBorrowAmount = sub(userBorrowAmount, deltaBorrowAmount);\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tborrowTotalAmount = add(borrowTotalAmount, deltaBorrowAmount);\r\n\t\t\tuserBorrowAmount = add(userBorrowAmount, deltaBorrowAmount);\r\n\t\t}\r\n\r\n\t\treturn (depositTotalAmount, userDepositAmount, borrowTotalAmount, userBorrowAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Update the amount of the reserve\r\n\t* @param depositNegativeFlag the sign of deltaDepositAmount (true for negative)\r\n\t* @param deltaDepositAmount The delta amount of deposit\r\n\t* @param borrowNegativeFlag the sign of deltaBorrowAmount (true for negative)\r\n\t* @param deltaBorrowAmount The delta amount of borrow\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction _updateReservedAmount(bool depositNegativeFlag, uint256 deltaDepositAmount, bool borrowNegativeFlag, uint256 deltaBorrowAmount) internal returns (bool)\r\n\t{\r\n\t\tint256 signedDeltaDepositAmount = int(deltaDepositAmount);\r\n\t\tint256 signedDeltaBorrowAmount = int(deltaBorrowAmount);\r\n\t\tif (depositNegativeFlag)\r\n\t\t{\r\n\t\t\tsignedDeltaDepositAmount = signedDeltaDepositAmount * (-1);\r\n\t\t}\r\n\r\n\t\tif (borrowNegativeFlag)\r\n\t\t{\r\n\t\t\tsignedDeltaBorrowAmount = signedDeltaBorrowAmount * (-1);\r\n\t\t}\r\n\r\n      /* signedDeltaReservedAmount is singed amount */\r\n\t\tint256 signedDeltaReservedAmount = signedSub(signedDeltaBorrowAmount, signedDeltaDepositAmount);\r\n\t\thandlerDataStorage.updateSignedReservedAmount(signedDeltaReservedAmount);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Sends the handler's assets to the given user\r\n\t* @param userAddr The address of user\r\n\t* @param unifiedTokenAmount The amount of token to send in unified token amount\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction _transfer(address payable userAddr, uint256 unifiedTokenAmount) internal returns (bool)\r\n\t{\r\n\t\tuint256 beforeBalance = erc20Instance.balanceOf(userAddr);\r\n\t\tuint256 underlyingAmount = _convertUnifiedToUnderlying(unifiedTokenAmount);\r\n\r\n\t\terc20Instance.transfer(userAddr, underlyingAmount);\r\n\r\n\t\tuint256 afterBalance = erc20Instance.balanceOf(userAddr);\r\n\t\trequire(underlyingAmount == sub(afterBalance, beforeBalance), TRANSFER);\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Sends the assets from the user to the contract\r\n\t* @param userAddr The address of user\r\n\t* @param unifiedTokenAmount The amount of token to send in unified token amount\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction _transferFrom(address payable userAddr, uint256 unifiedTokenAmount) internal returns (bool)\r\n\t{\r\n\t\tuint256 beforeBalance = erc20Instance.balanceOf(userAddr);\r\n\t\tuint256 underlyingAmount = _convertUnifiedToUnderlying(unifiedTokenAmount);\r\n\r\n\t\terc20Instance.transferFrom(userAddr, address(this), underlyingAmount);\r\n\r\n\t\tuint256 afterBalance = erc20Instance.balanceOf(userAddr);\r\n\t\trequire(underlyingAmount == sub(beforeBalance, afterBalance), TRANSFER);\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Convert amount of handler's unified decimals to amount of token's underlying decimals\r\n\t* @param unifiedTokenAmount The amount of unified decimals\r\n\t* @return (underlyingTokenAmount)\r\n\t*/\r\n\tfunction _convertUnifiedToUnderlying(uint256 unifiedTokenAmount) internal view returns (uint256)\r\n\t{\r\n\t\treturn div(mul(unifiedTokenAmount, underlyingTokenDecimal), unifiedTokenDecimal);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Convert amount of token's underlying decimals to amount of handler's unified decimals\r\n\t* @param underlyingTokenAmount The amount of underlying decimals\r\n\t* @return (unifiedTokenAmount)\r\n\t*/\r\n\tfunction _convertUnderlyingToUnified(uint256 underlyingTokenAmount) internal view returns (uint256)\r\n\t{\r\n\t\treturn div(mul(underlyingTokenAmount, unifiedTokenDecimal), underlyingTokenDecimal);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get (total deposit - total borrow) of the handler\r\n\t* @return (total deposit - total borrow) of the handler\r\n\t*/\r\n\tfunction _getTokenLiquidityAmount() internal view returns (uint256)\r\n\t{\r\n\t\tIMarketHandlerDataStorage _handlerDataStorage = handlerDataStorage;\r\n\t\tuint256 depositTotalAmount;\r\n\t\tuint256 borrowTotalAmount;\r\n\t\t(depositTotalAmount, borrowTotalAmount) = _handlerDataStorage.getHandlerAmount();\r\n\r\n\t\tif (depositTotalAmount == 0)\r\n\t\t{\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tif (depositTotalAmount < borrowTotalAmount)\r\n\t\t{\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\treturn sub(depositTotalAmount, borrowTotalAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get (total deposit * liquidity limit - total borrow) of the handler\r\n\t* @return (total deposit * liquidity limit - total borrow) of the handler\r\n\t*/\r\n\tfunction _getTokenLiquidityLimitAmount() internal view returns (uint256)\r\n\t{\r\n\t\tIMarketHandlerDataStorage _handlerDataStorage = handlerDataStorage;\r\n\t\tuint256 depositTotalAmount;\r\n\t\tuint256 borrowTotalAmount;\r\n\t\t(depositTotalAmount, borrowTotalAmount) = _handlerDataStorage.getHandlerAmount();\r\n\r\n\t\tif (depositTotalAmount == 0)\r\n\t\t{\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tuint256 liquidityDeposit = unifiedMul(depositTotalAmount, _handlerDataStorage.getLiquidityLimit());\r\n\t\tif (liquidityDeposit < borrowTotalAmount)\r\n\t\t{\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\treturn sub(liquidityDeposit, borrowTotalAmount);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get (total deposit - total borrow) of the handler including interest\r\n\t* @param userAddr The user address(for wrapping function, unused)\r\n\t* @return (total deposit - total borrow) of the handler including interest\r\n\t*/\r\n\tfunction _getTokenLiquidityAmountWithInterest(address payable userAddr) internal view returns (uint256)\r\n\t{\r\n\t\tuint256 depositTotalAmount;\r\n\t\tuint256 borrowTotalAmount;\r\n\t\t(depositTotalAmount, borrowTotalAmount) = _getTotalAmountWithInterest(userAddr);\r\n\r\n\t\tif (depositTotalAmount == 0)\r\n\t\t{\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tif (depositTotalAmount < borrowTotalAmount)\r\n\t\t{\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\treturn sub(depositTotalAmount, borrowTotalAmount);\r\n\t}\r\n\t/**\r\n\t* @dev Get (total deposit * liquidity limit - total borrow) of the handler including interest\r\n\t* @param userAddr The user address(for wrapping function, unused)\r\n\t* @return (total deposit * liquidity limit - total borrow) of the handler including interest\r\n\t*/\r\n\tfunction _getTokenLiquidityLimitAmountWithInterest(address payable userAddr) internal view returns (uint256)\r\n\t{\r\n\t\tuint256 depositTotalAmount;\r\n\t\tuint256 borrowTotalAmount;\r\n\t\t(depositTotalAmount, borrowTotalAmount) = _getTotalAmountWithInterest(userAddr);\r\n\r\n\t\tif (depositTotalAmount == 0)\r\n\t\t{\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tuint256 liquidityDeposit = unifiedMul(depositTotalAmount, handlerDataStorage.getLiquidityLimit());\r\n\r\n\t\tif (liquidityDeposit < borrowTotalAmount)\r\n\t\t{\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\treturn sub(liquidityDeposit, borrowTotalAmount);\r\n\t}\r\n\r\n\t/**\r\n\t * @dev Set the unifiedPoint of token's decimal\r\n\t * @param _unifiedTokenDecimal the unifiedPoint of token's decimal\r\n\t * @return true (TODO: validate results)\r\n\t */\r\n\tfunction setUnifiedTokenDecimal(uint256 _unifiedTokenDecimal) onlyOwner external returns (bool)\r\n\t{\r\n\t\tunifiedTokenDecimal = _unifiedTokenDecimal;\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * @dev Get the decimal of token\r\n\t * @return (uint256, uint256) the decimal of token and the unifiedPoint of token's decimal\r\n\t */\r\n\tfunction getTokenDecimals() external view returns (uint256, uint256)\r\n\t{\r\n\t\treturn (underlyingTokenDecimal, unifiedTokenDecimal);\r\n\t}\r\n\r\n\t/**\r\n\t * @dev Get the unifiedPoint of token's decimal (for fixed decimal number)\r\n\t * @return the unifiedPoint of token's decimal\r\n\t */\r\n\t/* default: UnifiedTokenDecimal Function */\r\n\tfunction getUnifiedTokenDecimal() external view returns (uint256)\r\n\t{\r\n\t\treturn unifiedTokenDecimal;\r\n\t}\r\n\r\n\t/**\r\n\t * @dev Get the decimal of the underlying token\r\n\t * @return the decimal of the underlying token\r\n\t */\r\n\t/* default: UnderlyingTokenDecimal Function */\r\n\tfunction getUnderlyingTokenDecimal() external view returns (uint256)\r\n\t{\r\n\t\treturn underlyingTokenDecimal;\r\n\t}\r\n\r\n\t/**\r\n\t * @dev Set the decimal of token\r\n\t * @param _underlyingTokenDecimal the decimal of token\r\n\t * @return true (TODO: validate results)\r\n\t */\r\n\tfunction setUnderlyingTokenDecimal(uint256 _underlyingTokenDecimal) onlyOwner external returns (bool)\r\n\t{\r\n\t\tunderlyingTokenDecimal = _underlyingTokenDecimal;\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Set the address of the marketManager contract\r\n\t* @param marketManagerAddr The address of the marketManager contract\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction setMarketManager(address marketManagerAddr) onlyOwner public returns (bool)\r\n\t{\r\n\t\tmarketManager = IMarketManager(marketManagerAddr);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Set the address of the InterestModel contract\r\n\t* @param interestModelAddr The address of the InterestModel contract\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction setInterestModel(address interestModelAddr) onlyOwner public returns (bool)\r\n\t{\r\n\t\tinterestModelInstance = IInterestModel(interestModelAddr);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Set the address of the marketDataStorage contract\r\n\t* @param marketDataStorageAddr The address of the marketDataStorage contract\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction setHandlerDataStorage(address marketDataStorageAddr) onlyOwner public returns (bool)\r\n\t{\r\n\t\thandlerDataStorage = IMarketHandlerDataStorage(marketDataStorageAddr);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t * @dev Set the address and name of the underlying ERC-20 token\r\n\t * @param erc20Addr The address of ERC-20 token\r\n\t * @param name The name of ERC-20 token\r\n\t * @return true (TODO: validate results)\r\n\t */\r\n\tfunction setErc20(address erc20Addr, string memory name) onlyOwner public returns (bool)\r\n\t{\r\n\t\terc20Instance = IERC20(erc20Addr);\r\n\t\ttokenName = name;\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Set the address of the siHandlerDataStorage contract\r\n\t* @param SIHandlerDataStorageAddr The address of the siHandlerDataStorage contract\r\n\t* @return true (TODO: validate results)\r\n\t*/\r\n\tfunction setSiHandlerDataStorage(address SIHandlerDataStorageAddr) onlyOwner public returns (bool)\r\n\t{\r\n\t\tSIHandlerDataStorage = IMarketSIHandlerDataStorage(SIHandlerDataStorageAddr);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the address of the siHandlerDataStorage contract\r\n\t* @return The address of the siHandlerDataStorage contract\r\n\t*/\r\n\tfunction getSiHandlerDataStorage() public view returns (address)\r\n\t{\r\n\t\treturn address(SIHandlerDataStorage);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the address of the marketManager contract\r\n\t* @return The address of the marketManager contract\r\n\t*/\r\n\tfunction getMarketManagerAddr() public view returns (address)\r\n\t{\r\n\t\treturn address(marketManager);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the address of the InterestModel contract\r\n\t* @return The address of the InterestModel contract\r\n\t*/\r\n\tfunction getInterestModelAddr() public view returns (address)\r\n\t{\r\n\t\treturn address(interestModelInstance);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the address of handler's dataStroage\r\n\t* @return the address of handler's dataStroage\r\n\t*/\r\n\tfunction getHandlerDataStorageAddr() public view returns (address)\r\n\t{\r\n\t\treturn address(handlerDataStorage);\r\n\t}\r\n\r\n\t/**\r\n\t * @dev Get the address of the underlying ERC-20 token\r\n\t * @return The address of the underlying ERC-20 token\r\n\t */\r\n\tfunction getErc20Addr() public view returns (address)\r\n\t{\r\n\t\treturn address(erc20Instance);\r\n\t}\r\n\r\n\t/**\r\n\t* @dev Get the outgoing limit of tokens\r\n\t* @return The outgoing limit of tokens\r\n\t*/\r\n\tfunction getLimitOfAction() external view returns (uint256)\r\n\t{\r\n\t\treturn handlerDataStorage.getLimitOfAction();\r\n\t}\r\n\r\n\t/* ******************* Safe Math ******************* */\r\n  // from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol\r\n  // Subject to the MIT license.\r\n\tfunction add(uint256 a, uint256 b) internal pure returns (uint256)\r\n\t{\r\n\t\tuint256 c = a + b;\r\n\t\trequire(c >= a, \"add overflow\");\r\n\t\treturn c;\r\n\t}\r\n\r\n\tfunction sub(uint256 a, uint256 b) internal pure returns (uint256)\r\n\t{\r\n\t\treturn _sub(a, b, \"sub overflow\");\r\n\t}\r\n\r\n\tfunction mul(uint256 a, uint256 b) internal pure returns (uint256)\r\n\t{\r\n\t\treturn _mul(a, b);\r\n\t}\r\n\r\n\tfunction div(uint256 a, uint256 b) internal pure returns (uint256)\r\n\t{\r\n\t\treturn _div(a, b, \"div by zero\");\r\n\t}\r\n\r\n\tfunction mod(uint256 a, uint256 b) internal pure returns (uint256)\r\n\t{\r\n\t\treturn _mod(a, b, \"mod by zero\");\r\n\t}\r\n\r\n\tfunction _sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256)\r\n\t{\r\n\t\trequire(b <= a, errorMessage);\r\n\t\treturn a - b;\r\n\t}\r\n\r\n\tfunction _mul(uint256 a, uint256 b) internal pure returns (uint256)\r\n\t{\r\n\t\tif (a == 0)\r\n\t\t{\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tuint256 c = a * b;\r\n\t\trequire((c / a) == b, \"mul overflow\");\r\n\t\treturn c;\r\n\t}\r\n\r\n\tfunction _div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256)\r\n\t{\r\n\t\trequire(b > 0, errorMessage);\r\n\t\treturn a / b;\r\n\t}\r\n\r\n\tfunction _mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256)\r\n\t{\r\n\t\trequire(b != 0, errorMessage);\r\n\t\treturn a % b;\r\n\t}\r\n\r\n\tfunction unifiedDiv(uint256 a, uint256 b) internal pure returns (uint256)\r\n\t{\r\n\t\treturn _div(_mul(a, unifiedPoint), b, \"unified div by zero\");\r\n\t}\r\n\r\n\tfunction unifiedMul(uint256 a, uint256 b) internal pure returns (uint256)\r\n\t{\r\n\t\treturn _div(_mul(a, b), unifiedPoint, \"unified mul by zero\");\r\n\t}\r\n\r\n\tfunction signedAdd(int256 a, int256 b) internal pure returns (int256)\r\n\t{\r\n\t\tint256 c = a + b;\r\n\t\trequire(((b >= 0) && (c >= a)) || ((b < 0) && (c < a)), \"SignedSafeMath: addition overflow\");\r\n\t\treturn c;\r\n\t}\r\n\r\n\tfunction signedSub(int256 a, int256 b) internal pure returns (int256)\r\n\t{\r\n\t\tint256 c = a - b;\r\n\t\trequire(((b >= 0) && (c <= a)) || ((b < 0) && (c > a)), \"SignedSafeMath: subtraction overflow\");\r\n\t\treturn c;\r\n\t}\r\n}"}},"matchId":"6539600","creationMatch":"match","runtimeMatch":"match","verifiedAt":"2025-06-22T01:26:39Z","match":"match","chainId":"1","address":"0x47Be3d1DEF039Bd85e7570864bB5148E7491A65F"}