ERC-20
Overview
Max Total Supply
23,532.080958022178450817 MPL-LP
Holders
36
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 18 Decimals)
Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
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:
Pool
Compiler Version
v0.6.11+commit.5ef660b1
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2022-03-07 */ // SPDX-License-Identifier: AGPL-3.0-or-later // hevm: flattened sources of contracts/Pool.sol pragma solidity =0.6.11 >=0.6.0 <0.8.0 >=0.6.2 <0.8.0; ////// contracts/interfaces/IBPool.sol /* pragma solidity 0.6.11; */ interface IBPool { function transfer(address, uint256) external returns (bool); function INIT_POOL_SUPPLY() external view returns (uint256); function MAX_OUT_RATIO() external view returns (uint256); function bind(address, uint256, uint256) external; function balanceOf(address) external view returns (uint256); function finalize() external; function gulp(address) external; function isFinalized() external view returns (bool); function isBound(address) external view returns (bool); function getNumTokens() external view returns (uint256); function getBalance(address) external view returns (uint256); function getNormalizedWeight(address) external view returns (uint256); function getDenormalizedWeight(address) external view returns (uint256); function getTotalDenormalizedWeight() external view returns (uint256); function getSwapFee() external view returns (uint256); function totalSupply() external view returns (uint256); function getFinalTokens() external view returns (address[] memory); function joinPool(uint poolAmountOut, uint[] calldata maxAmountsIn) external; function calcSingleOutGivenPoolIn( uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 poolSupply, uint256 totalWeight, uint256 poolAmountIn, uint256 swapFee ) external pure returns (uint256); function calcPoolInGivenSingleOut( uint256 tokenBalanceOut, uint256 tokenWeightOut, uint256 poolSupply, uint256 totalWeight, uint256 tokenAmountOut, uint256 swapFee ) external pure returns (uint256); function exitswapExternAmountOut( address tokenOut, uint256 tokenAmountOut, uint256 maxPoolAmountIn ) external returns (uint256 poolAmountIn); } ////// contracts/interfaces/IDebtLocker.sol /* pragma solidity 0.6.11; */ interface IDebtLocker { function loan() external view returns (address); function liquidityAsset() external view returns (address); function pool() external view returns (address); function lastPrincipalPaid() external view returns (uint256); function lastInterestPaid() external view returns (uint256); function lastFeePaid() external view returns (uint256); function lastExcessReturned() external view returns (uint256); function lastDefaultSuffered() external view returns (uint256); function lastAmountRecovered() external view returns (uint256); function claim() external returns (uint256[7] memory); function triggerDefault() external; } ////// contracts/interfaces/ILiquidityLocker.sol /* pragma solidity 0.6.11; */ interface ILiquidityLocker { function pool() external view returns (address); function liquidityAsset() external view returns (address); function transfer(address, uint256) external; function fundLoan(address, address, uint256) external; } ////// contracts/interfaces/ILiquidityLockerFactory.sol /* pragma solidity 0.6.11; */ interface ILiquidityLockerFactory { function owner(address) external view returns (address); function isLocker(address) external view returns (bool); function factoryType() external view returns (uint8); function newLocker(address) external returns (address); } ////// contracts/token/interfaces/IBaseFDT.sol /* pragma solidity 0.6.11; */ interface IBaseFDT { /** @dev Returns the total amount of funds a given address is able to withdraw currently. @param owner Address of FDT holder. @return A uint256 representing the available funds for a given account. */ function withdrawableFundsOf(address owner) external view returns (uint256); /** @dev Withdraws all available funds for a FDT holder. */ function withdrawFunds() external; /** @dev This event emits when new funds are distributed. @param by The address of the sender that distributed funds. @param fundsDistributed The amount of funds received for distribution. */ event FundsDistributed(address indexed by, uint256 fundsDistributed); /** @dev This event emits when distributed funds are withdrawn by a token holder. @param by The address of the receiver of funds. @param fundsWithdrawn The amount of funds that were withdrawn. @param totalWithdrawn The total amount of funds that were withdrawn. */ event FundsWithdrawn(address indexed by, uint256 fundsWithdrawn, uint256 totalWithdrawn); } ////// lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol /* pragma solidity >=0.6.0 <0.8.0; */ /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } ////// contracts/token/interfaces/IBasicFDT.sol /* pragma solidity 0.6.11; */ /* import "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; */ /* import "./IBaseFDT.sol"; */ interface IBasicFDT is IBaseFDT, IERC20 { event PointsPerShareUpdated(uint256); event PointsCorrectionUpdated(address indexed, int256); function withdrawnFundsOf(address) external view returns (uint256); function accumulativeFundsOf(address) external view returns (uint256); function updateFundsReceived() external; } ////// contracts/token/interfaces/ILoanFDT.sol /* pragma solidity 0.6.11; */ /* import "./IBasicFDT.sol"; */ interface ILoanFDT is IBasicFDT { function fundsToken() external view returns (address); function fundsTokenBalance() external view returns (uint256); } ////// contracts/interfaces/ILoan.sol /* pragma solidity 0.6.11; */ /* import "../token/interfaces/ILoanFDT.sol"; */ interface ILoan is ILoanFDT { // State Variables function liquidityAsset() external view returns (address); function collateralAsset() external view returns (address); function fundingLocker() external view returns (address); function flFactory() external view returns (address); function collateralLocker() external view returns (address); function clFactory() external view returns (address); function borrower() external view returns (address); function repaymentCalc() external view returns (address); function lateFeeCalc() external view returns (address); function premiumCalc() external view returns (address); function loanState() external view returns (uint256); function collateralRequiredForDrawdown(uint256) external view returns (uint256); // Loan Specifications function apr() external view returns (uint256); function paymentsRemaining() external view returns (uint256); function paymentIntervalSeconds() external view returns (uint256); function requestAmount() external view returns (uint256); function collateralRatio() external view returns (uint256); function fundingPeriod() external view returns (uint256); function defaultGracePeriod() external view returns (uint256); function createdAt() external view returns (uint256); function principalOwed() external view returns (uint256); function principalPaid() external view returns (uint256); function interestPaid() external view returns (uint256); function feePaid() external view returns (uint256); function excessReturned() external view returns (uint256); function getNextPayment() external view returns (uint256, uint256, uint256, uint256); function superFactory() external view returns (address); function termDays() external view returns (uint256); function nextPaymentDue() external view returns (uint256); function getFullPayment() external view returns (uint256, uint256, uint256); // Liquidations function amountLiquidated() external view returns (uint256); function defaultSuffered() external view returns (uint256); function amountRecovered() external view returns (uint256); function getExpectedAmountRecovered() external view returns (uint256); function liquidationExcess() external view returns (uint256); // Functions function fundLoan(address, uint256) external; function makePayment() external; function drawdown(uint256) external; function makeFullPayment() external; function triggerDefault() external; function unwind() external; // Security function pause() external; function unpause() external; function loanAdmins(address) external view returns (address); function setLoanAdmin(address, bool) external; // Misc function reclaimERC20(address) external; } ////// contracts/interfaces/ILoanFactory.sol /* pragma solidity 0.6.11; */ interface ILoanFactory { function CL_FACTORY() external view returns (uint8); function FL_FACTORY() external view returns (uint8); function INTEREST_CALC_TYPE() external view returns (uint8); function LATEFEE_CALC_TYPE() external view returns (uint8); function PREMIUM_CALC_TYPE() external view returns (uint8); function globals() external view returns (address); function loansCreated() external view returns (uint256); function loans(uint256) external view returns (address); function isLoan(address) external view returns (bool); function loanFactoryAdmins(address) external view returns (bool); function setGlobals(address) external; function createLoan(address, address, address, address, uint256[5] memory, address[3] memory) external returns (address); function setLoanFactoryAdmin(address, bool) external; function pause() external; function unpause() external; } ////// contracts/interfaces/IMapleGlobals.sol /* pragma solidity 0.6.11; */ interface IMapleGlobals { function pendingGovernor() external view returns (address); function governor() external view returns (address); function globalAdmin() external view returns (address); function mpl() external view returns (address); function mapleTreasury() external view returns (address); function isValidBalancerPool(address) external view returns (bool); function treasuryFee() external view returns (uint256); function investorFee() external view returns (uint256); function defaultGracePeriod() external view returns (uint256); function fundingPeriod() external view returns (uint256); function swapOutRequired() external view returns (uint256); function isValidLiquidityAsset(address) external view returns (bool); function isValidCollateralAsset(address) external view returns (bool); function isValidPoolDelegate(address) external view returns (bool); function validCalcs(address) external view returns (bool); function isValidCalc(address, uint8) external view returns (bool); function getLpCooldownParams() external view returns (uint256, uint256); function isValidLoanFactory(address) external view returns (bool); function isValidSubFactory(address, address, uint8) external view returns (bool); function isValidPoolFactory(address) external view returns (bool); function getLatestPrice(address) external view returns (uint256); function defaultUniswapPath(address, address) external view returns (address); function minLoanEquity() external view returns (uint256); function maxSwapSlippage() external view returns (uint256); function protocolPaused() external view returns (bool); function stakerCooldownPeriod() external view returns (uint256); function lpCooldownPeriod() external view returns (uint256); function stakerUnstakeWindow() external view returns (uint256); function lpWithdrawWindow() external view returns (uint256); function oracleFor(address) external view returns (address); function validSubFactories(address, address) external view returns (bool); function setStakerCooldownPeriod(uint256) external; function setLpCooldownPeriod(uint256) external; function setStakerUnstakeWindow(uint256) external; function setLpWithdrawWindow(uint256) external; function setMaxSwapSlippage(uint256) external; function setGlobalAdmin(address) external; function setValidBalancerPool(address, bool) external; function setProtocolPause(bool) external; function setValidPoolFactory(address, bool) external; function setValidLoanFactory(address, bool) external; function setValidSubFactory(address, address, bool) external; function setDefaultUniswapPath(address, address, address) external; function setPoolDelegateAllowlist(address, bool) external; function setCollateralAsset(address, bool) external; function setLiquidityAsset(address, bool) external; function setCalc(address, bool) external; function setInvestorFee(uint256) external; function setTreasuryFee(uint256) external; function setMapleTreasury(address) external; function setDefaultGracePeriod(uint256) external; function setMinLoanEquity(uint256) external; function setFundingPeriod(uint256) external; function setSwapOutRequired(uint256) external; function setPriceOracle(address, address) external; function setPendingGovernor(address) external; function acceptGovernor() external; } ////// contracts/interfaces/IPoolFactory.sol /* pragma solidity 0.6.11; */ interface IPoolFactory { function LL_FACTORY() external view returns (uint8); function SL_FACTORY() external view returns (uint8); function poolsCreated() external view returns (uint256); function globals() external view returns (address); function pools(uint256) external view returns (address); function isPool(address) external view returns (bool); function poolFactoryAdmins(address) external view returns (bool); function setGlobals(address) external; function createPool(address, address, address, address, uint256, uint256, uint256) external returns (address); function setPoolFactoryAdmin(address, bool) external; function pause() external; function unpause() external; } ////// contracts/token/interfaces/IExtendedFDT.sol /* pragma solidity 0.6.11; */ /* import "./IBasicFDT.sol"; */ interface IExtendedFDT is IBasicFDT { event LossesPerShareUpdated(uint256); event LossesCorrectionUpdated(address indexed, int256); event LossesDistributed(address indexed, uint256); event LossesRecognized(address indexed, uint256, uint256); function lossesPerShare() external view returns (uint256); function recognizableLossesOf(address) external view returns (uint256); function recognizedLossesOf(address) external view returns (uint256); function accumulativeLossesOf(address) external view returns (uint256); function updateLossesReceived() external; } ////// contracts/token/interfaces/IStakeLockerFDT.sol /* pragma solidity 0.6.11; */ /* import "./IExtendedFDT.sol"; */ interface IStakeLockerFDT is IExtendedFDT { function fundsToken() external view returns (address); function fundsTokenBalance() external view returns (uint256); function bptLosses() external view returns (uint256); function lossesBalance() external view returns (uint256); } ////// contracts/interfaces/IStakeLocker.sol /* pragma solidity 0.6.11; */ /* import "../token/interfaces/IStakeLockerFDT.sol"; */ interface IStakeLocker is IStakeLockerFDT { function stakeDate(address) external returns (uint256); function stake(uint256) external; function unstake(uint256) external; function pull(address, uint256) external; function setAllowlist(address, bool) external; function openStakeLockerToPublic() external; function openToPublic() external view returns (bool); function allowed(address) external view returns (bool); function updateLosses(uint256) external; function intendToUnstake() external; function unstakeCooldown(address) external view returns (uint256); function lockupPeriod() external view returns (uint256); function stakeAsset() external view returns (address); function liquidityAsset() external view returns (address); function pool() external view returns (address); function setLockupPeriod(uint256) external; function cancelUnstake() external; function increaseCustodyAllowance(address, uint256) external; function transferByCustodian(address, address, uint256) external; function pause() external; function unpause() external; function isUnstakeAllowed(address) external view returns (bool); function isReceiveAllowed(uint256) external view returns (bool); } ////// contracts/interfaces/IStakeLockerFactory.sol /* pragma solidity 0.6.11; */ interface IStakeLockerFactory { function owner(address) external returns (address); function isLocker(address) external returns (bool); function factoryType() external returns (uint8); function newLocker(address, address) external returns (address); } ////// contracts/interfaces/IDebtLockerFactory.sol /* pragma solidity 0.6.11; */ interface IDebtLockerFactory { function owner(address) external view returns (address); function isLocker(address) external view returns (bool); function factoryType() external view returns (uint8); function newLocker(address) external returns (address); } ////// contracts/interfaces/IERC20Details.sol /* pragma solidity 0.6.11; */ /* import "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; */ interface IERC20Details is IERC20 { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint256); } ////// lib/openzeppelin-contracts/contracts/math/SafeMath.sol /* pragma solidity >=0.6.0 <0.8.0; */ /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } ////// lib/openzeppelin-contracts/contracts/utils/Address.sol /* pragma solidity >=0.6.2 <0.8.0; */ /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } ////// lib/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol /* pragma solidity >=0.6.0 <0.8.0; */ /* import "./IERC20.sol"; */ /* import "../../math/SafeMath.sol"; */ /* import "../../utils/Address.sol"; */ /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } ////// contracts/library/PoolLib.sol /* pragma solidity 0.6.11; */ /* import "lib/openzeppelin-contracts/contracts/math/SafeMath.sol"; */ /* import "lib/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol"; */ /* import "../interfaces/ILoan.sol"; */ /* import "../interfaces/IBPool.sol"; */ /* import "../interfaces/IMapleGlobals.sol"; */ /* import "../interfaces/ILiquidityLocker.sol"; */ /* import "../interfaces/IERC20Details.sol"; */ /* import "../interfaces/ILoanFactory.sol"; */ /* import "../interfaces/IStakeLocker.sol"; */ /* import "../interfaces/IDebtLockerFactory.sol"; */ /// @title PoolLib is a library of utility functions used by Pool. library PoolLib { using SafeMath for uint256; using SafeERC20 for IERC20; uint256 public constant MAX_UINT256 = uint256(-1); uint256 public constant WAD = 10 ** 18; uint8 public constant DL_FACTORY = 1; // Factory type of DebtLockerFactory event LoanFunded(address indexed loan, address debtLocker, uint256 amountFunded); event DepositDateUpdated(address indexed liquidityProvider, uint256 depositDate); /***************************************/ /*** Pool Delegate Utility Functions ***/ /***************************************/ /** @dev Conducts sanity checks for Pools in the constructor. @param globals Instance of a MapleGlobals. @param liquidityAsset Asset used by Pool for liquidity to fund loans. @param stakeAsset Asset escrowed in StakeLocker. @param stakingFee Fee that the Stakers earn on interest, in basis points. @param delegateFee Fee that the Pool Delegate earns on interest, in basis points. */ function poolSanityChecks( IMapleGlobals globals, address liquidityAsset, address stakeAsset, uint256 stakingFee, uint256 delegateFee ) external view { IBPool bPool = IBPool(stakeAsset); require(globals.isValidLiquidityAsset(liquidityAsset), "P:INVALID_LIQ_ASSET"); require(stakingFee.add(delegateFee) <= 10_000, "P:INVALID_FEES"); require( globals.isValidBalancerPool(address(stakeAsset)) && bPool.isBound(globals.mpl()) && bPool.isBound(liquidityAsset) && bPool.isFinalized(), "P:INVALID_BALANCER_POOL" ); } /** @dev Funds a Loan for an amount, utilizing the supplied DebtLockerFactory for DebtLockers. @dev It emits a `LoanFunded` event. @param debtLockers Mapping contains the DebtLocker contract address corresponding to the DebtLockerFactory and Loan. @param superFactory Address of the PoolFactory. @param liquidityLocker Address of the LiquidityLocker contract attached with this Pool. @param loan Address of the Loan to fund. @param dlFactory The DebtLockerFactory to utilize. @param amt Amount to fund the Loan. */ function fundLoan( mapping(address => mapping(address => address)) storage debtLockers, address superFactory, address liquidityLocker, address loan, address dlFactory, uint256 amt ) external { IMapleGlobals globals = IMapleGlobals(ILoanFactory(superFactory).globals()); address loanFactory = ILoan(loan).superFactory(); // Auth checks. require(globals.isValidLoanFactory(loanFactory), "P:INVALID_LF"); require(ILoanFactory(loanFactory).isLoan(loan), "P:INVALID_L"); require(globals.isValidSubFactory(superFactory, dlFactory, DL_FACTORY), "P:INVALID_DLF"); address debtLocker = debtLockers[loan][dlFactory]; // Instantiate DebtLocker if it doesn't exist withing this factory if (debtLocker == address(0)) { debtLocker = IDebtLockerFactory(dlFactory).newLocker(loan); debtLockers[loan][dlFactory] = debtLocker; } // Fund the Loan. ILiquidityLocker(liquidityLocker).fundLoan(loan, debtLocker, amt); emit LoanFunded(loan, debtLocker, amt); } /** @dev Helper function used by Pool `claim` function, for when if a default has occurred. @param liquidityAsset IERC20 of Liquidity Asset. @param stakeLocker Address of StakeLocker. @param stakeAsset Address of BPTs. @param defaultSuffered Amount of shortfall in defaulted Loan after liquidation. @return bptsBurned Amount of BPTs burned to cover shortfall. @return postBurnBptBal Amount of BPTs returned to StakeLocker after burn. @return liquidityAssetRecoveredFromBurn Amount of Liquidity Asset recovered from burn. */ function handleDefault( IERC20 liquidityAsset, address stakeLocker, address stakeAsset, uint256 defaultSuffered ) external returns ( uint256 bptsBurned, uint256 postBurnBptBal, uint256 liquidityAssetRecoveredFromBurn ) { IBPool bPool = IBPool(stakeAsset); // stakeAsset = Balancer Pool Tokens // Check amount of Liquidity Asset coverage that exists in the StakeLocker. uint256 availableSwapOut = getSwapOutValueLocker(stakeAsset, address(liquidityAsset), stakeLocker); // Pull BPTs from StakeLocker. IStakeLocker(stakeLocker).pull(address(this), bPool.balanceOf(stakeLocker)); // To maintain accounting, account for direct transfers into Pool. uint256 preBurnLiquidityAssetBal = liquidityAsset.balanceOf(address(this)); uint256 preBurnBptBal = bPool.balanceOf(address(this)); // Burn enough BPTs for Liquidity Asset to cover default suffered. bPool.exitswapExternAmountOut( address(liquidityAsset), availableSwapOut >= defaultSuffered ? defaultSuffered : availableSwapOut, // Burn BPTs up to defaultSuffered amount preBurnBptBal ); // Return remaining BPTs to StakeLocker. postBurnBptBal = bPool.balanceOf(address(this)); bptsBurned = preBurnBptBal.sub(postBurnBptBal); bPool.transfer(stakeLocker, postBurnBptBal); liquidityAssetRecoveredFromBurn = liquidityAsset.balanceOf(address(this)).sub(preBurnLiquidityAssetBal); IStakeLocker(stakeLocker).updateLosses(bptsBurned); // Update StakeLockerFDT loss accounting for BPTs } /** @dev Calculates portions of claim from DebtLocker to be used by Pool `claim` function. @param claimInfo [0] = Total Claimed [1] = Interest Claimed [2] = Principal Claimed [3] = Fee Claimed [4] = Excess Returned Claimed [5] = Amount Recovered (from Liquidation) [6] = Default Suffered @param delegateFee Portion of interest (basis points) that goes to the Pool Delegate. @param stakingFee Portion of interest (basis points) that goes to the StakeLocker. @return poolDelegatePortion Total funds to send to the Pool Delegate. @return stakeLockerPortion Total funds to send to the StakeLocker. @return principalClaim Total principal claim. @return interestClaim Total interest claim. */ function calculateClaimAndPortions( uint256[7] calldata claimInfo, uint256 delegateFee, uint256 stakingFee ) external pure returns ( uint256 poolDelegatePortion, uint256 stakeLockerPortion, uint256 principalClaim, uint256 interestClaim ) { poolDelegatePortion = claimInfo[1].mul(delegateFee).div(10_000).add(claimInfo[3]); // Pool Delegate portion of interest plus fee. stakeLockerPortion = claimInfo[1].mul(stakingFee).div(10_000); // StakeLocker portion of interest. principalClaim = claimInfo[2].add(claimInfo[4]).add(claimInfo[5]); // principal + excess + amountRecovered interestClaim = claimInfo[1].sub(claimInfo[1].mul(delegateFee).div(10_000)).sub(stakeLockerPortion); // leftover interest } /** @dev Checks that the deactivation is allowed. @param globals Instance of a MapleGlobals. @param principalOut Amount of funds that are already funded to Loans. @param liquidityAsset Liquidity Asset of the Pool. */ function validateDeactivation(IMapleGlobals globals, uint256 principalOut, address liquidityAsset) external view { require(principalOut <= _convertFromUsd(globals, liquidityAsset, 100), "P:PRINCIPAL_OUTSTANDING"); } /********************************************/ /*** Liquidity Provider Utility Functions ***/ /********************************************/ /** @dev Updates the effective deposit date based on how much new capital has been added. If more capital is added, the deposit date moves closer to the current timestamp. @dev It emits a `DepositDateUpdated` event. @param amt Total deposit amount. @param account Address of account depositing. */ function updateDepositDate(mapping(address => uint256) storage depositDate, uint256 balance, uint256 amt, address account) internal { uint256 prevDate = depositDate[account]; // prevDate + (now - prevDate) * (amt / (balance + amt)) // NOTE: prevDate = 0 implies balance = 0, and equation reduces to now uint256 newDate = (balance + amt) > 0 ? prevDate.add(block.timestamp.sub(prevDate).mul(amt).div(balance + amt)) : prevDate; depositDate[account] = newDate; emit DepositDateUpdated(account, newDate); } /** @dev Performs all necessary checks for a `transferByCustodian` call. @dev From and to must always be equal. */ function transferByCustodianChecks(address from, address to, uint256 amount) external pure { require(to == from, "P:INVALID_RECEIVER"); require(amount != uint256(0), "P:INVALID_AMT"); } /** @dev Performs all necessary checks for an `increaseCustodyAllowance` call. */ function increaseCustodyAllowanceChecks(address custodian, uint256 amount, uint256 newTotalAllowance, uint256 fdtBal) external pure { require(custodian != address(0), "P:INVALID_CUSTODIAN"); require(amount != uint256(0), "P:INVALID_AMT"); require(newTotalAllowance <= fdtBal, "P:INSUF_BALANCE"); } /**********************************/ /*** Governor Utility Functions ***/ /**********************************/ /** @dev Transfers any locked funds to the Governor. Only the Governor can call this function. @param token Address of the token to be reclaimed. @param liquidityAsset Address of Liquidity Asset that is supported by the Pool. @param globals Instance of a MapleGlobals. */ function reclaimERC20(address token, address liquidityAsset, IMapleGlobals globals) external { require(msg.sender == globals.governor(), "P:NOT_GOV"); require(token != liquidityAsset && token != address(0), "P:INVALID_TOKEN"); IERC20(token).safeTransfer(msg.sender, IERC20(token).balanceOf(address(this))); } /************************/ /*** Getter Functions ***/ /************************/ /** @dev Official Balancer pool bdiv() function. Does synthetic float with 10^-18 precision. */ function _bdiv(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0, "P:DIV_ZERO"); uint256 c0 = a * WAD; require(a == 0 || c0 / a == WAD, "P:DIV_INTERNAL"); // bmul overflow uint256 c1 = c0 + (b / 2); require(c1 >= c0, "P:DIV_INTERNAL"); // badd require return c1 / b; } /** @dev Calculates the value of BPT in units of Liquidity Asset. @dev Vulnerable to flash-loan attacks where the attacker can artificially inflate the BPT price by swapping a large amount of Liquidity Asset into the Pool and swapping back after this function is called. @param _bPool Address of Balancer pool. @param liquidityAsset Asset used by Pool for liquidity to fund Loans. @param staker Address that deposited BPTs to StakeLocker. @param stakeLocker Escrows BPTs deposited by Staker. @return USDC value of Staker BPTs. */ function BPTVal( address _bPool, address liquidityAsset, address staker, address stakeLocker ) external view returns (uint256) { IBPool bPool = IBPool(_bPool); // StakeLockerFDTs are minted 1:1 (in wei) in the StakeLocker when staking BPTs, thus representing stake amount. // These are burned when withdrawing staked BPTs, thus representing the current stake amount. uint256 amountStakedBPT = IERC20(stakeLocker).balanceOf(staker); uint256 totalSupplyBPT = IERC20(_bPool).totalSupply(); uint256 liquidityAssetBalance = bPool.getBalance(liquidityAsset); uint256 liquidityAssetWeight = bPool.getNormalizedWeight(liquidityAsset); // liquidityAsset value = (amountStaked/totalSupply) * (liquidityAssetBalance/liquidityAssetWeight) return _bdiv(amountStakedBPT, totalSupplyBPT).mul(_bdiv(liquidityAssetBalance, liquidityAssetWeight)).div(WAD); } /** @dev Calculates Liquidity Asset swap out value of staker BPT balance escrowed in StakeLocker. @param _bPool Balancer pool that issues the BPTs. @param liquidityAsset Swap out asset (e.g. USDC) to receive when burning BPTs. @param staker Address that deposited BPTs to StakeLocker. @param stakeLocker Escrows BPTs deposited by Staker. @return liquidityAsset Swap out value of staker BPTs. */ function getSwapOutValue( address _bPool, address liquidityAsset, address staker, address stakeLocker ) public view returns (uint256) { return _getSwapOutValue(_bPool, liquidityAsset, IERC20(stakeLocker).balanceOf(staker)); } /** @dev Calculates Liquidity Asset swap out value of entire BPT balance escrowed in StakeLocker. @param _bPool Balancer pool that issues the BPTs. @param liquidityAsset Swap out asset (e.g. USDC) to receive when burning BPTs. @param stakeLocker Escrows BPTs deposited by Staker. @return liquidityAsset Swap out value of StakeLocker BPTs. */ function getSwapOutValueLocker( address _bPool, address liquidityAsset, address stakeLocker ) public view returns (uint256) { return _getSwapOutValue(_bPool, liquidityAsset, IBPool(_bPool).balanceOf(stakeLocker)); } function _getSwapOutValue( address _bPool, address liquidityAsset, uint256 poolAmountIn ) internal view returns (uint256) { // Fetch Balancer pool token information IBPool bPool = IBPool(_bPool); uint256 tokenBalanceOut = bPool.getBalance(liquidityAsset); uint256 tokenWeightOut = bPool.getDenormalizedWeight(liquidityAsset); uint256 poolSupply = bPool.totalSupply(); uint256 totalWeight = bPool.getTotalDenormalizedWeight(); uint256 swapFee = bPool.getSwapFee(); // Returns the amount of liquidityAsset that can be recovered from BPT burning uint256 tokenAmountOut = bPool.calcSingleOutGivenPoolIn( tokenBalanceOut, tokenWeightOut, poolSupply, totalWeight, poolAmountIn, swapFee ); // Max amount that can be swapped based on amount of liquidityAsset in the Balancer Pool uint256 maxSwapOut = tokenBalanceOut.mul(bPool.MAX_OUT_RATIO()).div(WAD); return tokenAmountOut <= maxSwapOut ? tokenAmountOut : maxSwapOut; } /** @dev Calculates BPTs required if burning BPTs for liquidityAsset, given supplied tokenAmountOutRequired. @dev Vulnerable to flash-loan attacks where the attacker can artificially inflate the BPT price by swapping a large amount of liquidityAsset into the pool and swapping back after this function is called. @param _bPool Balancer pool that issues the BPTs. @param liquidityAsset Swap out asset (e.g. USDC) to receive when burning BPTs. @param staker Address that deposited BPTs to stakeLocker. @param stakeLocker Escrows BPTs deposited by staker. @param liquidityAssetAmountRequired Amount of liquidityAsset required to recover. @return poolAmountInRequired poolAmountIn required. @return stakerBalance poolAmountIn currently staked. */ function getPoolSharesRequired( address _bPool, address liquidityAsset, address staker, address stakeLocker, uint256 liquidityAssetAmountRequired ) public view returns (uint256 poolAmountInRequired, uint256 stakerBalance) { // Fetch Balancer pool token information. IBPool bPool = IBPool(_bPool); uint256 tokenBalanceOut = bPool.getBalance(liquidityAsset); uint256 tokenWeightOut = bPool.getDenormalizedWeight(liquidityAsset); uint256 poolSupply = bPool.totalSupply(); uint256 totalWeight = bPool.getTotalDenormalizedWeight(); uint256 swapFee = bPool.getSwapFee(); // Fetch amount of BPTs required to burn to receive Liquidity Asset amount required. poolAmountInRequired = bPool.calcPoolInGivenSingleOut( tokenBalanceOut, tokenWeightOut, poolSupply, totalWeight, liquidityAssetAmountRequired, swapFee ); // Fetch amount staked in StakeLocker by Staker. stakerBalance = IERC20(stakeLocker).balanceOf(staker); } /** @dev Returns information on the stake requirements. @param globals Instance of a MapleGlobals. @param balancerPool Address of Balancer pool. @param liquidityAsset Address of Liquidity Asset, to be returned from swap out. @param poolDelegate Address of Pool Delegate. @param stakeLocker Address of StakeLocker. @return swapOutAmountRequired Min amount of Liquidity Asset coverage from staking required (in Liquidity Asset units). @return currentPoolDelegateCover Present amount of Liquidity Asset coverage from Pool Delegate stake (in Liquidity Asset units). @return enoughStakeForFinalization If enough stake is present from Pool Delegate for Pool finalization. @return poolAmountInRequired BPTs required for minimum Liquidity Asset coverage. @return poolAmountPresent Current staked BPTs. */ function getInitialStakeRequirements(IMapleGlobals globals, address balancerPool, address liquidityAsset, address poolDelegate, address stakeLocker) external view returns ( uint256 swapOutAmountRequired, uint256 currentPoolDelegateCover, bool enoughStakeForFinalization, uint256 poolAmountInRequired, uint256 poolAmountPresent ) { swapOutAmountRequired = _convertFromUsd(globals, liquidityAsset, globals.swapOutRequired()); ( poolAmountInRequired, poolAmountPresent ) = getPoolSharesRequired(balancerPool, liquidityAsset, poolDelegate, stakeLocker, swapOutAmountRequired); currentPoolDelegateCover = getSwapOutValue(balancerPool, liquidityAsset, poolDelegate, stakeLocker); enoughStakeForFinalization = poolAmountPresent >= poolAmountInRequired; } /************************/ /*** Helper Functions ***/ /************************/ /** @dev Converts from WAD precision to Liquidity Asset precision. @param amt Amount to convert. @param liquidityAssetDecimals Liquidity Asset decimal. */ function fromWad(uint256 amt, uint256 liquidityAssetDecimals) external pure returns (uint256) { return amt.mul(10 ** liquidityAssetDecimals).div(WAD); } /** @dev Returns Liquidity Asset in Liquidity Asset units when given integer USD (E.g., $100 = 100). @param globals Instance of a MapleGlobals. @param liquidityAsset Liquidity Asset of the pool. @param usdAmount USD amount to convert, in integer units (e.g., $100 = 100). @return usdAmount worth of Liquidity Asset, in Liquidity Asset units. */ function _convertFromUsd(IMapleGlobals globals, address liquidityAsset, uint256 usdAmount) internal view returns (uint256) { return usdAmount .mul(10 ** 8) // Cancel out 10 ** 8 decimals from oracle. .mul(10 ** IERC20Details(liquidityAsset).decimals()) // Convert to Liquidity Asset precision. .div(globals.getLatestPrice(liquidityAsset)); // Convert to Liquidity Asset value. } } ////// contracts/math/SafeMathInt.sol /* pragma solidity 0.6.11; */ library SafeMathInt { function toUint256Safe(int256 a) internal pure returns (uint256) { require(a >= 0, "SMI:NEG"); return uint256(a); } } ////// contracts/math/SafeMathUint.sol /* pragma solidity 0.6.11; */ library SafeMathUint { function toInt256Safe(uint256 a) internal pure returns (int256 b) { b = int256(a); require(b >= 0, "SMU:OOB"); } } ////// lib/openzeppelin-contracts/contracts/math/SignedSafeMath.sol /* pragma solidity >=0.6.0 <0.8.0; */ /** * @title SignedSafeMath * @dev Signed math operations with safety checks that revert on error. */ library SignedSafeMath { int256 constant private _INT256_MIN = -2**255; /** * @dev Returns the multiplication of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow"); int256 c = a * b; require(c / a == b, "SignedSafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two signed integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "SignedSafeMath: division by zero"); require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow"); int256 c = a / b; return c; } /** * @dev Returns the subtraction of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); return c; } /** * @dev Returns the addition of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); return c; } } ////// lib/openzeppelin-contracts/contracts/GSN/Context.sol /* pragma solidity >=0.6.0 <0.8.0; */ /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } ////// lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol /* pragma solidity >=0.6.0 <0.8.0; */ /* import "../../GSN/Context.sol"; */ /* import "./IERC20.sol"; */ /* import "../../math/SafeMath.sol"; */ /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } } ////// contracts/token/BasicFDT.sol /* pragma solidity 0.6.11; */ /* import "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; */ /* import "lib/openzeppelin-contracts/contracts/math/SafeMath.sol"; */ /* import "lib/openzeppelin-contracts/contracts/math/SignedSafeMath.sol"; */ /* import "./interfaces/IBaseFDT.sol"; */ /* import "../math/SafeMathUint.sol"; */ /* import "../math/SafeMathInt.sol"; */ /// @title BasicFDT implements base level FDT functionality for accounting for revenues. abstract contract BasicFDT is IBaseFDT, ERC20 { using SafeMath for uint256; using SafeMathUint for uint256; using SignedSafeMath for int256; using SafeMathInt for int256; uint256 internal constant pointsMultiplier = 2 ** 128; uint256 internal pointsPerShare; mapping(address => int256) internal pointsCorrection; mapping(address => uint256) internal withdrawnFunds; event PointsPerShareUpdated(uint256 pointsPerShare); event PointsCorrectionUpdated(address indexed account, int256 pointsCorrection); constructor(string memory name, string memory symbol) ERC20(name, symbol) public { } /** @dev Distributes funds to token holders. @dev It reverts if the total supply of tokens is 0. @dev It emits a `FundsDistributed` event if the amount of received funds is greater than 0. @dev It emits a `PointsPerShareUpdated` event if the amount of received funds is greater than 0. About undistributed funds: In each distribution, there is a small amount of funds which do not get distributed, which is `(value pointsMultiplier) % totalSupply()`. With a well-chosen `pointsMultiplier`, the amount funds that are not getting distributed in a distribution can be less than 1 (base unit). We can actually keep track of the undistributed funds in a distribution and try to distribute it in the next distribution. */ function _distributeFunds(uint256 value) internal { require(totalSupply() > 0, "FDT:ZERO_SUPPLY"); if (value == 0) return; pointsPerShare = pointsPerShare.add(value.mul(pointsMultiplier) / totalSupply()); emit FundsDistributed(msg.sender, value); emit PointsPerShareUpdated(pointsPerShare); } /** @dev Prepares the withdrawal of funds. @dev It emits a `FundsWithdrawn` event if the amount of withdrawn funds is greater than 0. @return withdrawableDividend The amount of dividend funds that can be withdrawn. */ function _prepareWithdraw() internal returns (uint256 withdrawableDividend) { withdrawableDividend = withdrawableFundsOf(msg.sender); uint256 _withdrawnFunds = withdrawnFunds[msg.sender].add(withdrawableDividend); withdrawnFunds[msg.sender] = _withdrawnFunds; emit FundsWithdrawn(msg.sender, withdrawableDividend, _withdrawnFunds); } /** @dev Returns the amount of funds that an account can withdraw. @param _owner The address of a token holder. @return The amount funds that `_owner` can withdraw. */ function withdrawableFundsOf(address _owner) public view override returns (uint256) { return accumulativeFundsOf(_owner).sub(withdrawnFunds[_owner]); } /** @dev Returns the amount of funds that an account has withdrawn. @param _owner The address of a token holder. @return The amount of funds that `_owner` has withdrawn. */ function withdrawnFundsOf(address _owner) external view returns (uint256) { return withdrawnFunds[_owner]; } /** @dev Returns the amount of funds that an account has earned in total. @dev accumulativeFundsOf(_owner) = withdrawableFundsOf(_owner) + withdrawnFundsOf(_owner) = (pointsPerShare * balanceOf(_owner) + pointsCorrection[_owner]) / pointsMultiplier @param _owner The address of a token holder. @return The amount of funds that `_owner` has earned in total. */ function accumulativeFundsOf(address _owner) public view returns (uint256) { return pointsPerShare .mul(balanceOf(_owner)) .toInt256Safe() .add(pointsCorrection[_owner]) .toUint256Safe() / pointsMultiplier; } /** @dev Transfers tokens from one account to another. Updates pointsCorrection to keep funds unchanged. @dev It emits two `PointsCorrectionUpdated` events, one for the sender and one for the receiver. @param from The address to transfer from. @param to The address to transfer to. @param value The amount to be transferred. */ function _transfer( address from, address to, uint256 value ) internal virtual override { super._transfer(from, to, value); int256 _magCorrection = pointsPerShare.mul(value).toInt256Safe(); int256 pointsCorrectionFrom = pointsCorrection[from].add(_magCorrection); pointsCorrection[from] = pointsCorrectionFrom; int256 pointsCorrectionTo = pointsCorrection[to].sub(_magCorrection); pointsCorrection[to] = pointsCorrectionTo; emit PointsCorrectionUpdated(from, pointsCorrectionFrom); emit PointsCorrectionUpdated(to, pointsCorrectionTo); } /** @dev Mints tokens to an account. Updates pointsCorrection to keep funds unchanged. @param account The account that will receive the created tokens. @param value The amount that will be created. */ function _mint(address account, uint256 value) internal virtual override { super._mint(account, value); int256 _pointsCorrection = pointsCorrection[account].sub( (pointsPerShare.mul(value)).toInt256Safe() ); pointsCorrection[account] = _pointsCorrection; emit PointsCorrectionUpdated(account, _pointsCorrection); } /** @dev Burns an amount of the token of a given account. Updates pointsCorrection to keep funds unchanged. @dev It emits a `PointsCorrectionUpdated` event. @param account The account whose tokens will be burnt. @param value The amount that will be burnt. */ function _burn(address account, uint256 value) internal virtual override { super._burn(account, value); int256 _pointsCorrection = pointsCorrection[account].add( (pointsPerShare.mul(value)).toInt256Safe() ); pointsCorrection[account] = _pointsCorrection; emit PointsCorrectionUpdated(account, _pointsCorrection); } /** @dev Withdraws all available funds for a token holder. */ function withdrawFunds() public virtual override {} /** @dev Updates the current `fundsToken` balance and returns the difference of the new and previous `fundsToken` balance. @return A int256 representing the difference of the new and previous `fundsToken` balance. */ function _updateFundsTokenBalance() internal virtual returns (int256) {} /** @dev Registers a payment of funds in tokens. May be called directly after a deposit is made. @dev Calls _updateFundsTokenBalance(), whereby the contract computes the delta of the new and previous `fundsToken` balance and increments the total received funds (cumulative), by delta, by calling _distributeFunds(). */ function updateFundsReceived() public virtual { int256 newFunds = _updateFundsTokenBalance(); if (newFunds <= 0) return; _distributeFunds(newFunds.toUint256Safe()); } } ////// contracts/token/ExtendedFDT.sol /* pragma solidity 0.6.11; */ /* import "./BasicFDT.sol"; */ /// @title ExtendedFDT implements FDT functionality for accounting for losses. abstract contract ExtendedFDT is BasicFDT { using SafeMath for uint256; using SafeMathUint for uint256; using SignedSafeMath for int256; using SafeMathInt for int256; uint256 internal lossesPerShare; mapping(address => int256) internal lossesCorrection; mapping(address => uint256) internal recognizedLosses; event LossesPerShareUpdated(uint256 lossesPerShare); event LossesCorrectionUpdated(address indexed account, int256 lossesCorrection); /** @dev This event emits when new losses are distributed. @param by The address of the account that has distributed losses. @param lossesDistributed The amount of losses received for distribution. */ event LossesDistributed(address indexed by, uint256 lossesDistributed); /** @dev This event emits when distributed losses are recognized by a token holder. @param by The address of the receiver of losses. @param lossesRecognized The amount of losses that were recognized. @param totalLossesRecognized The total amount of losses that are recognized. */ event LossesRecognized(address indexed by, uint256 lossesRecognized, uint256 totalLossesRecognized); constructor(string memory name, string memory symbol) BasicFDT(name, symbol) public { } /** @dev Distributes losses to token holders. @dev It reverts if the total supply of tokens is 0. @dev It emits a `LossesDistributed` event if the amount of received losses is greater than 0. @dev It emits a `LossesPerShareUpdated` event if the amount of received losses is greater than 0. About undistributed losses: In each distribution, there is a small amount of losses which do not get distributed, which is `(value * pointsMultiplier) % totalSupply()`. With a well-chosen `pointsMultiplier`, the amount losses that are not getting distributed in a distribution can be less than 1 (base unit). We can actually keep track of the undistributed losses in a distribution and try to distribute it in the next distribution. */ function _distributeLosses(uint256 value) internal { require(totalSupply() > 0, "FDT:ZERO_SUPPLY"); if (value == 0) return; uint256 _lossesPerShare = lossesPerShare.add(value.mul(pointsMultiplier) / totalSupply()); lossesPerShare = _lossesPerShare; emit LossesDistributed(msg.sender, value); emit LossesPerShareUpdated(_lossesPerShare); } /** @dev Prepares losses for a withdrawal. @dev It emits a `LossesWithdrawn` event if the amount of withdrawn losses is greater than 0. @return recognizableDividend The amount of dividend losses that can be recognized. */ function _prepareLossesWithdraw() internal returns (uint256 recognizableDividend) { recognizableDividend = recognizableLossesOf(msg.sender); uint256 _recognizedLosses = recognizedLosses[msg.sender].add(recognizableDividend); recognizedLosses[msg.sender] = _recognizedLosses; emit LossesRecognized(msg.sender, recognizableDividend, _recognizedLosses); } /** @dev Returns the amount of losses that an address can withdraw. @param _owner The address of a token holder. @return The amount of losses that `_owner` can withdraw. */ function recognizableLossesOf(address _owner) public view returns (uint256) { return accumulativeLossesOf(_owner).sub(recognizedLosses[_owner]); } /** @dev Returns the amount of losses that an address has recognized. @param _owner The address of a token holder @return The amount of losses that `_owner` has recognized */ function recognizedLossesOf(address _owner) external view returns (uint256) { return recognizedLosses[_owner]; } /** @dev Returns the amount of losses that an address has earned in total. @dev accumulativeLossesOf(_owner) = recognizableLossesOf(_owner) + recognizedLossesOf(_owner) = (lossesPerShare * balanceOf(_owner) + lossesCorrection[_owner]) / pointsMultiplier @param _owner The address of a token holder @return The amount of losses that `_owner` has earned in total */ function accumulativeLossesOf(address _owner) public view returns (uint256) { return lossesPerShare .mul(balanceOf(_owner)) .toInt256Safe() .add(lossesCorrection[_owner]) .toUint256Safe() / pointsMultiplier; } /** @dev Transfers tokens from one account to another. Updates pointsCorrection to keep funds unchanged. @dev It emits two `LossesCorrectionUpdated` events, one for the sender and one for the receiver. @param from The address to transfer from. @param to The address to transfer to. @param value The amount to be transferred. */ function _transfer( address from, address to, uint256 value ) internal virtual override { super._transfer(from, to, value); int256 _lossesCorrection = lossesPerShare.mul(value).toInt256Safe(); int256 lossesCorrectionFrom = lossesCorrection[from].add(_lossesCorrection); lossesCorrection[from] = lossesCorrectionFrom; int256 lossesCorrectionTo = lossesCorrection[to].sub(_lossesCorrection); lossesCorrection[to] = lossesCorrectionTo; emit LossesCorrectionUpdated(from, lossesCorrectionFrom); emit LossesCorrectionUpdated(to, lossesCorrectionTo); } /** @dev Mints tokens to an account. Updates lossesCorrection to keep losses unchanged. @dev It emits a `LossesCorrectionUpdated` event. @param account The account that will receive the created tokens. @param value The amount that will be created. */ function _mint(address account, uint256 value) internal virtual override { super._mint(account, value); int256 _lossesCorrection = lossesCorrection[account].sub( (lossesPerShare.mul(value)).toInt256Safe() ); lossesCorrection[account] = _lossesCorrection; emit LossesCorrectionUpdated(account, _lossesCorrection); } /** @dev Burns an amount of the token of a given account. Updates lossesCorrection to keep losses unchanged. @dev It emits a `LossesCorrectionUpdated` event. @param account The account from which tokens will be burnt. @param value The amount that will be burnt. */ function _burn(address account, uint256 value) internal virtual override { super._burn(account, value); int256 _lossesCorrection = lossesCorrection[account].add( (lossesPerShare.mul(value)).toInt256Safe() ); lossesCorrection[account] = _lossesCorrection; emit LossesCorrectionUpdated(account, _lossesCorrection); } /** @dev Registers a loss. May be called directly after a shortfall after BPT burning occurs. @dev Calls _updateLossesTokenBalance(), whereby the contract computes the delta of the new and previous losses balance and increments the total losses (cumulative), by delta, by calling _distributeLosses(). */ function updateLossesReceived() public virtual { int256 newLosses = _updateLossesBalance(); if (newLosses <= 0) return; _distributeLosses(newLosses.toUint256Safe()); } /** @dev Recognizes all recognizable losses for an account using loss accounting. */ function _recognizeLosses() internal virtual returns (uint256 losses) { } /** @dev Updates the current losses balance and returns the difference of the new and previous losses balance. @return A int256 representing the difference of the new and previous losses balance. */ function _updateLossesBalance() internal virtual returns (int256) { } } ////// contracts/token/PoolFDT.sol /* pragma solidity 0.6.11; */ /* import "./ExtendedFDT.sol"; */ /// @title PoolFDT inherits ExtendedFDT and accounts for gains/losses for Liquidity Providers. abstract contract PoolFDT is ExtendedFDT { using SafeMath for uint256; using SafeMathUint for uint256; using SignedSafeMath for int256; using SafeMathInt for int256; uint256 public interestSum; // Sum of all withdrawable interest. uint256 public poolLosses; // Sum of all unrecognized losses. uint256 public interestBalance; // The amount of earned interest present and accounted for in this contract. uint256 public lossesBalance; // The amount of losses present and accounted for in this contract. constructor(string memory name, string memory symbol) ExtendedFDT(name, symbol) public { } /** @dev Realizes losses incurred to LPs. */ function _recognizeLosses() internal override returns (uint256 losses) { losses = _prepareLossesWithdraw(); poolLosses = poolLosses.sub(losses); _updateLossesBalance(); } /** @dev Updates the current losses balance and returns the difference of the new and previous losses balance. @return A int256 representing the difference of the new and previous losses balance. */ function _updateLossesBalance() internal override returns (int256) { uint256 _prevLossesTokenBalance = lossesBalance; lossesBalance = poolLosses; return int256(lossesBalance).sub(int256(_prevLossesTokenBalance)); } /** @dev Updates the current interest balance and returns the difference of the new and previous interest balance. @return A int256 representing the difference of the new and previous interest balance. */ function _updateFundsTokenBalance() internal override returns (int256) { uint256 _prevFundsTokenBalance = interestBalance; interestBalance = interestSum; return int256(interestBalance).sub(int256(_prevFundsTokenBalance)); } } ////// contracts/Pool.sol /* pragma solidity 0.6.11; */ /* import "lib/openzeppelin-contracts/contracts/token/ERC20/SafeERC20.sol"; */ /* import "./interfaces/IBPool.sol"; */ /* import "./interfaces/IDebtLocker.sol"; */ /* import "./interfaces/IMapleGlobals.sol"; */ /* import "./interfaces/ILiquidityLocker.sol"; */ /* import "./interfaces/ILiquidityLockerFactory.sol"; */ /* import "./interfaces/ILoan.sol"; */ /* import "./interfaces/ILoanFactory.sol"; */ /* import "./interfaces/IPoolFactory.sol"; */ /* import "./interfaces/IStakeLocker.sol"; */ /* import "./interfaces/IStakeLockerFactory.sol"; */ /* import "./library/PoolLib.sol"; */ /* import "./token/PoolFDT.sol"; */ /// @title Pool maintains all accounting and functionality related to Pools. contract Pool is PoolFDT { using SafeMath for uint256; using SafeERC20 for IERC20; uint256 constant WAD = 10 ** 18; uint8 public constant DL_FACTORY = 1; // Factory type of `DebtLockerFactory`. IERC20 public immutable liquidityAsset; // The asset deposited by Lenders into the LiquidityLocker, for funding Loans. address public immutable poolDelegate; // The Pool Delegate address, maintains full authority over the Pool. address public immutable liquidityLocker; // The LiquidityLocker owned by this contract address public immutable stakeAsset; // The address of the asset deposited by Stakers into the StakeLocker (BPTs), for liquidation during default events. address public immutable stakeLocker; // The address of the StakeLocker, escrowing `stakeAsset`. address public immutable superFactory; // The factory that deployed this Loan. uint256 private immutable liquidityAssetDecimals; // The precision for the Liquidity Asset (i.e. `decimals()`). uint256 public stakingFee; // The fee Stakers earn (in basis points). uint256 public immutable delegateFee; // The fee the Pool Delegate earns (in basis points). uint256 public principalOut; // The sum of all outstanding principal on Loans. uint256 public liquidityCap; // The amount of liquidity tokens accepted by the Pool. uint256 public lockupPeriod; // The period of time from an account's deposit date during which they cannot withdraw any funds. bool public openToPublic; // Boolean opening Pool to public for LP deposits enum State { Initialized, Finalized, Deactivated } State public poolState; mapping(address => uint256) public depositDate; // Used for withdraw penalty calculation. mapping(address => mapping(address => address)) public debtLockers; // Address of the DebtLocker corresponding to `[Loan][DebtLockerFactory]`. mapping(address => bool) public poolAdmins; // The Pool Admin addresses that have permission to do certain operations in case of disaster management. mapping(address => bool) public allowedLiquidityProviders; // Mapping that contains the list of addresses that have early access to the pool. mapping(address => uint256) public withdrawCooldown; // The timestamp of when individual LPs have notified of their intent to withdraw. mapping(address => mapping(address => uint256)) public custodyAllowance; // The amount of PoolFDTs that are "locked" at a certain address. mapping(address => uint256) public totalCustodyAllowance; // The total amount of PoolFDTs that are "locked" for a given account. Cannot be greater than an account's balance. event LoanFunded(address indexed loan, address debtLocker, uint256 amountFunded); event Claim(address indexed loan, uint256 interest, uint256 principal, uint256 fee, uint256 stakeLockerPortion, uint256 poolDelegatePortion); event BalanceUpdated(address indexed liquidityProvider, address indexed token, uint256 balance); event CustodyTransfer(address indexed custodian, address indexed from, address indexed to, uint256 amount); event CustodyAllowanceChanged(address indexed liquidityProvider, address indexed custodian, uint256 oldAllowance, uint256 newAllowance); event LPStatusChanged(address indexed liquidityProvider, bool status); event LiquidityCapSet(uint256 newLiquidityCap); event LockupPeriodSet(uint256 newLockupPeriod); event StakingFeeSet(uint256 newStakingFee); event PoolStateChanged(State state); event Cooldown(address indexed liquidityProvider, uint256 cooldown); event PoolOpenedToPublic(bool isOpen); event PoolAdminSet(address indexed poolAdmin, bool allowed); event DepositDateUpdated(address indexed liquidityProvider, uint256 depositDate); event TotalCustodyAllowanceUpdated(address indexed liquidityProvider, uint256 newTotalAllowance); event DefaultSuffered( address indexed loan, uint256 defaultSuffered, uint256 bptsBurned, uint256 bptsReturned, uint256 liquidityAssetRecoveredFromBurn ); /** Universal accounting law: fdtTotalSupply = liquidityLockerBal + principalOut - interestSum + poolLosses fdtTotalSupply + interestSum - poolLosses = liquidityLockerBal + principalOut */ /** @dev Constructor for a Pool. @dev It emits a `PoolStateChanged` event. @param _poolDelegate Address that has manager privileges of the Pool. @param _liquidityAsset Asset used to fund the Pool, It gets escrowed in LiquidityLocker. @param _stakeAsset Asset escrowed in StakeLocker. @param _slFactory Factory used to instantiate the StakeLocker. @param _llFactory Factory used to instantiate the LiquidityLocker. @param _stakingFee Fee that Stakers earn on interest, in basis points. @param _delegateFee Fee that the Pool Delegate earns on interest, in basis points. @param _liquidityCap Max amount of Liquidity Asset accepted by the Pool. @param name Name of Pool token. @param symbol Symbol of Pool token. */ constructor( address _poolDelegate, address _liquidityAsset, address _stakeAsset, address _slFactory, address _llFactory, uint256 _stakingFee, uint256 _delegateFee, uint256 _liquidityCap, string memory name, string memory symbol ) PoolFDT(name, symbol) public { // Conduct sanity checks on Pool parameters. PoolLib.poolSanityChecks(_globals(msg.sender), _liquidityAsset, _stakeAsset, _stakingFee, _delegateFee); // Assign variables relating to the Liquidity Asset. liquidityAsset = IERC20(_liquidityAsset); liquidityAssetDecimals = ERC20(_liquidityAsset).decimals(); // Assign state variables. stakeAsset = _stakeAsset; poolDelegate = _poolDelegate; stakingFee = _stakingFee; delegateFee = _delegateFee; superFactory = msg.sender; liquidityCap = _liquidityCap; // Instantiate the LiquidityLocker and the StakeLocker. stakeLocker = address(IStakeLockerFactory(_slFactory).newLocker(_stakeAsset, _liquidityAsset)); liquidityLocker = address(ILiquidityLockerFactory(_llFactory).newLocker(_liquidityAsset)); lockupPeriod = 180 days; emit PoolStateChanged(State.Initialized); } /*******************************/ /*** Pool Delegate Functions ***/ /*******************************/ /** @dev Finalizes the Pool, enabling deposits. Checks the amount the Pool Delegate deposited to the StakeLocker. Only the Pool Delegate can call this function. @dev It emits a `PoolStateChanged` event. */ function finalize() external { _isValidDelegateAndProtocolNotPaused(); _isValidState(State.Initialized); (,, bool stakeSufficient,,) = getInitialStakeRequirements(); require(stakeSufficient, "P:INSUF_STAKE"); poolState = State.Finalized; emit PoolStateChanged(poolState); } /** @dev Funds a Loan for an amount, utilizing the supplied DebtLockerFactory for DebtLockers. Only the Pool Delegate can call this function. @dev It emits a `LoanFunded` event. @dev It emits a `BalanceUpdated` event. @param loan Address of the Loan to fund. @param dlFactory Address of the DebtLockerFactory to utilize. @param amt Amount to fund the Loan. */ function fundLoan(address loan, address dlFactory, uint256 amt) external { _isValidDelegateAndProtocolNotPaused(); _isValidState(State.Finalized); principalOut = principalOut.add(amt); PoolLib.fundLoan(debtLockers, superFactory, liquidityLocker, loan, dlFactory, amt); _emitBalanceUpdatedEvent(); } /** @dev Liquidates a Loan. The Pool Delegate could liquidate the Loan only when the Loan completes its grace period. The Pool Delegate can claim its proportion of recovered funds from the liquidation using the `claim()` function. Only the Pool Delegate can call this function. @param loan Address of the Loan to liquidate. @param dlFactory Address of the DebtLockerFactory that is used to pull corresponding DebtLocker. */ function triggerDefault(address loan, address dlFactory) external { _isValidDelegateAndProtocolNotPaused(); IDebtLocker(debtLockers[loan][dlFactory]).triggerDefault(); } /** @dev Claims available funds for the Loan through a specified DebtLockerFactory. Only the Pool Delegate or a Pool Admin can call this function. @dev It emits two `BalanceUpdated` events. @dev It emits a `Claim` event. @param loan Address of the loan to claim from. @param dlFactory Address of the DebtLockerFactory. @return claimInfo The claim details. claimInfo [0] = Total amount claimed claimInfo [1] = Interest portion claimed claimInfo [2] = Principal portion claimed claimInfo [3] = Fee portion claimed claimInfo [4] = Excess portion claimed claimInfo [5] = Recovered portion claimed (from liquidations) claimInfo [6] = Default suffered */ function claim(address loan, address dlFactory) external returns (uint256[7] memory claimInfo) { _whenProtocolNotPaused(); _isValidDelegateOrPoolAdmin(); claimInfo = IDebtLocker(debtLockers[loan][dlFactory]).claim(); (uint256 poolDelegatePortion, uint256 stakeLockerPortion, uint256 principalClaim, uint256 interestClaim) = PoolLib.calculateClaimAndPortions(claimInfo, delegateFee, stakingFee); // Subtract outstanding principal by the principal claimed plus excess returned. // Considers possible `principalClaim` overflow if Liquidity Asset is transferred directly into the Loan. if (principalClaim <= principalOut) { principalOut = principalOut - principalClaim; } else { interestClaim = interestClaim.add(principalClaim - principalOut); // Distribute `principalClaim` overflow as interest to LPs. principalClaim = principalOut; // Set `principalClaim` to `principalOut` so correct amount gets transferred. principalOut = 0; // Set `principalOut` to zero to avoid subtraction overflow. } // Accounts for rounding error in StakeLocker / Pool Delegate / LiquidityLocker interest split. interestSum = interestSum.add(interestClaim); _transferLiquidityAsset(poolDelegate, poolDelegatePortion); // Transfer the fee and portion of interest to the Pool Delegate. _transferLiquidityAsset(stakeLocker, stakeLockerPortion); // Transfer the portion of interest to the StakeLocker. // Transfer remaining claim (remaining interest + principal + excess + recovered) to the LiquidityLocker. // Dust will accrue in the Pool, but this ensures that state variables are in sync with the LiquidityLocker balance updates. // Not using `balanceOf` in case of external address transferring the Liquidity Asset directly into Pool. // Ensures that internal accounting is exactly reflective of balance change. _transferLiquidityAsset(liquidityLocker, principalClaim.add(interestClaim)); // Handle default if defaultSuffered > 0. if (claimInfo[6] > 0) _handleDefault(loan, claimInfo[6]); // Update funds received for StakeLockerFDTs. IStakeLocker(stakeLocker).updateFundsReceived(); // Update funds received for PoolFDTs. updateFundsReceived(); _emitBalanceUpdatedEvent(); emit BalanceUpdated(stakeLocker, address(liquidityAsset), liquidityAsset.balanceOf(stakeLocker)); emit Claim(loan, interestClaim, principalClaim, claimInfo[3], stakeLockerPortion, poolDelegatePortion); } /** @dev Handles if a claim has been made and there is a non-zero defaultSuffered amount. @dev It emits a `DefaultSuffered` event. @param loan Address of a Loan that has defaulted. @param defaultSuffered Losses suffered from default after liquidation. */ function _handleDefault(address loan, uint256 defaultSuffered) internal { (uint256 bptsBurned, uint256 postBurnBptBal, uint256 liquidityAssetRecoveredFromBurn) = PoolLib.handleDefault(liquidityAsset, stakeLocker, stakeAsset, defaultSuffered); // If BPT burn is not enough to cover full default amount, pass on losses to LPs with PoolFDT loss accounting. if (defaultSuffered > liquidityAssetRecoveredFromBurn) { poolLosses = poolLosses.add(defaultSuffered - liquidityAssetRecoveredFromBurn); updateLossesReceived(); } // Transfer Liquidity Asset from burn to LiquidityLocker. liquidityAsset.safeTransfer(liquidityLocker, liquidityAssetRecoveredFromBurn); principalOut = principalOut.sub(defaultSuffered); // Subtract rest of the Loan's principal from `principalOut`. emit DefaultSuffered( loan, // The Loan that suffered the default. defaultSuffered, // Total default suffered from the Loan by the Pool after liquidation. bptsBurned, // Amount of BPTs burned from StakeLocker. postBurnBptBal, // Remaining BPTs in StakeLocker post-burn. liquidityAssetRecoveredFromBurn // Amount of Liquidity Asset recovered from burning BPTs. ); } /** @dev Triggers deactivation, permanently shutting down the Pool. Must have less than 100 USD worth of Liquidity Asset `principalOut`. Only the Pool Delegate can call this function. @dev It emits a `PoolStateChanged` event. */ function deactivate() external { _isValidDelegateAndProtocolNotPaused(); _isValidState(State.Finalized); PoolLib.validateDeactivation(_globals(superFactory), principalOut, address(liquidityAsset)); poolState = State.Deactivated; emit PoolStateChanged(poolState); } /**************************************/ /*** Pool Delegate Setter Functions ***/ /**************************************/ /** @dev Sets the liquidity cap. Only the Pool Delegate or a Pool Admin can call this function. @dev It emits a `LiquidityCapSet` event. @param newLiquidityCap New liquidity cap value. */ function setLiquidityCap(uint256 newLiquidityCap) external { _whenProtocolNotPaused(); _isValidDelegateOrPoolAdmin(); liquidityCap = newLiquidityCap; emit LiquidityCapSet(newLiquidityCap); } /** @dev Sets the lockup period. Only the Pool Delegate can call this function. @dev It emits a `LockupPeriodSet` event. @param newLockupPeriod New lockup period used to restrict the withdrawals. */ function setLockupPeriod(uint256 newLockupPeriod) external { _isValidDelegateAndProtocolNotPaused(); require(newLockupPeriod <= lockupPeriod, "P:BAD_VALUE"); lockupPeriod = newLockupPeriod; emit LockupPeriodSet(newLockupPeriod); } /** @dev Sets the staking fee. Only the Pool Delegate can call this function. @dev It emits a `StakingFeeSet` event. @param newStakingFee New staking fee. */ function setStakingFee(uint256 newStakingFee) external { _isValidDelegateAndProtocolNotPaused(); require(newStakingFee.add(delegateFee) <= 10_000, "P:BAD_FEE"); stakingFee = newStakingFee; emit StakingFeeSet(newStakingFee); } /** @dev Sets the account status in the Pool's allowlist. Only the Pool Delegate can call this function. @dev It emits an `LPStatusChanged` event. @param account The address to set status for. @param status The status of an account in the allowlist. */ function setAllowList(address account, bool status) external { _isValidDelegateAndProtocolNotPaused(); allowedLiquidityProviders[account] = status; emit LPStatusChanged(account, status); } /** @dev Sets a Pool Admin. Only the Pool Delegate can call this function. @dev It emits a `PoolAdminSet` event. @param poolAdmin An address being allowed or disallowed as a Pool Admin. @param allowed Status of a Pool Admin. */ function setPoolAdmin(address poolAdmin, bool allowed) external { _isValidDelegateAndProtocolNotPaused(); poolAdmins[poolAdmin] = allowed; emit PoolAdminSet(poolAdmin, allowed); } /** @dev Sets whether the Pool is open to the public. Only the Pool Delegate can call this function. @dev It emits a `PoolOpenedToPublic` event. @param open Public pool access status. */ function setOpenToPublic(bool open) external { _isValidDelegateAndProtocolNotPaused(); openToPublic = open; emit PoolOpenedToPublic(open); } /************************************/ /*** Liquidity Provider Functions ***/ /************************************/ /** @dev Handles Liquidity Providers depositing of Liquidity Asset into the LiquidityLocker, minting PoolFDTs. @dev It emits a `DepositDateUpdated` event. @dev It emits a `BalanceUpdated` event. @dev It emits a `Cooldown` event. @param amt Amount of Liquidity Asset to deposit. */ function deposit(uint256 amt) external { _whenProtocolNotPaused(); _isValidState(State.Finalized); require(isDepositAllowed(amt), "P:DEP_NOT_ALLOWED"); withdrawCooldown[msg.sender] = uint256(0); // Reset the LP's withdraw cooldown if they had previously intended to withdraw. uint256 wad = _toWad(amt); PoolLib.updateDepositDate(depositDate, balanceOf(msg.sender), wad, msg.sender); liquidityAsset.safeTransferFrom(msg.sender, liquidityLocker, amt); _mint(msg.sender, wad); _emitBalanceUpdatedEvent(); emit Cooldown(msg.sender, uint256(0)); } /** @dev Activates the cooldown period to withdraw. It can't be called if the account is not providing liquidity. @dev It emits a `Cooldown` event. **/ function intendToWithdraw() external { require(balanceOf(msg.sender) != uint256(0), "P:ZERO_BAL"); withdrawCooldown[msg.sender] = block.timestamp; emit Cooldown(msg.sender, block.timestamp); } /** @dev Cancels an initiated withdrawal by resetting the account's withdraw cooldown. @dev It emits a `Cooldown` event. **/ function cancelWithdraw() external { require(withdrawCooldown[msg.sender] != uint256(0), "P:NOT_WITHDRAWING"); withdrawCooldown[msg.sender] = uint256(0); emit Cooldown(msg.sender, uint256(0)); } /** @dev Checks that the account can withdraw an amount. @param account The address of the account. @param wad The amount to withdraw. */ function _canWithdraw(address account, uint256 wad) internal view { require(depositDate[account].add(lockupPeriod) <= block.timestamp, "P:FUNDS_LOCKED"); // Restrict withdrawal during lockup period require(balanceOf(account).sub(wad) >= totalCustodyAllowance[account], "P:INSUF_TRANS_BAL"); // Account can only withdraw tokens that aren't custodied } /** @dev Handles Liquidity Providers withdrawing of Liquidity Asset from the LiquidityLocker, burning PoolFDTs. @dev It emits two `BalanceUpdated` event. @param amt Amount of Liquidity Asset to withdraw. */ function withdraw(uint256 amt) external { _whenProtocolNotPaused(); uint256 wad = _toWad(amt); (uint256 lpCooldownPeriod, uint256 lpWithdrawWindow) = _globals(superFactory).getLpCooldownParams(); _canWithdraw(msg.sender, wad); require((block.timestamp - (withdrawCooldown[msg.sender] + lpCooldownPeriod)) <= lpWithdrawWindow, "P:WITHDRAW_NOT_ALLOWED"); _burn(msg.sender, wad); // Burn the corresponding PoolFDTs balance. withdrawFunds(); // Transfer full entitled interest, decrement `interestSum`. // Transfer amount that is due after realized losses are accounted for. // Recognized losses are absorbed by the LP. _transferLiquidityLockerFunds(msg.sender, amt.sub(_recognizeLosses())); _emitBalanceUpdatedEvent(); } /** @dev Transfers PoolFDTs. @param from Address sending PoolFDTs. @param to Address receiving PoolFDTs. @param wad Amount of PoolFDTs to transfer. */ function _transfer(address from, address to, uint256 wad) internal override { _whenProtocolNotPaused(); (uint256 lpCooldownPeriod, uint256 lpWithdrawWindow) = _globals(superFactory).getLpCooldownParams(); _canWithdraw(from, wad); require(block.timestamp > (withdrawCooldown[to] + lpCooldownPeriod + lpWithdrawWindow), "P:TO_NOT_ALLOWED"); // Recipient must not be currently withdrawing. require(recognizableLossesOf(from) == uint256(0), "P:RECOG_LOSSES"); // If an LP has unrecognized losses, they must recognize losses using `withdraw`. PoolLib.updateDepositDate(depositDate, balanceOf(to), wad, to); super._transfer(from, to, wad); } /** @dev Withdraws all claimable interest from the LiquidityLocker for an account using `interestSum` accounting. @dev It emits a `BalanceUpdated` event. */ function withdrawFunds() public override { _whenProtocolNotPaused(); uint256 withdrawableFunds = _prepareWithdraw(); if (withdrawableFunds == uint256(0)) return; _transferLiquidityLockerFunds(msg.sender, withdrawableFunds); _emitBalanceUpdatedEvent(); interestSum = interestSum.sub(withdrawableFunds); _updateFundsTokenBalance(); } /** @dev Increases the custody allowance for a given Custodian corresponding to the calling account (`msg.sender`). @dev It emits a `CustodyAllowanceChanged` event. @dev It emits a `TotalCustodyAllowanceUpdated` event. @param custodian Address which will act as Custodian of a given amount for an account. @param amount Number of additional FDTs to be custodied by the Custodian. */ function increaseCustodyAllowance(address custodian, uint256 amount) external { uint256 oldAllowance = custodyAllowance[msg.sender][custodian]; uint256 newAllowance = oldAllowance.add(amount); uint256 newTotalAllowance = totalCustodyAllowance[msg.sender].add(amount); PoolLib.increaseCustodyAllowanceChecks(custodian, amount, newTotalAllowance, balanceOf(msg.sender)); custodyAllowance[msg.sender][custodian] = newAllowance; totalCustodyAllowance[msg.sender] = newTotalAllowance; emit CustodyAllowanceChanged(msg.sender, custodian, oldAllowance, newAllowance); emit TotalCustodyAllowanceUpdated(msg.sender, newTotalAllowance); } /** @dev Transfers custodied PoolFDTs back to the account. @dev `from` and `to` should always be equal in this implementation. @dev This means that the Custodian can only decrease their own allowance and unlock funds for the original owner. @dev It emits a `CustodyTransfer` event. @dev It emits a `CustodyAllowanceChanged` event. @dev It emits a `TotalCustodyAllowanceUpdated` event. @param from Address which holds the PoolFDTs. @param to Address which will be the new owner of the amount of PoolFDTs. @param amount Amount of PoolFDTs transferred. */ function transferByCustodian(address from, address to, uint256 amount) external { uint256 oldAllowance = custodyAllowance[from][msg.sender]; uint256 newAllowance = oldAllowance.sub(amount); PoolLib.transferByCustodianChecks(from, to, amount); custodyAllowance[from][msg.sender] = newAllowance; uint256 newTotalAllowance = totalCustodyAllowance[from].sub(amount); totalCustodyAllowance[from] = newTotalAllowance; emit CustodyTransfer(msg.sender, from, to, amount); emit CustodyAllowanceChanged(from, msg.sender, oldAllowance, newAllowance); emit TotalCustodyAllowanceUpdated(msg.sender, newTotalAllowance); } /**************************/ /*** Governor Functions ***/ /**************************/ /** @dev Transfers any locked funds to the Governor. Only the Governor can call this function. @param token Address of the token to be reclaimed. */ function reclaimERC20(address token) external { PoolLib.reclaimERC20(token, address(liquidityAsset), _globals(superFactory)); } /*************************/ /*** Getter Functions ***/ /*************************/ /** @dev Calculates the value of BPT in units of Liquidity Asset. @param _bPool Address of Balancer pool. @param _liquidityAsset Asset used by Pool for liquidity to fund Loans. @param _staker Address that deposited BPTs to StakeLocker. @param _stakeLocker Escrows BPTs deposited by Staker. @return USDC value of staker BPTs. */ function BPTVal( address _bPool, address _liquidityAsset, address _staker, address _stakeLocker ) external view returns (uint256) { return PoolLib.BPTVal(_bPool, _liquidityAsset, _staker, _stakeLocker); } /** @dev Checks that the given deposit amount is acceptable based on current liquidityCap. @param depositAmt Amount of tokens (i.e liquidityAsset type) the account is trying to deposit. */ function isDepositAllowed(uint256 depositAmt) public view returns (bool) { return (openToPublic || allowedLiquidityProviders[msg.sender]) && _balanceOfLiquidityLocker().add(principalOut).add(depositAmt) <= liquidityCap; } /** @dev Returns information on the stake requirements. @return [0] = Min amount of Liquidity Asset coverage from staking required. [1] = Present amount of Liquidity Asset coverage from the Pool Delegate stake. [2] = If enough stake is present from the Pool Delegate for finalization. [3] = Staked BPTs required for minimum Liquidity Asset coverage. [4] = Current staked BPTs. */ function getInitialStakeRequirements() public view returns (uint256, uint256, bool, uint256, uint256) { return PoolLib.getInitialStakeRequirements(_globals(superFactory), stakeAsset, address(liquidityAsset), poolDelegate, stakeLocker); } /** @dev Calculates BPTs required if burning BPTs for the Liquidity Asset, given supplied `tokenAmountOutRequired`. @param _bPool The Balancer pool that issues the BPTs. @param _liquidityAsset Swap out asset (e.g. USDC) to receive when burning BPTs. @param _staker Address that deposited BPTs to StakeLocker. @param _stakeLocker Escrows BPTs deposited by Staker. @param _liquidityAssetAmountRequired Amount of Liquidity Asset required to recover. @return [0] = poolAmountIn required. [1] = poolAmountIn currently staked. */ function getPoolSharesRequired( address _bPool, address _liquidityAsset, address _staker, address _stakeLocker, uint256 _liquidityAssetAmountRequired ) external view returns (uint256, uint256) { return PoolLib.getPoolSharesRequired(_bPool, _liquidityAsset, _staker, _stakeLocker, _liquidityAssetAmountRequired); } /** @dev Checks that the Pool state is `Finalized`. @return bool Boolean value indicating if Pool is in a Finalized state. */ function isPoolFinalized() external view returns (bool) { return poolState == State.Finalized; } /************************/ /*** Helper Functions ***/ /************************/ /** @dev Converts to WAD precision. @param amt Amount to convert. */ function _toWad(uint256 amt) internal view returns (uint256) { return amt.mul(WAD).div(10 ** liquidityAssetDecimals); } /** @dev Returns the balance of this Pool's LiquidityLocker. @return Balance of LiquidityLocker. */ function _balanceOfLiquidityLocker() internal view returns (uint256) { return liquidityAsset.balanceOf(liquidityLocker); } /** @dev Checks that the current state of Pool matches the provided state. @param _state Enum of desired Pool state. */ function _isValidState(State _state) internal view { require(poolState == _state, "P:BAD_STATE"); } /** @dev Checks that `msg.sender` is the Pool Delegate. */ function _isValidDelegate() internal view { require(msg.sender == poolDelegate, "P:NOT_DEL"); } /** @dev Returns the MapleGlobals instance. */ function _globals(address poolFactory) internal view returns (IMapleGlobals) { return IMapleGlobals(IPoolFactory(poolFactory).globals()); } /** @dev Emits a `BalanceUpdated` event for LiquidityLocker. @dev It emits a `BalanceUpdated` event. */ function _emitBalanceUpdatedEvent() internal { emit BalanceUpdated(liquidityLocker, address(liquidityAsset), _balanceOfLiquidityLocker()); } /** @dev Transfers Liquidity Asset to given `to` address, from self (i.e. `address(this)`). @param to Address to transfer liquidityAsset. @param value Amount of liquidity asset that gets transferred. */ function _transferLiquidityAsset(address to, uint256 value) internal { liquidityAsset.safeTransfer(to, value); } /** @dev Checks that `msg.sender` is the Pool Delegate or a Pool Admin. */ function _isValidDelegateOrPoolAdmin() internal view { require(msg.sender == poolDelegate || poolAdmins[msg.sender], "P:NOT_DEL_OR_ADMIN"); } /** @dev Checks that the protocol is not in a paused state. */ function _whenProtocolNotPaused() internal view { require(!_globals(superFactory).protocolPaused(), "P:PROTO_PAUSED"); } /** @dev Checks that `msg.sender` is the Pool Delegate and that the protocol is not in a paused state. */ function _isValidDelegateAndProtocolNotPaused() internal view { _isValidDelegate(); _whenProtocolNotPaused(); } function _transferLiquidityLockerFunds(address to, uint256 value) internal { ILiquidityLocker(liquidityLocker).transfer(to, value); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_poolDelegate","type":"address"},{"internalType":"address","name":"_liquidityAsset","type":"address"},{"internalType":"address","name":"_stakeAsset","type":"address"},{"internalType":"address","name":"_slFactory","type":"address"},{"internalType":"address","name":"_llFactory","type":"address"},{"internalType":"uint256","name":"_stakingFee","type":"uint256"},{"internalType":"uint256","name":"_delegateFee","type":"uint256"},{"internalType":"uint256","name":"_liquidityCap","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidityProvider","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"BalanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"loan","type":"address"},{"indexed":false,"internalType":"uint256","name":"interest","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"principal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stakeLockerPortion","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"poolDelegatePortion","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidityProvider","type":"address"},{"indexed":false,"internalType":"uint256","name":"cooldown","type":"uint256"}],"name":"Cooldown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidityProvider","type":"address"},{"indexed":true,"internalType":"address","name":"custodian","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldAllowance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAllowance","type":"uint256"}],"name":"CustodyAllowanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"custodian","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CustodyTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"loan","type":"address"},{"indexed":false,"internalType":"uint256","name":"defaultSuffered","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bptsBurned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bptsReturned","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidityAssetRecoveredFromBurn","type":"uint256"}],"name":"DefaultSuffered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidityProvider","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositDate","type":"uint256"}],"name":"DepositDateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundsDistributed","type":"uint256"}],"name":"FundsDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"fundsWithdrawn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalWithdrawn","type":"uint256"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidityProvider","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"LPStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newLiquidityCap","type":"uint256"}],"name":"LiquidityCapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"loan","type":"address"},{"indexed":false,"internalType":"address","name":"debtLocker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountFunded","type":"uint256"}],"name":"LoanFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newLockupPeriod","type":"uint256"}],"name":"LockupPeriodSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"int256","name":"lossesCorrection","type":"int256"}],"name":"LossesCorrectionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"lossesDistributed","type":"uint256"}],"name":"LossesDistributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"lossesPerShare","type":"uint256"}],"name":"LossesPerShareUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"uint256","name":"lossesRecognized","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalLossesRecognized","type":"uint256"}],"name":"LossesRecognized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"int256","name":"pointsCorrection","type":"int256"}],"name":"PointsCorrectionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"pointsPerShare","type":"uint256"}],"name":"PointsPerShareUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"poolAdmin","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"PoolAdminSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isOpen","type":"bool"}],"name":"PoolOpenedToPublic","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum Pool.State","name":"state","type":"uint8"}],"name":"PoolStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newStakingFee","type":"uint256"}],"name":"StakingFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"liquidityProvider","type":"address"},{"indexed":false,"internalType":"uint256","name":"newTotalAllowance","type":"uint256"}],"name":"TotalCustodyAllowanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"_bPool","type":"address"},{"internalType":"address","name":"_liquidityAsset","type":"address"},{"internalType":"address","name":"_staker","type":"address"},{"internalType":"address","name":"_stakeLocker","type":"address"}],"name":"BPTVal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DL_FACTORY","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"accumulativeFundsOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"accumulativeLossesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowedLiquidityProviders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"loan","type":"address"},{"internalType":"address","name":"dlFactory","type":"address"}],"name":"claim","outputs":[{"internalType":"uint256[7]","name":"claimInfo","type":"uint256[7]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"custodyAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deactivate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"debtLockers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delegateFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"depositDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"loan","type":"address"},{"internalType":"address","name":"dlFactory","type":"address"},{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"fundLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getInitialStakeRequirements","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bPool","type":"address"},{"internalType":"address","name":"_liquidityAsset","type":"address"},{"internalType":"address","name":"_staker","type":"address"},{"internalType":"address","name":"_stakeLocker","type":"address"},{"internalType":"uint256","name":"_liquidityAssetAmountRequired","type":"uint256"}],"name":"getPoolSharesRequired","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"custodian","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"increaseCustodyAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"intendToWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestSum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"depositAmt","type":"uint256"}],"name":"isDepositAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPoolFinalized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityAsset","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidityLocker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockupPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lossesBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openToPublic","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"poolAdmins","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolDelegate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLosses","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolState","outputs":[{"internalType":"enum Pool.State","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"principalOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"reclaimERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"recognizableLossesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"recognizedLossesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setAllowList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLiquidityCap","type":"uint256"}],"name":"setLiquidityCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLockupPeriod","type":"uint256"}],"name":"setLockupPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"open","type":"bool"}],"name":"setOpenToPublic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"poolAdmin","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setPoolAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newStakingFee","type":"uint256"}],"name":"setStakingFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakeLocker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"superFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalCustodyAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferByCustodian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"loan","type":"address"},{"internalType":"address","name":"dlFactory","type":"address"}],"name":"triggerDefault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateFundsReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateLossesReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amt","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"withdrawCooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"withdrawableFundsOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"withdrawnFundsOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101806040523480156200001257600080fd5b50604051620050433803806200504383398181016040526101408110156200003957600080fd5b815160208301516040808501516060860151608087015160a088015160c089015160e08a01516101008b0180519751999b989a969995989497939692959194919392820192846401000000008211156200009257600080fd5b908301906020820185811115620000a857600080fd5b8251640100000000811182820188101715620000c357600080fd5b82525081516020918201929091019080838360005b83811015620000f2578181015183820152602001620000d8565b50505050905090810190601f168015620001205780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200014457600080fd5b9083019060208201858111156200015a57600080fd5b82516401000000008111828201881017156200017557600080fd5b82525081516020918201929091019080838360005b83811015620001a45781810151838201526020016200018a565b50505050905090810190601f168015620001d25780820380516001836020036101000a031916815260200191505b5060405250505081818181818181818160039080519060200190620001f99291906200056e565b5080516200020f9060049060208401906200056e565b50506005805460ff1916601217905550732c1c30fb8cc313ef3cfd2e2bbf2da88add902c30955063149851689450620002589350339250506001600160e01b03620004fe169050565b604080516001600160e01b031960e085901b1681526001600160a01b039283166004820152828e166024820152918c16604483015260648201899052608482018890525160a4808301926000929190829003018186803b158015620002bc57600080fd5b505af4158015620002d1573d6000803e3d6000fd5b50505050886001600160a01b03166080816001600160a01b031660601b81525050886001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156200032c57600080fd5b505afa15801562000341573d6000803e3d6000fd5b505050506040513d60208110156200035857600080fd5b505160ff1661014052606088811b6001600160601b031990811660e0528b821b1660a052601086905561016085905233901b610120526012839055604080516342ef033f60e11b81526001600160a01b03808b1660048301528b811660248301529151918916916385de067e916044808201926020929091908290030181600087803b158015620003e857600080fd5b505af1158015620003fd573d6000803e3d6000fd5b505050506040513d60208110156200041457600080fd5b505160601b6001600160601b0319166101005260408051630cf5bc1d60e11b81526001600160a01b038b811660048301529151918816916319eb783a916024808201926020929091908290030181600087803b1580156200047457600080fd5b505af115801562000489573d6000803e3d6000fd5b505050506040513d6020811015620004a057600080fd5b505160601b6001600160601b03191660c05262ed4e00601355604080516000815290517f24b0afb747a8213aea796b9518bfa667de187b83390eda7cc93b8e57f80fcd1a916020908290030190a15050505050505050505062000613565b6000816001600160a01b031663c31245256040518163ffffffff1660e01b815260040160206040518083038186803b1580156200053a57600080fd5b505afa1580156200054f573d6000803e3d6000fd5b505050506040513d60208110156200056657600080fd5b505192915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620005b157805160ff1916838001178555620005e1565b82800160010185558215620005e1579182015b82811115620005e1578251825591602001919060010190620005c4565b50620005ef929150620005f3565b5090565b6200061091905b80821115620005ef5760008155600101620005fa565b90565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c6101205160601c61014051610160516148fd62000746600039806111395280611c695280612644525080613397525080610d5f5280610da85280610f5f52806119ae5280611ed152806123b15280612c755280613020525080610c875280610e6b528061127752806112f2528061139f52806114195280612e45525080610df3528061225f5280612e6d525080610f8752806112a1528061251052806127285280612c0c5280612f7552806132ac5280613805525080610e43528061124d5280611b4c5280612d4b5280613b28525080610e1b5280611027528061137552806113ea5280611efa528061238d52806127055280612be25280612dd95280612e1d5280612f5352806137d652506148fd6000f3fe608060405234801561001057600080fd5b50600436106103fb5760003560e01c806370a0823111610215578063a9059cbb11610125578063c771c390116100b8578063d82745c811610087578063d82745c814610bfa578063dd62ed3e14610c20578063ee947a7c14610c4e578063eff9884314610c56578063fec984e314610c5e576103fb565b8063c771c39014610b79578063c965b54814610b96578063cc0fef0214610bc4578063d7bd3c9114610bcc576103fb565b8063b69410de116100f4578063b69410de14610acf578063b6b55f2514610ad7578063c374682514610af4578063c59e395914610b53576103fb565b8063a9059cbb14610a4f578063ac64165514610a7b578063aed4966a14610a83578063af6d557114610aa9576103fb565b806384b76824116101a85780639759164a116101775780639759164a146109ec5780639f3c7325146109f4578063a33142f7146109fc578063a43baa3d14610a04578063a457c2d714610a23576103fb565b806384b76824146109885780638905fd4f146109905780639185192a146109b657806395d89b41146109e4576103fb565b806376687d3d116101e457806376687d3d1461093e5780637b99adb11461094657806380cd916d1461096357806380e7ce851461096b576103fb565b806370a08231146108da57806371073bac1461090057806373ef9a50146109085780637666f12514610910576103fb565b80632e1a7d4d1161031057806346c162de116102a357806351b42b001161027257806351b42b001461081c578063613384f214610824578063641ad8a91461084a5780636696779114610876578063681cb10a1461089c576103fb565b806346c162de146107de5780634bb278f3146107e65780634e97415f146107ee5780634f85221a14610814576103fb565b806340504ba0116102df57806340504ba01461074757806340bde09814610775578063410dbf7e1461079b578063443bb293146107b8576103fb565b80632e1a7d4d146106ee578063313ce5671461070b57806339509351146107135780634046af2b1461073f576103fb565b80631831ccf21161039357806323b872dd1161036257806323b872dd1461062857806324600fc31461065e57806324b92e8e1461066657806327f918561461068c5780632ac04ac8146106b8576103fb565b80631831ccf21461057a5780631aa37cec14610582578063209b2bca146105ba57806321c0b342146105c2576103fb565b80630d49b38c116103cf5780630d49b38c1461051957806313bf9e7e14610521578063174a5be41461055457806318160ddd14610572576103fb565b806241c52c14610400578063033b1cf01461043857806306fdde031461045c578063095ea7b3146104d9575b600080fd5b6104266004803603602081101561041657600080fd5b50356001600160a01b0316610c66565b60408051918252519081900360200190f35b610440610c85565b604080516001600160a01b039092168252519081900360200190f35b610464610ca9565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561049e578181015183820152602001610486565b50505050905090810190601f1680156104cb5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610505600480360360408110156104ef57600080fd5b506001600160a01b038135169060200135610d3f565b604080519115158252519081900360200190f35b610440610d5d565b610529610d81565b6040805195865260208601949094529115158484015260608401526080830152519081900360a00190f35b61055c610f04565b6040805160ff9092168252519081900360200190f35b610426610f09565b610505610f0f565b6105b86004803603606081101561059857600080fd5b506001600160a01b03813581169160208101359091169060400135610f18565b005b610440611025565b6105f0600480360360408110156105d857600080fd5b506001600160a01b0381358116916020013516611049565b604051808260e080838360005b838110156106155781810151838201526020016105fd565b5050505090500191505060405180910390f35b6105056004803603606081101561063e57600080fd5b506001600160a01b03813581169160208101359091169060400135611525565b6105b86115b3565b6104266004803603602081101561067c57600080fd5b50356001600160a01b0316611607565b6105b8600480360360408110156106a257600080fd5b506001600160a01b038135169060200135611619565b6105b8600480360360608110156106ce57600080fd5b506001600160a01b038135811691602081013590911690604001356117ba565b6105b86004803603602081101561070457600080fd5b5035611991565b61055c611aed565b6105056004803603604081101561072957600080fd5b506001600160a01b038135169060200135611af6565b610440611b4a565b6105b86004803603604081101561075d57600080fd5b506001600160a01b0381358116916020013516611b6e565b6104266004803603602081101561078b57600080fd5b50356001600160a01b0316611bef565b6105b8600480360360208110156107b157600080fd5b5035611c58565b610426600480360360208110156107ce57600080fd5b50356001600160a01b0316611d0d565b6105b8611d3f565b6105b8611d6d565b6104266004803603602081101561080457600080fd5b50356001600160a01b0316611e3b565b610505611e80565b6105b8611ea0565b6105056004803603602081101561083a57600080fd5b50356001600160a01b0316611ff9565b61085261200e565b6040518082600281111561086257fe5b60ff16815260200191505060405180910390f35b6104266004803603602081101561088c57600080fd5b50356001600160a01b031661201c565b610426600480360360808110156108b257600080fd5b506001600160a01b038135811691602081013582169160408201358116916060013516612042565b610426600480360360208110156108f057600080fd5b50356001600160a01b03166120ed565b610426612108565b6105b861210e565b6105b86004803603604081101561092657600080fd5b506001600160a01b03813516906020013515156121a4565b61042661220c565b6105b86004803603602081101561095c57600080fd5b5035612212565b61044061225d565b6105056004803603602081101561098157600080fd5b5035612281565b6105b86122d4565b6105b8600480360360208110156109a657600080fd5b50356001600160a01b0316612370565b6105b8600480360360408110156109cc57600080fd5b506001600160a01b0381351690602001351515612445565b6104646124ad565b61044061250e565b610426612532565b610426612538565b6105b860048036036020811015610a1a57600080fd5b5035151561253e565b61050560048036036040811015610a3957600080fd5b506001600160a01b03813516906020013561258d565b61050560048036036040811015610a6557600080fd5b506001600160a01b0381351690602001356125fb565b61042661260f565b61042660048036036020811015610a9957600080fd5b50356001600160a01b0316612615565b61042660048036036020811015610abf57600080fd5b50356001600160a01b0316612630565b610426612642565b6105b860048036036020811015610aed57600080fd5b5035612666565b610b3a600480360360a0811015610b0a57600080fd5b506001600160a01b03813581169160208101358216916040820135811691606081013590911690608001356127a0565b6040805192835260208301919091528051918290030190f35b61050560048036036020811015610b6957600080fd5b50356001600160a01b031661285d565b6105b860048036036020811015610b8f57600080fd5b5035612872565b61042660048036036040811015610bac57600080fd5b506001600160a01b03813581169160200135166128fa565b6105b8612917565b61044060048036036040811015610be257600080fd5b506001600160a01b0381358116916020013516612942565b61042660048036036020811015610c1057600080fd5b50356001600160a01b0316612968565b61042660048036036040811015610c3657600080fd5b506001600160a01b038135811691602001351661297a565b6104266129a5565b6104266129ab565b6104266129b1565b6001600160a01b0381166000908152600860205260409020545b919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60038054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610d355780601f10610d0a57610100808354040283529160200191610d35565b820191906000526020600020905b815481529060010190602001808311610d1857829003601f168201915b5050505050905090565b6000610d53610d4c6129b7565b84846129bb565b5060015b92915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000806000806000732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3063767f5038610dcc7f0000000000000000000000000000000000000000000000000000000000000000612aa7565b6040805160e084901b6001600160e01b03191681526001600160a01b0392831660048201527f0000000000000000000000000000000000000000000000000000000000000000831660248201527f0000000000000000000000000000000000000000000000000000000000000000831660448201527f0000000000000000000000000000000000000000000000000000000000000000831660648201527f000000000000000000000000000000000000000000000000000000000000000090921660848301525160a48083019260a0929190829003018186803b158015610eb257600080fd5b505af4158015610ec6573d6000803e3d6000fd5b505050506040513d60a0811015610edc57600080fd5b5080516020820151604083015160608401516080909401519299919850965091945092509050565b600181565b60025490565b60145460ff1681565b610f20612b14565b610f2a6001612b24565b601154610f3d908263ffffffff612b8616565b6011556040805163fbecb17160e01b8152601660048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301527f00000000000000000000000000000000000000000000000000000000000000008116604483015280861660648301528416608482015260a481018390529051732c1c30fb8cc313ef3cfd2e2bbf2da88add902c309163fbecb1719160c4808301926000929190829003018186803b15801561100057600080fd5b505af4158015611014573d6000803e3d6000fd5b50505050611020612be0565b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6110516146af565b611059612c70565b611061612d40565b6001600160a01b0380841660009081526016602090815260408083208685168452909152808220548151634e71d92d60e01b81529151931692634e71d92d9260048084019360e093929083900390910190829087803b1580156110c357600080fd5b505af11580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525060e08110156110fc57600080fd5b50601054604051633faa6c5d60e01b8152919250600091829182918291732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3091633faa6c5d9188917f00000000000000000000000000000000000000000000000000000000000000009190600401808460e08083838c5b8381101561117e578181015183820152602001611166565b50505050905001838152602001828152602001935050505060806040518083038186803b1580156111ae57600080fd5b505af41580156111c2573d6000803e3d6000fd5b505050506040513d60808110156111d857600080fd5b50805160208201516040830151606090930151601154929750909550919350909150821161120e57601180548390039055611232565b601154611224908290840363ffffffff612b8616565b601180546000909155925090505b600c54611245908263ffffffff612b8616565b600c556112727f000000000000000000000000000000000000000000000000000000000000000085612dcc565b61129c7f000000000000000000000000000000000000000000000000000000000000000084612dcc565b6112d57f00000000000000000000000000000000000000000000000000000000000000006112d0848463ffffffff612b8616565b612dcc565b60c0850151156112f0576112f0878660066020020151612e06565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166346c162de6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561134b57600080fd5b505af115801561135f573d6000803e3d6000fd5b5050505061136b611d3f565b611373612be0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f2047d1633ff7768462ae07d28cb16e484203bfd6d85ce832494270ebcd9081a27f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a082317f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561147e57600080fd5b505afa158015611492573d6000803e3d6000fd5b505050506040513d60208110156114a857600080fd5b505160408051918252519081900360200190a36060808601516040805184815260208101869052808201929092529181018590526080810186905290516001600160a01b038916917f21280d282ce6aa29c649fd1825373d7c77892fac3f1958fd98d5ca52dd82a197919081900360a00190a25050505092915050565b6000611532848484613010565b6115a88461153e6129b7565b6115a3856040518060600160405280602881526020016147c3602891396001600160a01b038a1660009081526001602052604081209061157c6129b7565b6001600160a01b03168152602081019190915260400160002054919063ffffffff61318e16565b6129bb565b5060015b9392505050565b6115bb612c70565b60006115c5613225565b9050806115d25750611605565b6115dc33826132aa565b6115e4612be0565b600c546115f7908263ffffffff61332a16565b600c5561160261336c565b50505b565b60156020526000908152604090205481565b336000908152601a602090815260408083206001600160a01b03861684529091528120549061164e828463ffffffff612b8616565b336000908152601b602052604081205491925090611672908563ffffffff612b8616565b9050732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3063297e7bf786868461169a336120ed565b6040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b0316815260200184815260200183815260200182815260200194505050505060006040518083038186803b1580156116f557600080fd5b505af4158015611709573d6000803e3d6000fd5b5050336000818152601a602090815260408083206001600160a01b038c16808552908352818420899055848452601b835292819020879055805189815291820188905280519295509293507f847e03d69a7075471d42285f4ac63570c10f3012d8bf736d66de2eef17aac3e892908290030190a360408051828152905133917fe7f3fb4dacbff434e6d283d891f199c48b05b1629f610bd7ddc62353e162fb16919081900360200190a25050505050565b6001600160a01b0383166000908152601a60209081526040808320338452909152812054906117ef828463ffffffff61332a16565b60408051631b4c903160e01b81526001600160a01b03808916600483015287166024820152604481018690529051919250732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3091631b4c903191606480820192600092909190829003018186803b15801561185c57600080fd5b505af4158015611870573d6000803e3d6000fd5b505050506001600160a01b0385166000818152601a602090815260408083203384528252808320859055928252601b9052908120546118af908561332a565b6001600160a01b038088166000818152601b60209081526040918290208590558151898152915194955092891693919233927ffaa022ea2cd7f14157070896fabadafe96cc4d4714eef7ae6a992a5084493ed59281900390910190a46040805184815260208101849052815133926001600160a01b038a16927f847e03d69a7075471d42285f4ac63570c10f3012d8bf736d66de2eef17aac3e8929081900390910190a360408051828152905133917fe7f3fb4dacbff434e6d283d891f199c48b05b1629f610bd7ddc62353e162fb16919081900360200190a2505050505050565b611999612c70565b60006119a482613390565b90506000806119d27f0000000000000000000000000000000000000000000000000000000000000000612aa7565b6001600160a01b0316639f51290b6040518163ffffffff1660e01b8152600401604080518083038186803b158015611a0957600080fd5b505afa158015611a1d573d6000803e3d6000fd5b505050506040513d6040811015611a3357600080fd5b5080516020909101519092509050611a4b33846133dd565b3360009081526019602052604090205482014203811015611aac576040805162461bcd60e51b8152602060048201526016602482015275140e95d2551211149055d7d393d517d0531313d5d15160521b604482015290519081900360640190fd5b611ab633846134bc565b611abe6115b3565b611adf33611ada611acd613563565b879063ffffffff61332a16565b6132aa565b611ae7612be0565b50505050565b60055460ff1690565b6000610d53611b036129b7565b846115a38560016000611b146129b7565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff612b8616565b7f000000000000000000000000000000000000000000000000000000000000000081565b611b76612b14565b6001600160a01b038083166000908152601660209081526040808320858516845290915280822054815163175f832960e01b8152915193169263175f83299260048084019391929182900301818387803b158015611bd357600080fd5b505af1158015611be7573d6000803e3d6000fd5b505050505050565b6001600160a01b0381166000908152600a6020526040812054600160801b90611c4a90611c4590611c39611c34611c25886120ed565b6009549063ffffffff61359216565b6135eb565b9063ffffffff61362c16565b613691565b81611c5157fe5b0492915050565b611c60612b14565b612710611c93827f000000000000000000000000000000000000000000000000000000000000000063ffffffff612b8616565b1115611cd2576040805162461bcd60e51b8152602060048201526009602482015268503a4241445f46454560b81b604482015290519081900360640190fd5b60108190556040805182815290517f9408bb8c08d29b335e36090045074610352365476d9df02e203c25db4fcd67c09181900360200190a150565b6001600160a01b038116600090815260086020526040812054610d5790611d3384611e3b565b9063ffffffff61332a16565b6000611d4961336c565b905060008113611d595750611605565b611d6a611d6582613691565b6136d2565b50565b611d75612b14565b611d7f6000612b24565b6000611d89610d81565b50509250505080611dd1576040805162461bcd60e51b815260206004820152600d60248201526c503a494e5355465f5354414b4560981b604482015290519081900360640190fd5b601480546001919061ff0019166101008302179055506014546040517f24b0afb747a8213aea796b9518bfa667de187b83390eda7cc93b8e57f80fcd1a91610100900460ff169080826002811115611e2557fe5b60ff16815260200191505060405180910390a150565b6001600160a01b038116600090815260076020526040812054600160801b90611c4a90611c4590611c39611c34611e71886120ed565b6006549063ffffffff61359216565b60006001601454610100900460ff166002811115611e9a57fe5b14905090565b611ea8612b14565b611eb26001612b24565b732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3063abbedb40611ef57f0000000000000000000000000000000000000000000000000000000000000000612aa7565b6011547f00000000000000000000000000000000000000000000000000000000000000006040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001838152602001826001600160a01b03166001600160a01b03168152602001935050505060006040518083038186803b158015611f7f57600080fd5b505af4158015611f93573d6000803e3d6000fd5b50506014805461ff00191661020017908190556040517f24b0afb747a8213aea796b9518bfa667de187b83390eda7cc93b8e57f80fcd1a935061010090910460ff16915080826002811115611fe457fe5b60ff16815260200191505060405180910390a1565b60176020526000908152604090205460ff1681565b601454610100900460ff1681565b6001600160a01b0381166000908152600b6020526040812054610d5790611d3384611bef565b6040805163340e588560e11b81526001600160a01b03808716600483015280861660248301528085166044830152831660648201529051600091732c1c30fb8cc313ef3cfd2e2bbf2da88add902c309163681cb10a91608480820192602092909190829003018186803b1580156120b857600080fd5b505af41580156120cc573d6000803e3d6000fd5b505050506040513d60208110156120e257600080fd5b505195945050505050565b6001600160a01b031660009081526020819052604090205490565b600c5481565b6000612119336120ed565b1415612159576040805162461bcd60e51b815260206004820152600a602482015269140e96915493d7d0905360b21b604482015290519081900360640190fd5b336000818152601960209081526040918290204290819055825190815291517f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d659281900390910190a2565b6121ac612b14565b6001600160a01b038216600081815260186020908152604091829020805460ff1916851515908117909155825190815291517fdf56132520665b33cd5731c5cfbacd8bee82524e67df563bb25b2be304f91d449281900390910190a25050565b60125481565b61221a612c70565b612222612d40565b60128190556040805182815290517f3ff20538222f568f27ff436c0c49dfd3e48d5b8f86533a3f759dc1c7089775ab9181900360200190a150565b7f000000000000000000000000000000000000000000000000000000000000000081565b60145460009060ff16806122a457503360009081526018602052604090205460ff165b8015610d5757506012546122cc836122c06011546122c06137d2565b9063ffffffff612b8616565b111592915050565b33600090815260196020526040902054612329576040805162461bcd60e51b8152602060048201526011602482015270503a4e4f545f5749544844524157494e4760781b604482015290519081900360640190fd5b3360008181526019602090815260408083208390558051928352517f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d659281900390910190a2565b732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3063a89d5ddb827f00000000000000000000000000000000000000000000000000000000000000006123d57f0000000000000000000000000000000000000000000000000000000000000000612aa7565b604080516001600160e01b031960e087901b1681526001600160a01b03948516600482015292841660248401529216604482015290516064808301926000929190829003018186803b15801561242a57600080fd5b505af415801561243e573d6000803e3d6000fd5b5050505050565b61244d612b14565b6001600160a01b038216600081815260176020908152604091829020805460ff1916851515908117909155825190815291517f353578bbc0ab907b7018b0f7b50b5f822d31dc9fcf4c16fffa780e109ca7c9309281900390910190a25050565b60048054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610d355780601f10610d0a57610100808354040283529160200191610d35565b7f000000000000000000000000000000000000000000000000000000000000000081565b600e5481565b600d5481565b612546612b14565b6014805482151560ff19909116811790915560408051918252517feeba6fd794e30165023f7e3d017e92901622076a95d36e45906955e025ff4fe79181900360200190a150565b6000610d5361259a6129b7565b846115a3856040518060600160405280602581526020016148a360259139600160006125c46129b7565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff61318e16565b6000610d536126086129b7565b8484613010565b60115481565b6001600160a01b03166000908152600b602052604090205490565b601b6020526000908152604090205481565b7f000000000000000000000000000000000000000000000000000000000000000081565b61266e612c70565b6126786001612b24565b61268181612281565b6126c6576040805162461bcd60e51b8152602060048201526011602482015270140e91115417d393d517d0531313d5d151607a1b604482015290519081900360640190fd5b3360009081526019602052604081208190556126e182613390565b90506126f860156126f1336120ed565b833361389b565b6127536001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016337f00000000000000000000000000000000000000000000000000000000000000008563ffffffff61395416565b61275d33826139ae565b612765612be0565b6040805160008152905133917f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d65919081900360200190a25050565b6040805163c374682560e01b81526001600160a01b03808816600483015280871660248301528086166044830152841660648201526084810183905281516000928392732c1c30fb8cc313ef3cfd2e2bbf2da88add902c309263c37468259260a480840193919291829003018186803b15801561281c57600080fd5b505af4158015612830573d6000803e3d6000fd5b505050506040513d604081101561284657600080fd5b508051602090910151909890975095505050505050565b60186020526000908152604090205460ff1681565b61287a612b14565b6013548111156128bf576040805162461bcd60e51b815260206004820152600b60248201526a503a4241445f56414c554560a81b604482015290519081900360640190fd5b60138190556040805182815290517f3094b4ce0463766c3cd81ed2ae2451610dcac39a1061fa023ca9d3d4df959f759181900360200190a150565b601a60209081526000928352604080842090915290825290205481565b60006129216139fa565b9050600081136129315750611605565b611d6a61293d82613691565b613a18565b60166020908152600092835260408084209091529082529020546001600160a01b031681565b60196020526000908152604090205481565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60135481565b60105481565b600f5481565b3390565b6001600160a01b038316612a005760405162461bcd60e51b81526004018080602001828103825260248152602001806148316024913960400191505060405180910390fd5b6001600160a01b038216612a455760405162461bcd60e51b81526004018080602001828103825260228152602001806147136022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6000816001600160a01b031663c31245256040518163ffffffff1660e01b815260040160206040518083038186803b158015612ae257600080fd5b505afa158015612af6573d6000803e3d6000fd5b505050506040513d6020811015612b0c57600080fd5b505192915050565b612b1c613b1d565b611605612c70565b806002811115612b3057fe5b601454610100900460ff166002811115612b4657fe5b14611d6a576040805162461bcd60e51b815260206004820152600b60248201526a503a4241445f535441544560a81b604482015290519081900360640190fd5b6000828201838110156115ac576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f2047d1633ff7768462ae07d28cb16e484203bfd6d85ce832494270ebcd9081a2612c5d6137d2565b60408051918252519081900360200190a3565b612c997f0000000000000000000000000000000000000000000000000000000000000000612aa7565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015612cd157600080fd5b505afa158015612ce5573d6000803e3d6000fd5b505050506040513d6020811015612cfb57600080fd5b505115611605576040805162461bcd60e51b815260206004820152600e60248201526d140e941493d513d7d4105554d15160921b604482015290519081900360640190fd5b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480612d8657503360009081526017602052604090205460ff165b611605576040805162461bcd60e51b8152602060048201526012602482015271281d2727aa2fa222a62fa7a92fa0a226a4a760711b604482015290519081900360640190fd5b6116026001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016838363ffffffff613b8616565b6040805162715b0960e41b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301527f0000000000000000000000000000000000000000000000000000000000000000811660248301527f000000000000000000000000000000000000000000000000000000000000000016604482015260648101839052905160009182918291732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3091630715b09091608480820192606092909190829003018186803b158015612ede57600080fd5b505af4158015612ef2573d6000803e3d6000fd5b505050506040513d6060811015612f0857600080fd5b5080516020820151604090920151909450909250905080841115612f4657600d54612f3b9082860363ffffffff612b8616565b600d55612f46612917565b612fa06001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000167f00000000000000000000000000000000000000000000000000000000000000008363ffffffff613b8616565b601154612fb3908563ffffffff61332a16565b60115560408051858152602081018590528082018490526060810183905290516001600160a01b038716917fd393d18014c1898545668c52621bced9493753be5b8138f2539542ca606732eb919081900360800190a25050505050565b613018612c70565b6000806130447f0000000000000000000000000000000000000000000000000000000000000000612aa7565b6001600160a01b0316639f51290b6040518163ffffffff1660e01b8152600401604080518083038186803b15801561307b57600080fd5b505afa15801561308f573d6000803e3d6000fd5b505050506040513d60408110156130a557600080fd5b50805160209091015190925090506130bd85846133dd565b6001600160a01b038416600090815260196020526040902054820181014211613120576040805162461bcd60e51b815260206004820152601060248201526f140e9513d7d393d517d0531313d5d15160821b604482015290519081900360640190fd5b600061312b8661201c565b1461316e576040805162461bcd60e51b815260206004820152600e60248201526d503a5245434f475f4c4f5353455360901b604482015290519081900360640190fd5b613183601561317c866120ed565b858761389b565b61243e858585613bd8565b6000818484111561321d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156131e25781810151838201526020016131ca565b50505050905090810190601f16801561320f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600061323033611d0d565b3360009081526008602052604081205491925090613254908363ffffffff612b8616565b336000818152600860209081526040918290208490558151868152908101849052815193945091927ffbc3a599b784fe88772fc5abcc07223f64ca0b13acc341f4fb1e46bef0510eb49281900390910190a25090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb83836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015611bd357600080fd5b60006115ac83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061318e565b600e8054600c549182905560009161338a908263ffffffff613d0416565b91505090565b6000610d577f0000000000000000000000000000000000000000000000000000000000000000600a0a6133d184670de0b6b3a764000063ffffffff61359216565b9063ffffffff613d6916565b6013546001600160a01b038316600090815260156020526040902054429161340b919063ffffffff612b8616565b111561344f576040805162461bcd60e51b815260206004820152600e60248201526d140e9195539114d7d313d0d2d15160921b604482015290519081900360640190fd5b6001600160a01b0382166000908152601b602052604090205461347582611d33856120ed565b1015611602576040805162461bcd60e51b8152602060048201526011602482015270140e925394d55197d514905394d7d09053607a1b604482015290519081900360640190fd5b6134c68282613dab565b60006135086134e3611c348460095461359290919063ffffffff16565b6001600160a01b0385166000908152600a60205260409020549063ffffffff61362c16565b6001600160a01b0384166000818152600a60209081526040918290208490558151848152915193945091927fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3929181900390910190a2505050565b600061356d613e52565b600d54909150613583908263ffffffff61332a16565b600d5561358e6139fa565b5090565b6000826135a157506000610d57565b828202828482816135ae57fe5b04146115ac5760405162461bcd60e51b81526004018080602001828103825260218152602001806147a26021913960400191505060405180910390fd5b806000811215610c80576040805162461bcd60e51b815260206004820152600760248201526629a6aa9d27a7a160c91b604482015290519081900360640190fd5b60008282018183128015906136415750838112155b80613656575060008312801561365657508381125b6115ac5760405162461bcd60e51b815260040180806020018281038252602181526020018061475b6021913960400191505060405180910390fd5b60008082121561358e576040805162461bcd60e51b8152602060048201526007602482015266534d493a4e454760c81b604482015290519081900360640190fd5b60006136dc610f09565b11613720576040805162461bcd60e51b815260206004820152600f60248201526e4644543a5a45524f5f535550504c5960881b604482015290519081900360640190fd5b8061372a57611d6a565b613761613735610f09565b61374983600160801b63ffffffff61359216565b8161375057fe5b60065491900463ffffffff612b8616565b60065560408051828152905133917f26536799ace2c3dbe12e638ec3ade6b4173dcf1289be0a58d51a5003015649bd919081900360200190a260065460408051918252517f1f8d7705f31c3337a080803a8ad7e71946fb88d84738879be2bf402f97156e969181900360200190a150565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a082317f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561386a57600080fd5b505afa15801561387e573d6000803e3d6000fd5b505050506040513d602081101561389457600080fd5b5051905090565b6001600160a01b038116600090815260208590526040812054908484016138c257816138f8565b6138f86138eb8686016133d1876138df428863ffffffff61332a16565b9063ffffffff61359216565b839063ffffffff612b8616565b6001600160a01b038416600081815260208981526040918290208490558151848152915193945091927ff9b842c70d79466435b46540bb988aa5c998b3243bf91c36380ddb5887c0f0e4929181900390910190a2505050505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611ae7908590613ed7565b6139b88282613f88565b60006135086139d5611c348460095461359290919063ffffffff16565b6001600160a01b0385166000908152600a60205260409020549063ffffffff613d0416565b600f8054600d549182905560009161338a908263ffffffff613d0416565b6000613a22610f09565b11613a66576040805162461bcd60e51b815260206004820152600f60248201526e4644543a5a45524f5f535550504c5960881b604482015290519081900360640190fd5b80613a7057611d6a565b6000613aa9613a7d610f09565b613a9184600160801b63ffffffff61359216565b81613a9857fe5b60095491900463ffffffff612b8616565b600981905560408051848152905191925033917ff88156a8032a0d2c65df18fafaf84e0bea647b3d94a0f7fc6ab14c97dec2bf749181900360200190a26040805182815290517f240ce2b5ce9e9e5a70010c7f8034c233d89b7ce2d60f3a38d9bc3ca01a36f88c9181900360200190a15050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611605576040805162461bcd60e51b8152602060048201526009602482015268140e9393d517d1115360ba1b604482015290519081900360640190fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611020908490613ed7565b613be3838383613fd4565b6000613bfd611c348360095461359290919063ffffffff16565b6001600160a01b0385166000908152600a602052604081205491925090613c2a908363ffffffff61362c16565b6001600160a01b038087166000908152600a602052604080822084905591871681529081205491925090613c64908463ffffffff613d0416565b6001600160a01b038087166000908152600a602090815260409182902084905581518681529151939450918916927fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3929181900390910190a26040805182815290516001600160a01b038716917fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3919081900360200190a2505050505050565b6000818303818312801590613d195750838113155b80613d2e5750600083128015613d2e57508381135b6115ac5760405162461bcd60e51b81526004018080602001828103825260248152602001806148556024913960400191505060405180910390fd5b60006115ac83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614100565b613db58282614165565b6000613df7613dd2611c348460065461359290919063ffffffff16565b6001600160a01b0385166000908152600760205260409020549063ffffffff61362c16565b6001600160a01b0384166000818152600760209081526040918290208490558151848152915193945091927ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773929181900390910190a2505050565b6000613e5d3361201c565b336000908152600b602052604081205491925090613e81908363ffffffff612b8616565b336000818152600b60209081526040918290208490558151868152908101849052815193945091927f814eba35782909dbbaeefb8104073dfca45de43173f7077970c1584b3cf918b59281900390910190a25090565b6060613f2c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661426d9092919063ffffffff16565b80519091501561102057808060200190516020811015613f4b57600080fd5b50516110205760405162461bcd60e51b815260040180806020018281038252602a815260200180614879602a913960400191505060405180910390fd5b613f928282614284565b6000613df7613faf611c348460065461359290919063ffffffff16565b6001600160a01b0385166000908152600760205260409020549063ffffffff613d0416565b613fdf838383614380565b6000613ff9611c348360065461359290919063ffffffff16565b6001600160a01b03851660009081526007602052604081205491925090614026908363ffffffff61362c16565b6001600160a01b0380871660009081526007602052604080822084905591871681529081205491925090614060908463ffffffff613d0416565b6001600160a01b0380871660009081526007602090815260409182902084905581518681529151939450918916927ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773929181900390910190a26040805182815290516001600160a01b038716917ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773919081900360200190a2505050505050565b6000818361414f5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156131e25781810151838201526020016131ca565b50600083858161415b57fe5b0495945050505050565b6001600160a01b0382166141aa5760405162461bcd60e51b81526004018080602001828103825260218152602001806147eb6021913960400191505060405180910390fd5b6141b682600083611020565b6141f9816040518060600160405280602281526020016146f1602291396001600160a01b038516600090815260208190526040902054919063ffffffff61318e16565b6001600160a01b038316600090815260208190526040902055600254614225908263ffffffff61332a16565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b606061427c84846000856144e7565b949350505050565b6001600160a01b0382166142df576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6142eb60008383611020565b6002546142fe908263ffffffff612b8616565b6002556001600160a01b03821660009081526020819052604090205461432a908263ffffffff612b8616565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b0383166143c55760405162461bcd60e51b815260040180806020018281038252602581526020018061480c6025913960400191505060405180910390fd5b6001600160a01b03821661440a5760405162461bcd60e51b81526004018080602001828103825260238152602001806146ce6023913960400191505060405180910390fd5b614415838383611020565b61445881604051806060016040528060268152602001614735602691396001600160a01b038616600090815260208190526040902054919063ffffffff61318e16565b6001600160a01b03808516600090815260208190526040808220939093559084168152205461448d908263ffffffff612b8616565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6060824710156145285760405162461bcd60e51b815260040180806020018281038252602681526020018061477c6026913960400191505060405180910390fd5b61453185614643565b614582576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106145c15780518252601f1990920191602091820191016145a2565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614623576040519150601f19603f3d011682016040523d82523d6000602084013e614628565b606091505b5091509150614638828286614649565b979650505050505050565b3b151590565b606083156146585750816115ac565b8251156146685782518084602001fd5b60405162461bcd60e51b81526020600482018181528451602484015284518593919283926044019190850190808383600083156131e25781810151838201526020016131ca565b6040518060e00160405280600790602082028036833750919291505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63655369676e6564536166654d6174683a206164646974696f6e206f766572666c6f77416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220338ed6b58b0c477d8e804960099fbfd7403722cacff069fd1119edb300baf01664736f6c634300060b0033000000000000000000000000990d11977378d4610776e6646b2caae543ea4eda000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000030b705bfa64be9ae395bd9238efc63e9f5f8d1cc00000000000000000000000053a597a4730eb02095dd798b203dcc306348b8d6000000000000000000000000966528bb1c44f96b3aa8fbf411ee896116b068c900000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000001bc85dc2a89bb2000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000104d61706c6520506f6f6c20546f6b656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064d504c2d4c500000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103fb5760003560e01c806370a0823111610215578063a9059cbb11610125578063c771c390116100b8578063d82745c811610087578063d82745c814610bfa578063dd62ed3e14610c20578063ee947a7c14610c4e578063eff9884314610c56578063fec984e314610c5e576103fb565b8063c771c39014610b79578063c965b54814610b96578063cc0fef0214610bc4578063d7bd3c9114610bcc576103fb565b8063b69410de116100f4578063b69410de14610acf578063b6b55f2514610ad7578063c374682514610af4578063c59e395914610b53576103fb565b8063a9059cbb14610a4f578063ac64165514610a7b578063aed4966a14610a83578063af6d557114610aa9576103fb565b806384b76824116101a85780639759164a116101775780639759164a146109ec5780639f3c7325146109f4578063a33142f7146109fc578063a43baa3d14610a04578063a457c2d714610a23576103fb565b806384b76824146109885780638905fd4f146109905780639185192a146109b657806395d89b41146109e4576103fb565b806376687d3d116101e457806376687d3d1461093e5780637b99adb11461094657806380cd916d1461096357806380e7ce851461096b576103fb565b806370a08231146108da57806371073bac1461090057806373ef9a50146109085780637666f12514610910576103fb565b80632e1a7d4d1161031057806346c162de116102a357806351b42b001161027257806351b42b001461081c578063613384f214610824578063641ad8a91461084a5780636696779114610876578063681cb10a1461089c576103fb565b806346c162de146107de5780634bb278f3146107e65780634e97415f146107ee5780634f85221a14610814576103fb565b806340504ba0116102df57806340504ba01461074757806340bde09814610775578063410dbf7e1461079b578063443bb293146107b8576103fb565b80632e1a7d4d146106ee578063313ce5671461070b57806339509351146107135780634046af2b1461073f576103fb565b80631831ccf21161039357806323b872dd1161036257806323b872dd1461062857806324600fc31461065e57806324b92e8e1461066657806327f918561461068c5780632ac04ac8146106b8576103fb565b80631831ccf21461057a5780631aa37cec14610582578063209b2bca146105ba57806321c0b342146105c2576103fb565b80630d49b38c116103cf5780630d49b38c1461051957806313bf9e7e14610521578063174a5be41461055457806318160ddd14610572576103fb565b806241c52c14610400578063033b1cf01461043857806306fdde031461045c578063095ea7b3146104d9575b600080fd5b6104266004803603602081101561041657600080fd5b50356001600160a01b0316610c66565b60408051918252519081900360200190f35b610440610c85565b604080516001600160a01b039092168252519081900360200190f35b610464610ca9565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561049e578181015183820152602001610486565b50505050905090810190601f1680156104cb5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610505600480360360408110156104ef57600080fd5b506001600160a01b038135169060200135610d3f565b604080519115158252519081900360200190f35b610440610d5d565b610529610d81565b6040805195865260208601949094529115158484015260608401526080830152519081900360a00190f35b61055c610f04565b6040805160ff9092168252519081900360200190f35b610426610f09565b610505610f0f565b6105b86004803603606081101561059857600080fd5b506001600160a01b03813581169160208101359091169060400135610f18565b005b610440611025565b6105f0600480360360408110156105d857600080fd5b506001600160a01b0381358116916020013516611049565b604051808260e080838360005b838110156106155781810151838201526020016105fd565b5050505090500191505060405180910390f35b6105056004803603606081101561063e57600080fd5b506001600160a01b03813581169160208101359091169060400135611525565b6105b86115b3565b6104266004803603602081101561067c57600080fd5b50356001600160a01b0316611607565b6105b8600480360360408110156106a257600080fd5b506001600160a01b038135169060200135611619565b6105b8600480360360608110156106ce57600080fd5b506001600160a01b038135811691602081013590911690604001356117ba565b6105b86004803603602081101561070457600080fd5b5035611991565b61055c611aed565b6105056004803603604081101561072957600080fd5b506001600160a01b038135169060200135611af6565b610440611b4a565b6105b86004803603604081101561075d57600080fd5b506001600160a01b0381358116916020013516611b6e565b6104266004803603602081101561078b57600080fd5b50356001600160a01b0316611bef565b6105b8600480360360208110156107b157600080fd5b5035611c58565b610426600480360360208110156107ce57600080fd5b50356001600160a01b0316611d0d565b6105b8611d3f565b6105b8611d6d565b6104266004803603602081101561080457600080fd5b50356001600160a01b0316611e3b565b610505611e80565b6105b8611ea0565b6105056004803603602081101561083a57600080fd5b50356001600160a01b0316611ff9565b61085261200e565b6040518082600281111561086257fe5b60ff16815260200191505060405180910390f35b6104266004803603602081101561088c57600080fd5b50356001600160a01b031661201c565b610426600480360360808110156108b257600080fd5b506001600160a01b038135811691602081013582169160408201358116916060013516612042565b610426600480360360208110156108f057600080fd5b50356001600160a01b03166120ed565b610426612108565b6105b861210e565b6105b86004803603604081101561092657600080fd5b506001600160a01b03813516906020013515156121a4565b61042661220c565b6105b86004803603602081101561095c57600080fd5b5035612212565b61044061225d565b6105056004803603602081101561098157600080fd5b5035612281565b6105b86122d4565b6105b8600480360360208110156109a657600080fd5b50356001600160a01b0316612370565b6105b8600480360360408110156109cc57600080fd5b506001600160a01b0381351690602001351515612445565b6104646124ad565b61044061250e565b610426612532565b610426612538565b6105b860048036036020811015610a1a57600080fd5b5035151561253e565b61050560048036036040811015610a3957600080fd5b506001600160a01b03813516906020013561258d565b61050560048036036040811015610a6557600080fd5b506001600160a01b0381351690602001356125fb565b61042661260f565b61042660048036036020811015610a9957600080fd5b50356001600160a01b0316612615565b61042660048036036020811015610abf57600080fd5b50356001600160a01b0316612630565b610426612642565b6105b860048036036020811015610aed57600080fd5b5035612666565b610b3a600480360360a0811015610b0a57600080fd5b506001600160a01b03813581169160208101358216916040820135811691606081013590911690608001356127a0565b6040805192835260208301919091528051918290030190f35b61050560048036036020811015610b6957600080fd5b50356001600160a01b031661285d565b6105b860048036036020811015610b8f57600080fd5b5035612872565b61042660048036036040811015610bac57600080fd5b506001600160a01b03813581169160200135166128fa565b6105b8612917565b61044060048036036040811015610be257600080fd5b506001600160a01b0381358116916020013516612942565b61042660048036036020811015610c1057600080fd5b50356001600160a01b0316612968565b61042660048036036040811015610c3657600080fd5b506001600160a01b038135811691602001351661297a565b6104266129a5565b6104266129ab565b6104266129b1565b6001600160a01b0381166000908152600860205260409020545b919050565b7f000000000000000000000000d5deeb06859369e42cf1906408ed6cb249e0e00281565b60038054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610d355780601f10610d0a57610100808354040283529160200191610d35565b820191906000526020600020905b815481529060010190602001808311610d1857829003601f168201915b5050505050905090565b6000610d53610d4c6129b7565b84846129bb565b5060015b92915050565b7f0000000000000000000000002cd79f7f8b38b9c0d80ea6b230441841a31537ec81565b6000806000806000732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3063767f5038610dcc7f0000000000000000000000002cd79f7f8b38b9c0d80ea6b230441841a31537ec612aa7565b6040805160e084901b6001600160e01b03191681526001600160a01b0392831660048201527f00000000000000000000000030b705bfa64be9ae395bd9238efc63e9f5f8d1cc831660248201527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2831660448201527f000000000000000000000000990d11977378d4610776e6646b2caae543ea4eda831660648201527f000000000000000000000000d5deeb06859369e42cf1906408ed6cb249e0e00290921660848301525160a48083019260a0929190829003018186803b158015610eb257600080fd5b505af4158015610ec6573d6000803e3d6000fd5b505050506040513d60a0811015610edc57600080fd5b5080516020820151604083015160608401516080909401519299919850965091945092509050565b600181565b60025490565b60145460ff1681565b610f20612b14565b610f2a6001612b24565b601154610f3d908263ffffffff612b8616565b6011556040805163fbecb17160e01b8152601660048201526001600160a01b037f0000000000000000000000002cd79f7f8b38b9c0d80ea6b230441841a31537ec811660248301527f00000000000000000000000077fb4797db0c418967ba155dcf344aadeafcb2508116604483015280861660648301528416608482015260a481018390529051732c1c30fb8cc313ef3cfd2e2bbf2da88add902c309163fbecb1719160c4808301926000929190829003018186803b15801561100057600080fd5b505af4158015611014573d6000803e3d6000fd5b50505050611020612be0565b505050565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6110516146af565b611059612c70565b611061612d40565b6001600160a01b0380841660009081526016602090815260408083208685168452909152808220548151634e71d92d60e01b81529151931692634e71d92d9260048084019360e093929083900390910190829087803b1580156110c357600080fd5b505af11580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525060e08110156110fc57600080fd5b50601054604051633faa6c5d60e01b8152919250600091829182918291732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3091633faa6c5d9188917f00000000000000000000000000000000000000000000000000000000000003e89190600401808460e08083838c5b8381101561117e578181015183820152602001611166565b50505050905001838152602001828152602001935050505060806040518083038186803b1580156111ae57600080fd5b505af41580156111c2573d6000803e3d6000fd5b505050506040513d60808110156111d857600080fd5b50805160208201516040830151606090930151601154929750909550919350909150821161120e57601180548390039055611232565b601154611224908290840363ffffffff612b8616565b601180546000909155925090505b600c54611245908263ffffffff612b8616565b600c556112727f000000000000000000000000990d11977378d4610776e6646b2caae543ea4eda85612dcc565b61129c7f000000000000000000000000d5deeb06859369e42cf1906408ed6cb249e0e00284612dcc565b6112d57f00000000000000000000000077fb4797db0c418967ba155dcf344aadeafcb2506112d0848463ffffffff612b8616565b612dcc565b60c0850151156112f0576112f0878660066020020151612e06565b7f000000000000000000000000d5deeb06859369e42cf1906408ed6cb249e0e0026001600160a01b03166346c162de6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561134b57600080fd5b505af115801561135f573d6000803e3d6000fd5b5050505061136b611d3f565b611373612be0565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03167f000000000000000000000000d5deeb06859369e42cf1906408ed6cb249e0e0026001600160a01b03167f2047d1633ff7768462ae07d28cb16e484203bfd6d85ce832494270ebcd9081a27f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03166370a082317f000000000000000000000000d5deeb06859369e42cf1906408ed6cb249e0e0026040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561147e57600080fd5b505afa158015611492573d6000803e3d6000fd5b505050506040513d60208110156114a857600080fd5b505160408051918252519081900360200190a36060808601516040805184815260208101869052808201929092529181018590526080810186905290516001600160a01b038916917f21280d282ce6aa29c649fd1825373d7c77892fac3f1958fd98d5ca52dd82a197919081900360a00190a25050505092915050565b6000611532848484613010565b6115a88461153e6129b7565b6115a3856040518060600160405280602881526020016147c3602891396001600160a01b038a1660009081526001602052604081209061157c6129b7565b6001600160a01b03168152602081019190915260400160002054919063ffffffff61318e16565b6129bb565b5060015b9392505050565b6115bb612c70565b60006115c5613225565b9050806115d25750611605565b6115dc33826132aa565b6115e4612be0565b600c546115f7908263ffffffff61332a16565b600c5561160261336c565b50505b565b60156020526000908152604090205481565b336000908152601a602090815260408083206001600160a01b03861684529091528120549061164e828463ffffffff612b8616565b336000908152601b602052604081205491925090611672908563ffffffff612b8616565b9050732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3063297e7bf786868461169a336120ed565b6040518563ffffffff1660e01b815260040180856001600160a01b03166001600160a01b0316815260200184815260200183815260200182815260200194505050505060006040518083038186803b1580156116f557600080fd5b505af4158015611709573d6000803e3d6000fd5b5050336000818152601a602090815260408083206001600160a01b038c16808552908352818420899055848452601b835292819020879055805189815291820188905280519295509293507f847e03d69a7075471d42285f4ac63570c10f3012d8bf736d66de2eef17aac3e892908290030190a360408051828152905133917fe7f3fb4dacbff434e6d283d891f199c48b05b1629f610bd7ddc62353e162fb16919081900360200190a25050505050565b6001600160a01b0383166000908152601a60209081526040808320338452909152812054906117ef828463ffffffff61332a16565b60408051631b4c903160e01b81526001600160a01b03808916600483015287166024820152604481018690529051919250732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3091631b4c903191606480820192600092909190829003018186803b15801561185c57600080fd5b505af4158015611870573d6000803e3d6000fd5b505050506001600160a01b0385166000818152601a602090815260408083203384528252808320859055928252601b9052908120546118af908561332a565b6001600160a01b038088166000818152601b60209081526040918290208590558151898152915194955092891693919233927ffaa022ea2cd7f14157070896fabadafe96cc4d4714eef7ae6a992a5084493ed59281900390910190a46040805184815260208101849052815133926001600160a01b038a16927f847e03d69a7075471d42285f4ac63570c10f3012d8bf736d66de2eef17aac3e8929081900390910190a360408051828152905133917fe7f3fb4dacbff434e6d283d891f199c48b05b1629f610bd7ddc62353e162fb16919081900360200190a2505050505050565b611999612c70565b60006119a482613390565b90506000806119d27f0000000000000000000000002cd79f7f8b38b9c0d80ea6b230441841a31537ec612aa7565b6001600160a01b0316639f51290b6040518163ffffffff1660e01b8152600401604080518083038186803b158015611a0957600080fd5b505afa158015611a1d573d6000803e3d6000fd5b505050506040513d6040811015611a3357600080fd5b5080516020909101519092509050611a4b33846133dd565b3360009081526019602052604090205482014203811015611aac576040805162461bcd60e51b8152602060048201526016602482015275140e95d2551211149055d7d393d517d0531313d5d15160521b604482015290519081900360640190fd5b611ab633846134bc565b611abe6115b3565b611adf33611ada611acd613563565b879063ffffffff61332a16565b6132aa565b611ae7612be0565b50505050565b60055460ff1690565b6000610d53611b036129b7565b846115a38560016000611b146129b7565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff612b8616565b7f000000000000000000000000990d11977378d4610776e6646b2caae543ea4eda81565b611b76612b14565b6001600160a01b038083166000908152601660209081526040808320858516845290915280822054815163175f832960e01b8152915193169263175f83299260048084019391929182900301818387803b158015611bd357600080fd5b505af1158015611be7573d6000803e3d6000fd5b505050505050565b6001600160a01b0381166000908152600a6020526040812054600160801b90611c4a90611c4590611c39611c34611c25886120ed565b6009549063ffffffff61359216565b6135eb565b9063ffffffff61362c16565b613691565b81611c5157fe5b0492915050565b611c60612b14565b612710611c93827f00000000000000000000000000000000000000000000000000000000000003e863ffffffff612b8616565b1115611cd2576040805162461bcd60e51b8152602060048201526009602482015268503a4241445f46454560b81b604482015290519081900360640190fd5b60108190556040805182815290517f9408bb8c08d29b335e36090045074610352365476d9df02e203c25db4fcd67c09181900360200190a150565b6001600160a01b038116600090815260086020526040812054610d5790611d3384611e3b565b9063ffffffff61332a16565b6000611d4961336c565b905060008113611d595750611605565b611d6a611d6582613691565b6136d2565b50565b611d75612b14565b611d7f6000612b24565b6000611d89610d81565b50509250505080611dd1576040805162461bcd60e51b815260206004820152600d60248201526c503a494e5355465f5354414b4560981b604482015290519081900360640190fd5b601480546001919061ff0019166101008302179055506014546040517f24b0afb747a8213aea796b9518bfa667de187b83390eda7cc93b8e57f80fcd1a91610100900460ff169080826002811115611e2557fe5b60ff16815260200191505060405180910390a150565b6001600160a01b038116600090815260076020526040812054600160801b90611c4a90611c4590611c39611c34611e71886120ed565b6006549063ffffffff61359216565b60006001601454610100900460ff166002811115611e9a57fe5b14905090565b611ea8612b14565b611eb26001612b24565b732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3063abbedb40611ef57f0000000000000000000000002cd79f7f8b38b9c0d80ea6b230441841a31537ec612aa7565b6011547f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26040518463ffffffff1660e01b815260040180846001600160a01b03166001600160a01b03168152602001838152602001826001600160a01b03166001600160a01b03168152602001935050505060006040518083038186803b158015611f7f57600080fd5b505af4158015611f93573d6000803e3d6000fd5b50506014805461ff00191661020017908190556040517f24b0afb747a8213aea796b9518bfa667de187b83390eda7cc93b8e57f80fcd1a935061010090910460ff16915080826002811115611fe457fe5b60ff16815260200191505060405180910390a1565b60176020526000908152604090205460ff1681565b601454610100900460ff1681565b6001600160a01b0381166000908152600b6020526040812054610d5790611d3384611bef565b6040805163340e588560e11b81526001600160a01b03808716600483015280861660248301528085166044830152831660648201529051600091732c1c30fb8cc313ef3cfd2e2bbf2da88add902c309163681cb10a91608480820192602092909190829003018186803b1580156120b857600080fd5b505af41580156120cc573d6000803e3d6000fd5b505050506040513d60208110156120e257600080fd5b505195945050505050565b6001600160a01b031660009081526020819052604090205490565b600c5481565b6000612119336120ed565b1415612159576040805162461bcd60e51b815260206004820152600a602482015269140e96915493d7d0905360b21b604482015290519081900360640190fd5b336000818152601960209081526040918290204290819055825190815291517f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d659281900390910190a2565b6121ac612b14565b6001600160a01b038216600081815260186020908152604091829020805460ff1916851515908117909155825190815291517fdf56132520665b33cd5731c5cfbacd8bee82524e67df563bb25b2be304f91d449281900390910190a25050565b60125481565b61221a612c70565b612222612d40565b60128190556040805182815290517f3ff20538222f568f27ff436c0c49dfd3e48d5b8f86533a3f759dc1c7089775ab9181900360200190a150565b7f00000000000000000000000030b705bfa64be9ae395bd9238efc63e9f5f8d1cc81565b60145460009060ff16806122a457503360009081526018602052604090205460ff165b8015610d5757506012546122cc836122c06011546122c06137d2565b9063ffffffff612b8616565b111592915050565b33600090815260196020526040902054612329576040805162461bcd60e51b8152602060048201526011602482015270503a4e4f545f5749544844524157494e4760781b604482015290519081900360640190fd5b3360008181526019602090815260408083208390558051928352517f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d659281900390910190a2565b732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3063a89d5ddb827f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26123d57f0000000000000000000000002cd79f7f8b38b9c0d80ea6b230441841a31537ec612aa7565b604080516001600160e01b031960e087901b1681526001600160a01b03948516600482015292841660248401529216604482015290516064808301926000929190829003018186803b15801561242a57600080fd5b505af415801561243e573d6000803e3d6000fd5b5050505050565b61244d612b14565b6001600160a01b038216600081815260176020908152604091829020805460ff1916851515908117909155825190815291517f353578bbc0ab907b7018b0f7b50b5f822d31dc9fcf4c16fffa780e109ca7c9309281900390910190a25050565b60048054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610d355780601f10610d0a57610100808354040283529160200191610d35565b7f00000000000000000000000077fb4797db0c418967ba155dcf344aadeafcb25081565b600e5481565b600d5481565b612546612b14565b6014805482151560ff19909116811790915560408051918252517feeba6fd794e30165023f7e3d017e92901622076a95d36e45906955e025ff4fe79181900360200190a150565b6000610d5361259a6129b7565b846115a3856040518060600160405280602581526020016148a360259139600160006125c46129b7565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff61318e16565b6000610d536126086129b7565b8484613010565b60115481565b6001600160a01b03166000908152600b602052604090205490565b601b6020526000908152604090205481565b7f00000000000000000000000000000000000000000000000000000000000003e881565b61266e612c70565b6126786001612b24565b61268181612281565b6126c6576040805162461bcd60e51b8152602060048201526011602482015270140e91115417d393d517d0531313d5d151607a1b604482015290519081900360640190fd5b3360009081526019602052604081208190556126e182613390565b90506126f860156126f1336120ed565b833361389b565b6127536001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216337f00000000000000000000000077fb4797db0c418967ba155dcf344aadeafcb2508563ffffffff61395416565b61275d33826139ae565b612765612be0565b6040805160008152905133917f8a05f911d8ab7fc50fec37ef4ba7f9bfcb1a3c191c81dcd824ad0946c4e20d65919081900360200190a25050565b6040805163c374682560e01b81526001600160a01b03808816600483015280871660248301528086166044830152841660648201526084810183905281516000928392732c1c30fb8cc313ef3cfd2e2bbf2da88add902c309263c37468259260a480840193919291829003018186803b15801561281c57600080fd5b505af4158015612830573d6000803e3d6000fd5b505050506040513d604081101561284657600080fd5b508051602090910151909890975095505050505050565b60186020526000908152604090205460ff1681565b61287a612b14565b6013548111156128bf576040805162461bcd60e51b815260206004820152600b60248201526a503a4241445f56414c554560a81b604482015290519081900360640190fd5b60138190556040805182815290517f3094b4ce0463766c3cd81ed2ae2451610dcac39a1061fa023ca9d3d4df959f759181900360200190a150565b601a60209081526000928352604080842090915290825290205481565b60006129216139fa565b9050600081136129315750611605565b611d6a61293d82613691565b613a18565b60166020908152600092835260408084209091529082529020546001600160a01b031681565b60196020526000908152604090205481565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60135481565b60105481565b600f5481565b3390565b6001600160a01b038316612a005760405162461bcd60e51b81526004018080602001828103825260248152602001806148316024913960400191505060405180910390fd5b6001600160a01b038216612a455760405162461bcd60e51b81526004018080602001828103825260228152602001806147136022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6000816001600160a01b031663c31245256040518163ffffffff1660e01b815260040160206040518083038186803b158015612ae257600080fd5b505afa158015612af6573d6000803e3d6000fd5b505050506040513d6020811015612b0c57600080fd5b505192915050565b612b1c613b1d565b611605612c70565b806002811115612b3057fe5b601454610100900460ff166002811115612b4657fe5b14611d6a576040805162461bcd60e51b815260206004820152600b60248201526a503a4241445f535441544560a81b604482015290519081900360640190fd5b6000828201838110156115ac576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03167f00000000000000000000000077fb4797db0c418967ba155dcf344aadeafcb2506001600160a01b03167f2047d1633ff7768462ae07d28cb16e484203bfd6d85ce832494270ebcd9081a2612c5d6137d2565b60408051918252519081900360200190a3565b612c997f0000000000000000000000002cd79f7f8b38b9c0d80ea6b230441841a31537ec612aa7565b6001600160a01b031663425fad586040518163ffffffff1660e01b815260040160206040518083038186803b158015612cd157600080fd5b505afa158015612ce5573d6000803e3d6000fd5b505050506040513d6020811015612cfb57600080fd5b505115611605576040805162461bcd60e51b815260206004820152600e60248201526d140e941493d513d7d4105554d15160921b604482015290519081900360640190fd5b336001600160a01b037f000000000000000000000000990d11977378d4610776e6646b2caae543ea4eda161480612d8657503360009081526017602052604090205460ff165b611605576040805162461bcd60e51b8152602060048201526012602482015271281d2727aa2fa222a62fa7a92fa0a226a4a760711b604482015290519081900360640190fd5b6116026001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216838363ffffffff613b8616565b6040805162715b0960e41b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2811660048301527f000000000000000000000000d5deeb06859369e42cf1906408ed6cb249e0e002811660248301527f00000000000000000000000030b705bfa64be9ae395bd9238efc63e9f5f8d1cc16604482015260648101839052905160009182918291732c1c30fb8cc313ef3cfd2e2bbf2da88add902c3091630715b09091608480820192606092909190829003018186803b158015612ede57600080fd5b505af4158015612ef2573d6000803e3d6000fd5b505050506040513d6060811015612f0857600080fd5b5080516020820151604090920151909450909250905080841115612f4657600d54612f3b9082860363ffffffff612b8616565b600d55612f46612917565b612fa06001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2167f00000000000000000000000077fb4797db0c418967ba155dcf344aadeafcb2508363ffffffff613b8616565b601154612fb3908563ffffffff61332a16565b60115560408051858152602081018590528082018490526060810183905290516001600160a01b038716917fd393d18014c1898545668c52621bced9493753be5b8138f2539542ca606732eb919081900360800190a25050505050565b613018612c70565b6000806130447f0000000000000000000000002cd79f7f8b38b9c0d80ea6b230441841a31537ec612aa7565b6001600160a01b0316639f51290b6040518163ffffffff1660e01b8152600401604080518083038186803b15801561307b57600080fd5b505afa15801561308f573d6000803e3d6000fd5b505050506040513d60408110156130a557600080fd5b50805160209091015190925090506130bd85846133dd565b6001600160a01b038416600090815260196020526040902054820181014211613120576040805162461bcd60e51b815260206004820152601060248201526f140e9513d7d393d517d0531313d5d15160821b604482015290519081900360640190fd5b600061312b8661201c565b1461316e576040805162461bcd60e51b815260206004820152600e60248201526d503a5245434f475f4c4f5353455360901b604482015290519081900360640190fd5b613183601561317c866120ed565b858761389b565b61243e858585613bd8565b6000818484111561321d5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156131e25781810151838201526020016131ca565b50505050905090810190601f16801561320f5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600061323033611d0d565b3360009081526008602052604081205491925090613254908363ffffffff612b8616565b336000818152600860209081526040918290208490558151868152908101849052815193945091927ffbc3a599b784fe88772fc5abcc07223f64ca0b13acc341f4fb1e46bef0510eb49281900390910190a25090565b7f00000000000000000000000077fb4797db0c418967ba155dcf344aadeafcb2506001600160a01b031663a9059cbb83836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015611bd357600080fd5b60006115ac83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525061318e565b600e8054600c549182905560009161338a908263ffffffff613d0416565b91505090565b6000610d577f0000000000000000000000000000000000000000000000000000000000000012600a0a6133d184670de0b6b3a764000063ffffffff61359216565b9063ffffffff613d6916565b6013546001600160a01b038316600090815260156020526040902054429161340b919063ffffffff612b8616565b111561344f576040805162461bcd60e51b815260206004820152600e60248201526d140e9195539114d7d313d0d2d15160921b604482015290519081900360640190fd5b6001600160a01b0382166000908152601b602052604090205461347582611d33856120ed565b1015611602576040805162461bcd60e51b8152602060048201526011602482015270140e925394d55197d514905394d7d09053607a1b604482015290519081900360640190fd5b6134c68282613dab565b60006135086134e3611c348460095461359290919063ffffffff16565b6001600160a01b0385166000908152600a60205260409020549063ffffffff61362c16565b6001600160a01b0384166000818152600a60209081526040918290208490558151848152915193945091927fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3929181900390910190a2505050565b600061356d613e52565b600d54909150613583908263ffffffff61332a16565b600d5561358e6139fa565b5090565b6000826135a157506000610d57565b828202828482816135ae57fe5b04146115ac5760405162461bcd60e51b81526004018080602001828103825260218152602001806147a26021913960400191505060405180910390fd5b806000811215610c80576040805162461bcd60e51b815260206004820152600760248201526629a6aa9d27a7a160c91b604482015290519081900360640190fd5b60008282018183128015906136415750838112155b80613656575060008312801561365657508381125b6115ac5760405162461bcd60e51b815260040180806020018281038252602181526020018061475b6021913960400191505060405180910390fd5b60008082121561358e576040805162461bcd60e51b8152602060048201526007602482015266534d493a4e454760c81b604482015290519081900360640190fd5b60006136dc610f09565b11613720576040805162461bcd60e51b815260206004820152600f60248201526e4644543a5a45524f5f535550504c5960881b604482015290519081900360640190fd5b8061372a57611d6a565b613761613735610f09565b61374983600160801b63ffffffff61359216565b8161375057fe5b60065491900463ffffffff612b8616565b60065560408051828152905133917f26536799ace2c3dbe12e638ec3ade6b4173dcf1289be0a58d51a5003015649bd919081900360200190a260065460408051918252517f1f8d7705f31c3337a080803a8ad7e71946fb88d84738879be2bf402f97156e969181900360200190a150565b60007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b03166370a082317f00000000000000000000000077fb4797db0c418967ba155dcf344aadeafcb2506040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561386a57600080fd5b505afa15801561387e573d6000803e3d6000fd5b505050506040513d602081101561389457600080fd5b5051905090565b6001600160a01b038116600090815260208590526040812054908484016138c257816138f8565b6138f86138eb8686016133d1876138df428863ffffffff61332a16565b9063ffffffff61359216565b839063ffffffff612b8616565b6001600160a01b038416600081815260208981526040918290208490558151848152915193945091927ff9b842c70d79466435b46540bb988aa5c998b3243bf91c36380ddb5887c0f0e4929181900390910190a2505050505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611ae7908590613ed7565b6139b88282613f88565b60006135086139d5611c348460095461359290919063ffffffff16565b6001600160a01b0385166000908152600a60205260409020549063ffffffff613d0416565b600f8054600d549182905560009161338a908263ffffffff613d0416565b6000613a22610f09565b11613a66576040805162461bcd60e51b815260206004820152600f60248201526e4644543a5a45524f5f535550504c5960881b604482015290519081900360640190fd5b80613a7057611d6a565b6000613aa9613a7d610f09565b613a9184600160801b63ffffffff61359216565b81613a9857fe5b60095491900463ffffffff612b8616565b600981905560408051848152905191925033917ff88156a8032a0d2c65df18fafaf84e0bea647b3d94a0f7fc6ab14c97dec2bf749181900360200190a26040805182815290517f240ce2b5ce9e9e5a70010c7f8034c233d89b7ce2d60f3a38d9bc3ca01a36f88c9181900360200190a15050565b336001600160a01b037f000000000000000000000000990d11977378d4610776e6646b2caae543ea4eda1614611605576040805162461bcd60e51b8152602060048201526009602482015268140e9393d517d1115360ba1b604482015290519081900360640190fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611020908490613ed7565b613be3838383613fd4565b6000613bfd611c348360095461359290919063ffffffff16565b6001600160a01b0385166000908152600a602052604081205491925090613c2a908363ffffffff61362c16565b6001600160a01b038087166000908152600a602052604080822084905591871681529081205491925090613c64908463ffffffff613d0416565b6001600160a01b038087166000908152600a602090815260409182902084905581518681529151939450918916927fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3929181900390910190a26040805182815290516001600160a01b038716917fb464de3159e090617503d0166bff9ffeecdefd42cd9dbb49f918df95a80fdea3919081900360200190a2505050505050565b6000818303818312801590613d195750838113155b80613d2e5750600083128015613d2e57508381135b6115ac5760405162461bcd60e51b81526004018080602001828103825260248152602001806148556024913960400191505060405180910390fd5b60006115ac83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250614100565b613db58282614165565b6000613df7613dd2611c348460065461359290919063ffffffff16565b6001600160a01b0385166000908152600760205260409020549063ffffffff61362c16565b6001600160a01b0384166000818152600760209081526040918290208490558151848152915193945091927ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773929181900390910190a2505050565b6000613e5d3361201c565b336000908152600b602052604081205491925090613e81908363ffffffff612b8616565b336000818152600b60209081526040918290208490558151868152908101849052815193945091927f814eba35782909dbbaeefb8104073dfca45de43173f7077970c1584b3cf918b59281900390910190a25090565b6060613f2c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661426d9092919063ffffffff16565b80519091501561102057808060200190516020811015613f4b57600080fd5b50516110205760405162461bcd60e51b815260040180806020018281038252602a815260200180614879602a913960400191505060405180910390fd5b613f928282614284565b6000613df7613faf611c348460065461359290919063ffffffff16565b6001600160a01b0385166000908152600760205260409020549063ffffffff613d0416565b613fdf838383614380565b6000613ff9611c348360065461359290919063ffffffff16565b6001600160a01b03851660009081526007602052604081205491925090614026908363ffffffff61362c16565b6001600160a01b0380871660009081526007602052604080822084905591871681529081205491925090614060908463ffffffff613d0416565b6001600160a01b0380871660009081526007602090815260409182902084905581518681529151939450918916927ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773929181900390910190a26040805182815290516001600160a01b038716917ff694bebd33ada288ae2f4485315db76739e2d5501daf315e71c9d8f841aa7773919081900360200190a2505050505050565b6000818361414f5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156131e25781810151838201526020016131ca565b50600083858161415b57fe5b0495945050505050565b6001600160a01b0382166141aa5760405162461bcd60e51b81526004018080602001828103825260218152602001806147eb6021913960400191505060405180910390fd5b6141b682600083611020565b6141f9816040518060600160405280602281526020016146f1602291396001600160a01b038516600090815260208190526040902054919063ffffffff61318e16565b6001600160a01b038316600090815260208190526040902055600254614225908263ffffffff61332a16565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b606061427c84846000856144e7565b949350505050565b6001600160a01b0382166142df576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6142eb60008383611020565b6002546142fe908263ffffffff612b8616565b6002556001600160a01b03821660009081526020819052604090205461432a908263ffffffff612b8616565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b0383166143c55760405162461bcd60e51b815260040180806020018281038252602581526020018061480c6025913960400191505060405180910390fd5b6001600160a01b03821661440a5760405162461bcd60e51b81526004018080602001828103825260238152602001806146ce6023913960400191505060405180910390fd5b614415838383611020565b61445881604051806060016040528060268152602001614735602691396001600160a01b038616600090815260208190526040902054919063ffffffff61318e16565b6001600160a01b03808516600090815260208190526040808220939093559084168152205461448d908263ffffffff612b8616565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6060824710156145285760405162461bcd60e51b815260040180806020018281038252602681526020018061477c6026913960400191505060405180910390fd5b61453185614643565b614582576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106145c15780518252601f1990920191602091820191016145a2565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614623576040519150601f19603f3d011682016040523d82523d6000602084013e614628565b606091505b5091509150614638828286614649565b979650505050505050565b3b151590565b606083156146585750816115ac565b8251156146685782518084602001fd5b60405162461bcd60e51b81526020600482018181528451602484015284518593919283926044019190850190808383600083156131e25781810151838201526020016131ca565b6040518060e00160405280600790602082028036833750919291505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e63655369676e6564536166654d6174683a206164646974696f6e206f766572666c6f77416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220338ed6b58b0c477d8e804960099fbfd7403722cacff069fd1119edb300baf01664736f6c634300060b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000990d11977378d4610776e6646b2caae543ea4eda000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000030b705bfa64be9ae395bd9238efc63e9f5f8d1cc00000000000000000000000053a597a4730eb02095dd798b203dcc306348b8d6000000000000000000000000966528bb1c44f96b3aa8fbf411ee896116b068c900000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000001bc85dc2a89bb2000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000104d61706c6520506f6f6c20546f6b656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064d504c2d4c500000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _poolDelegate (address): 0x990d11977378D4610776e6646b2cAAe543Ea4EDA
Arg [1] : _liquidityAsset (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : _stakeAsset (address): 0x30b705BfA64Be9AE395bD9238EfC63E9f5F8d1Cc
Arg [3] : _slFactory (address): 0x53a597A4730Eb02095dD798B203Dcc306348B8d6
Arg [4] : _llFactory (address): 0x966528BB1C44f96b3AA8Fbf411ee896116b068C9
Arg [5] : _stakingFee (uint256): 1000
Arg [6] : _delegateFee (uint256): 1000
Arg [7] : _liquidityCap (uint256): 8200000000000000000000
Arg [8] : name (string): Maple Pool Token
Arg [9] : symbol (string): MPL-LP
-----Encoded View---------------
14 Constructor Arguments found :
Arg [0] : 000000000000000000000000990d11977378d4610776e6646b2caae543ea4eda
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 00000000000000000000000030b705bfa64be9ae395bd9238efc63e9f5f8d1cc
Arg [3] : 00000000000000000000000053a597a4730eb02095dd798b203dcc306348b8d6
Arg [4] : 000000000000000000000000966528bb1c44f96b3aa8fbf411ee896116b068c9
Arg [5] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [6] : 00000000000000000000000000000000000000000000000000000000000003e8
Arg [7] : 0000000000000000000000000000000000000000000001bc85dc2a89bb200000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [11] : 4d61706c6520506f6f6c20546f6b656e00000000000000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [13] : 4d504c2d4c500000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.