Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
CauldronV4
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED // Cauldron // ( ( ( // )\ ) ( )\ )\ ) ( // (((_) ( /( ))\ ((_)(()/( )( ( ( // )\___ )(_)) /((_) _ ((_))(()\ )\ )\ ) // ((/ __|((_)_ (_))( | | _| | ((_) ((_) _(_/( // | (__ / _` || || || |/ _` | | '_|/ _ \| ' \)) // \___|\__,_| \_,_||_|\__,_| |_| \___/|_||_| // Copyright (c) 2021 BoringCrypto - All rights reserved // Twitter: @Boring_Crypto // Special thanks to: // @0xKeno - for all his invaluable contributions // @burger_crypto - for the idea of trying to let the LPs benefit from liquidations pragma solidity >=0.8.0; import "BoringSolidity/BoringOwnable.sol"; import "BoringSolidity/ERC20.sol"; import "BoringSolidity/interfaces/IMasterContract.sol"; import "BoringSolidity/libraries/BoringRebase.sol"; import "BoringSolidity/libraries/BoringERC20.sol"; import "libraries/compat/BoringMath.sol"; import "interfaces/IOracle.sol"; import "interfaces/ISwapperV2.sol"; import "interfaces/IBentoBoxV1.sol"; import "interfaces/IBentoBoxOwner.sol"; // solhint-disable avoid-low-level-calls // solhint-disable no-inline-assembly /// @title Cauldron /// @dev This contract allows contract calls to any contract (except BentoBox) /// from arbitrary callers thus, don't trust calls from this contract in any circumstances. contract CauldronV4 is BoringOwnable, IMasterContract { using BoringMath for uint256; using BoringMath128 for uint128; using RebaseLibrary for Rebase; using BoringERC20 for IERC20; event LogExchangeRate(uint256 rate); event LogAccrue(uint128 accruedAmount); event LogAddCollateral(address indexed from, address indexed to, uint256 share); event LogRemoveCollateral(address indexed from, address indexed to, uint256 share); event LogBorrow(address indexed from, address indexed to, uint256 amount, uint256 part); event LogRepay(address indexed from, address indexed to, uint256 amount, uint256 part); event LogFeeTo(address indexed newFeeTo); event LogWithdrawFees(address indexed feeTo, uint256 feesEarnedFraction); event LogInterestChange(uint64 oldInterestRate, uint64 newInterestRate); event LogChangeBorrowLimit(uint128 newLimit, uint128 perAddressPart); event LogChangeBlacklistedCallee(address indexed account, bool blacklisted); event LogRepayForAll(uint256 amount, uint128 previousElastic, uint128 newElastic); event LogLiquidation( address indexed from, address indexed user, address indexed to, uint256 collateralShare, uint256 borrowAmount, uint256 borrowPart ); // Immutables (for MasterContract and all clones) IBentoBoxV1 public immutable bentoBox; CauldronV4 public immutable masterContract; IERC20 public immutable magicInternetMoney; // MasterContract variables address public feeTo; // Per clone variables // Clone init settings IERC20 public collateral; IOracle public oracle; bytes public oracleData; struct BorrowCap { uint128 total; uint128 borrowPartPerAddress; } BorrowCap public borrowLimit; // Total amounts uint256 public totalCollateralShare; // Total collateral supplied Rebase public totalBorrow; // elastic = Total token amount to be repayed by borrowers, base = Total parts of the debt held by borrowers // User balances mapping(address => uint256) public userCollateralShare; mapping(address => uint256) public userBorrowPart; // Callee restrictions mapping(address => bool) public blacklistedCallees; /// @notice Exchange and interest rate tracking. /// This is 'cached' here because calls to Oracles can be very expensive. uint256 public exchangeRate; struct AccrueInfo { uint64 lastAccrued; uint128 feesEarned; uint64 INTEREST_PER_SECOND; } AccrueInfo public accrueInfo; uint64 private constant ONE_PERCENT_RATE = 317097920; /// @notice tracking of last interest update uint256 private lastInterestUpdate; // Settings uint256 public COLLATERIZATION_RATE; uint256 private constant COLLATERIZATION_RATE_PRECISION = 1e5; // Must be less than EXCHANGE_RATE_PRECISION (due to optimization in math) uint256 private constant EXCHANGE_RATE_PRECISION = 1e18; uint256 public LIQUIDATION_MULTIPLIER; uint256 private constant LIQUIDATION_MULTIPLIER_PRECISION = 1e5; uint256 public BORROW_OPENING_FEE; uint256 private constant BORROW_OPENING_FEE_PRECISION = 1e5; uint256 private constant DISTRIBUTION_PART = 10; uint256 private constant DISTRIBUTION_PRECISION = 100; modifier onlyMasterContractOwner() { require(msg.sender == masterContract.owner(), "Caller is not the owner"); _; } /// @notice The constructor is only used for the initial master contract. Subsequent clones are initialised via `init`. constructor(IBentoBoxV1 bentoBox_, IERC20 magicInternetMoney_) { bentoBox = bentoBox_; magicInternetMoney = magicInternetMoney_; masterContract = this; } /// @notice Serves as the constructor for clones, as clones can't have a regular constructor /// @dev `data` is abi encoded in the format: (IERC20 collateral, IERC20 asset, IOracle oracle, bytes oracleData) function init(bytes calldata data) public payable override { require(address(collateral) == address(0), "Cauldron: already initialized"); (collateral, oracle, oracleData, accrueInfo.INTEREST_PER_SECOND, LIQUIDATION_MULTIPLIER, COLLATERIZATION_RATE, BORROW_OPENING_FEE) = abi.decode(data, (IERC20, IOracle, bytes, uint64, uint256, uint256, uint256)); borrowLimit = BorrowCap(type(uint128).max, type(uint128).max); require(address(collateral) != address(0), "Cauldron: bad pair"); magicInternetMoney.approve(address(bentoBox), type(uint256).max); (, exchangeRate) = oracle.get(oracleData); blacklistedCallees[address(bentoBox)] = true; blacklistedCallees[address(this)] = true; blacklistedCallees[BoringOwnable(address(bentoBox)).owner()] = true; } /// @notice Accrues the interest on the borrowed tokens and handles the accumulation of fees. function accrue() public { AccrueInfo memory _accrueInfo = accrueInfo; // Number of seconds since accrue was called uint256 elapsedTime = block.timestamp - _accrueInfo.lastAccrued; if (elapsedTime == 0) { return; } _accrueInfo.lastAccrued = uint64(block.timestamp); Rebase memory _totalBorrow = totalBorrow; if (_totalBorrow.base == 0) { accrueInfo = _accrueInfo; return; } // Accrue interest uint128 extraAmount = (uint256(_totalBorrow.elastic).mul(_accrueInfo.INTEREST_PER_SECOND).mul(elapsedTime) / 1e18).to128(); _totalBorrow.elastic = _totalBorrow.elastic.add(extraAmount); _accrueInfo.feesEarned = _accrueInfo.feesEarned.add(extraAmount); totalBorrow = _totalBorrow; accrueInfo = _accrueInfo; emit LogAccrue(extraAmount); } /// @notice Concrete implementation of `isSolvent`. Includes a third parameter to allow caching `exchangeRate`. /// @param _exchangeRate The exchange rate. Used to cache the `exchangeRate` between calls. function _isSolvent(address user, uint256 _exchangeRate) internal view returns (bool) { // accrue must have already been called! uint256 borrowPart = userBorrowPart[user]; if (borrowPart == 0) return true; uint256 collateralShare = userCollateralShare[user]; if (collateralShare == 0) return false; Rebase memory _totalBorrow = totalBorrow; return bentoBox.toAmount( collateral, collateralShare.mul(EXCHANGE_RATE_PRECISION / COLLATERIZATION_RATE_PRECISION).mul(COLLATERIZATION_RATE), false ) >= // Moved exchangeRate here instead of dividing the other side to preserve more precision borrowPart.mul(_totalBorrow.elastic).mul(_exchangeRate) / _totalBorrow.base; } /// @dev Checks if the user is solvent in the closed liquidation case at the end of the function body. modifier solvent() { _; (, uint256 _exchangeRate) = updateExchangeRate(); require(_isSolvent(msg.sender, _exchangeRate), "Cauldron: user insolvent"); } /// @notice Gets the exchange rate. I.e how much collateral to buy 1e18 asset. /// This function is supposed to be invoked if needed because Oracle queries can be expensive. /// @return updated True if `exchangeRate` was updated. /// @return rate The new exchange rate. function updateExchangeRate() public returns (bool updated, uint256 rate) { (updated, rate) = oracle.get(oracleData); if (updated) { exchangeRate = rate; emit LogExchangeRate(rate); } else { // Return the old rate if fetching wasn't successful rate = exchangeRate; } } /// @dev Helper function to move tokens. /// @param token The ERC-20 token. /// @param share The amount in shares to add. /// @param total Grand total amount to deduct from this contract's balance. Only applicable if `skim` is True. /// Only used for accounting checks. /// @param skim If True, only does a balance check on this contract. /// False if tokens from msg.sender in `bentoBox` should be transferred. function _addTokens( IERC20 token, uint256 share, uint256 total, bool skim ) internal { if (skim) { require(share <= bentoBox.balanceOf(token, address(this)).sub(total), "Cauldron: Skim too much"); } else { bentoBox.transfer(token, msg.sender, address(this), share); } } /// @notice Adds `collateral` from msg.sender to the account `to`. /// @param to The receiver of the tokens. /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.x /// False if tokens from msg.sender in `bentoBox` should be transferred. /// @param share The amount of shares to add for `to`. function addCollateral( address to, bool skim, uint256 share ) public { userCollateralShare[to] = userCollateralShare[to].add(share); uint256 oldTotalCollateralShare = totalCollateralShare; totalCollateralShare = oldTotalCollateralShare.add(share); _addTokens(collateral, share, oldTotalCollateralShare, skim); emit LogAddCollateral(skim ? address(bentoBox) : msg.sender, to, share); } /// @dev Concrete implementation of `removeCollateral`. function _removeCollateral(address to, uint256 share) internal { userCollateralShare[msg.sender] = userCollateralShare[msg.sender].sub(share); totalCollateralShare = totalCollateralShare.sub(share); emit LogRemoveCollateral(msg.sender, to, share); bentoBox.transfer(collateral, address(this), to, share); } /// @notice Removes `share` amount of collateral and transfers it to `to`. /// @param to The receiver of the shares. /// @param share Amount of shares to remove. function removeCollateral(address to, uint256 share) public solvent { // accrue must be called because we check solvency accrue(); _removeCollateral(to, share); } /// @dev Concrete implementation of `borrow`. function _borrow(address to, uint256 amount) internal returns (uint256 part, uint256 share) { uint256 feeAmount = amount.mul(BORROW_OPENING_FEE) / BORROW_OPENING_FEE_PRECISION; // A flat % fee is charged for any borrow (totalBorrow, part) = totalBorrow.add(amount.add(feeAmount), true); BorrowCap memory cap = borrowLimit; require(totalBorrow.elastic <= cap.total, "Borrow Limit reached"); accrueInfo.feesEarned = accrueInfo.feesEarned.add(uint128(feeAmount)); uint256 newBorrowPart = userBorrowPart[msg.sender].add(part); require(newBorrowPart <= cap.borrowPartPerAddress, "Borrow Limit reached"); userBorrowPart[msg.sender] = newBorrowPart; // As long as there are tokens on this contract you can 'mint'... this enables limiting borrows share = bentoBox.toShare(magicInternetMoney, amount, false); bentoBox.transfer(magicInternetMoney, address(this), to, share); emit LogBorrow(msg.sender, to, amount.add(feeAmount), part); } /// @notice Sender borrows `amount` and transfers it to `to`. /// @return part Total part of the debt held by borrowers. /// @return share Total amount in shares borrowed. function borrow(address to, uint256 amount) public solvent returns (uint256 part, uint256 share) { accrue(); (part, share) = _borrow(to, amount); } /// @dev Concrete implementation of `repay`. function _repay( address to, bool skim, uint256 part ) internal returns (uint256 amount) { (totalBorrow, amount) = totalBorrow.sub(part, true); userBorrowPart[to] = userBorrowPart[to].sub(part); uint256 share = bentoBox.toShare(magicInternetMoney, amount, true); bentoBox.transfer(magicInternetMoney, skim ? address(bentoBox) : msg.sender, address(this), share); emit LogRepay(skim ? address(bentoBox) : msg.sender, to, amount, part); } /// @notice Repays a loan. /// @param to Address of the user this payment should go. /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender. /// False if tokens from msg.sender in `bentoBox` should be transferred. /// @param part The amount to repay. See `userBorrowPart`. /// @return amount The total amount repayed. function repay( address to, bool skim, uint256 part ) public returns (uint256 amount) { accrue(); amount = _repay(to, skim, part); } // Functions that need accrue to be called uint8 internal constant ACTION_REPAY = 2; uint8 internal constant ACTION_REMOVE_COLLATERAL = 4; uint8 internal constant ACTION_BORROW = 5; uint8 internal constant ACTION_GET_REPAY_SHARE = 6; uint8 internal constant ACTION_GET_REPAY_PART = 7; uint8 internal constant ACTION_ACCRUE = 8; // Functions that don't need accrue to be called uint8 internal constant ACTION_ADD_COLLATERAL = 10; uint8 internal constant ACTION_UPDATE_EXCHANGE_RATE = 11; // Function on BentoBox uint8 internal constant ACTION_BENTO_DEPOSIT = 20; uint8 internal constant ACTION_BENTO_WITHDRAW = 21; uint8 internal constant ACTION_BENTO_TRANSFER = 22; uint8 internal constant ACTION_BENTO_TRANSFER_MULTIPLE = 23; uint8 internal constant ACTION_BENTO_SETAPPROVAL = 24; // Any external call (except to BentoBox) uint8 internal constant ACTION_CALL = 30; uint8 internal constant ACTION_LIQUIDATE = 31; uint8 internal constant ACTION_RELEASE_COLLATERAL_FROM_STRATEGY = 33; int256 internal constant USE_VALUE1 = -1; int256 internal constant USE_VALUE2 = -2; /// @dev Helper function for choosing the correct value (`value1` or `value2`) depending on `inNum`. function _num( int256 inNum, uint256 value1, uint256 value2 ) internal pure returns (uint256 outNum) { outNum = inNum >= 0 ? uint256(inNum) : (inNum == USE_VALUE1 ? value1 : value2); } /// @dev Helper function for depositing into `bentoBox`. function _bentoDeposit( bytes memory data, uint256 value, uint256 value1, uint256 value2 ) internal returns (uint256, uint256) { (IERC20 token, address to, int256 amount, int256 share) = abi.decode(data, (IERC20, address, int256, int256)); amount = int256(_num(amount, value1, value2)); // Done this way to avoid stack too deep errors share = int256(_num(share, value1, value2)); return bentoBox.deposit{value: value}(token, msg.sender, to, uint256(amount), uint256(share)); } /// @dev Helper function to withdraw from the `bentoBox`. function _bentoWithdraw( bytes memory data, uint256 value1, uint256 value2 ) internal returns (uint256, uint256) { (IERC20 token, address to, int256 amount, int256 share) = abi.decode(data, (IERC20, address, int256, int256)); return bentoBox.withdraw(token, msg.sender, to, _num(amount, value1, value2), _num(share, value1, value2)); } /// @dev Helper function to perform a contract call and eventually extracting revert messages on failure. /// Calls to `bentoBox` are not allowed for obvious security reasons. /// This also means that calls made from this contract shall *not* be trusted. function _call( uint256 value, bytes memory data, uint256 value1, uint256 value2 ) internal returns (bytes memory, uint8) { (address callee, bytes memory callData, bool useValue1, bool useValue2, uint8 returnValues) = abi.decode(data, (address, bytes, bool, bool, uint8)); if (useValue1 && !useValue2) { callData = abi.encodePacked(callData, value1); } else if (!useValue1 && useValue2) { callData = abi.encodePacked(callData, value2); } else if (useValue1 && useValue2) { callData = abi.encodePacked(callData, value1, value2); } require(!blacklistedCallees[callee], "Cauldron: can't call"); (bool success, bytes memory returnData) = callee.call{value: value}(callData); require(success, "Cauldron: call failed"); return (returnData, returnValues); } struct CookStatus { bool needsSolvencyCheck; bool hasAccrued; } /// @notice Executes a set of actions and allows composability (contract calls) to other contracts. /// @param actions An array with a sequence of actions to execute (see ACTION_ declarations). /// @param values A one-to-one mapped array to `actions`. ETH amounts to send along with the actions. /// Only applicable to `ACTION_CALL`, `ACTION_BENTO_DEPOSIT`. /// @param datas A one-to-one mapped array to `actions`. Contains abi encoded data of function arguments. /// @return value1 May contain the first positioned return value of the last executed action (if applicable). /// @return value2 May contain the second positioned return value of the last executed action which returns 2 values (if applicable). function cook( uint8[] calldata actions, uint256[] calldata values, bytes[] calldata datas ) external payable returns (uint256 value1, uint256 value2) { CookStatus memory status; uint64 previousStrategyTargetPercentage = type(uint64).max; for (uint256 i = 0; i < actions.length; i++) { uint8 action = actions[i]; if (!status.hasAccrued && action < 10) { accrue(); status.hasAccrued = true; } if (action == ACTION_ADD_COLLATERAL) { (int256 share, address to, bool skim) = abi.decode(datas[i], (int256, address, bool)); addCollateral(to, skim, _num(share, value1, value2)); } else if (action == ACTION_REPAY) { (int256 part, address to, bool skim) = abi.decode(datas[i], (int256, address, bool)); _repay(to, skim, _num(part, value1, value2)); } else if (action == ACTION_REMOVE_COLLATERAL) { (int256 share, address to) = abi.decode(datas[i], (int256, address)); _removeCollateral(to, _num(share, value1, value2)); status.needsSolvencyCheck = true; } else if (action == ACTION_BORROW) { (int256 amount, address to) = abi.decode(datas[i], (int256, address)); (value1, value2) = _borrow(to, _num(amount, value1, value2)); status.needsSolvencyCheck = true; } else if (action == ACTION_UPDATE_EXCHANGE_RATE) { (bool must_update, uint256 minRate, uint256 maxRate) = abi.decode(datas[i], (bool, uint256, uint256)); (bool updated, uint256 rate) = updateExchangeRate(); require((!must_update || updated) && rate > minRate && (maxRate == 0 || rate > maxRate), "Cauldron: rate not ok"); } else if (action == ACTION_BENTO_SETAPPROVAL) { (address user, address _masterContract, bool approved, uint8 v, bytes32 r, bytes32 s) = abi.decode(datas[i], (address, address, bool, uint8, bytes32, bytes32)); bentoBox.setMasterContractApproval(user, _masterContract, approved, v, r, s); } else if (action == ACTION_BENTO_DEPOSIT) { (value1, value2) = _bentoDeposit(datas[i], values[i], value1, value2); } else if (action == ACTION_BENTO_WITHDRAW) { (value1, value2) = _bentoWithdraw(datas[i], value1, value2); } else if (action == ACTION_BENTO_TRANSFER) { (IERC20 token, address to, int256 share) = abi.decode(datas[i], (IERC20, address, int256)); bentoBox.transfer(token, msg.sender, to, _num(share, value1, value2)); } else if (action == ACTION_BENTO_TRANSFER_MULTIPLE) { (IERC20 token, address[] memory tos, uint256[] memory shares) = abi.decode(datas[i], (IERC20, address[], uint256[])); bentoBox.transferMultiple(token, msg.sender, tos, shares); } else if (action == ACTION_CALL) { (bytes memory returnData, uint8 returnValues) = _call(values[i], datas[i], value1, value2); if (returnValues == 1) { (value1) = abi.decode(returnData, (uint256)); } else if (returnValues == 2) { (value1, value2) = abi.decode(returnData, (uint256, uint256)); } } else if (action == ACTION_GET_REPAY_SHARE) { int256 part = abi.decode(datas[i], (int256)); value1 = bentoBox.toShare(magicInternetMoney, totalBorrow.toElastic(_num(part, value1, value2), true), true); } else if (action == ACTION_GET_REPAY_PART) { int256 amount = abi.decode(datas[i], (int256)); value1 = totalBorrow.toBase(_num(amount, value1, value2), false); } else if (action == ACTION_LIQUIDATE) { _cookActionLiquidate(datas[i]); } else if (action == ACTION_RELEASE_COLLATERAL_FROM_STRATEGY) { require(previousStrategyTargetPercentage == type(uint64).max, "Cauldron: strategy already released"); (, previousStrategyTargetPercentage,) = bentoBox.strategyData(collateral); IBentoBoxOwner(bentoBox.owner()).setStrategyTargetPercentageAndRebalance(collateral, 0); } } if (previousStrategyTargetPercentage != type(uint64).max) { IBentoBoxOwner(bentoBox.owner()).setStrategyTargetPercentageAndRebalance(collateral, previousStrategyTargetPercentage); } if (status.needsSolvencyCheck) { (, uint256 _exchangeRate) = updateExchangeRate(); require(_isSolvent(msg.sender, _exchangeRate), "Cauldron: user insolvent"); } } function _cookActionLiquidate(bytes calldata data) private { (address[] memory users, uint256[] memory maxBorrowParts, address to, ISwapperV2 swapper, bytes memory swapperData) = abi.decode(data, (address[], uint256[], address, ISwapperV2, bytes)); liquidate(users, maxBorrowParts, to, swapper, swapperData); } /// @notice Handles the liquidation of users' balances, once the users' amount of collateral is too low. /// @param users An array of user addresses. /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user. /// @param to Address of the receiver in open liquidations if `swapper` is zero. function liquidate( address[] memory users, uint256[] memory maxBorrowParts, address to, ISwapperV2 swapper, bytes memory swapperData ) public { // Oracle can fail but we still need to allow liquidations (, uint256 _exchangeRate) = updateExchangeRate(); accrue(); uint256 allCollateralShare; uint256 allBorrowAmount; uint256 allBorrowPart; Rebase memory bentoBoxTotals = bentoBox.totals(collateral); for (uint256 i = 0; i < users.length; i++) { address user = users[i]; if (!_isSolvent(user, _exchangeRate)) { uint256 borrowPart; { uint256 availableBorrowPart = userBorrowPart[user]; borrowPart = maxBorrowParts[i] > availableBorrowPart ? availableBorrowPart : maxBorrowParts[i]; userBorrowPart[user] = availableBorrowPart.sub(borrowPart); } uint256 borrowAmount = totalBorrow.toElastic(borrowPart, false); uint256 collateralShare = bentoBoxTotals.toBase( borrowAmount.mul(LIQUIDATION_MULTIPLIER).mul(_exchangeRate) / (LIQUIDATION_MULTIPLIER_PRECISION * EXCHANGE_RATE_PRECISION), false ); userCollateralShare[user] = userCollateralShare[user].sub(collateralShare); emit LogRemoveCollateral(user, to, collateralShare); emit LogRepay(msg.sender, user, borrowAmount, borrowPart); emit LogLiquidation(msg.sender, user, to, collateralShare, borrowAmount, borrowPart); // Keep totals allCollateralShare = allCollateralShare.add(collateralShare); allBorrowAmount = allBorrowAmount.add(borrowAmount); allBorrowPart = allBorrowPart.add(borrowPart); } } require(allBorrowAmount != 0, "Cauldron: all are solvent"); totalBorrow.elastic = totalBorrow.elastic.sub(allBorrowAmount.to128()); totalBorrow.base = totalBorrow.base.sub(allBorrowPart.to128()); totalCollateralShare = totalCollateralShare.sub(allCollateralShare); // Apply a percentual fee share to sSpell holders { uint256 distributionAmount = (allBorrowAmount.mul(LIQUIDATION_MULTIPLIER) / LIQUIDATION_MULTIPLIER_PRECISION).sub(allBorrowAmount).mul(DISTRIBUTION_PART) / DISTRIBUTION_PRECISION; // Distribution Amount allBorrowAmount = allBorrowAmount.add(distributionAmount); accrueInfo.feesEarned = accrueInfo.feesEarned.add(distributionAmount.to128()); } uint256 allBorrowShare = bentoBox.toShare(magicInternetMoney, allBorrowAmount, true); // Swap using a swapper freely chosen by the caller // Open (flash) liquidation: get proceeds first and provide the borrow after bentoBox.transfer(collateral, address(this), to, allCollateralShare); if (swapper != ISwapperV2(address(0))) { swapper.swap(address(collateral), address(magicInternetMoney), msg.sender, allBorrowShare, allCollateralShare, swapperData); } allBorrowShare = bentoBox.toShare(magicInternetMoney, allBorrowAmount, true); bentoBox.transfer(magicInternetMoney, msg.sender, address(this), allBorrowShare); } /// @notice Withdraws the fees accumulated. function withdrawFees() public { accrue(); address _feeTo = masterContract.feeTo(); uint256 _feesEarned = accrueInfo.feesEarned; uint256 share = bentoBox.toShare(magicInternetMoney, _feesEarned, false); bentoBox.transfer(magicInternetMoney, address(this), _feeTo, share); accrueInfo.feesEarned = 0; emit LogWithdrawFees(_feeTo, _feesEarned); } /// @notice Sets the beneficiary of interest accrued. /// MasterContract Only Admin function. /// @param newFeeTo The address of the receiver. function setFeeTo(address newFeeTo) public onlyOwner { feeTo = newFeeTo; emit LogFeeTo(newFeeTo); } /// @notice reduces the supply of MIM /// @param amount amount to reduce supply by function reduceSupply(uint256 amount) public onlyMasterContractOwner { uint256 maxAmount = bentoBox.toAmount(magicInternetMoney, bentoBox.balanceOf(magicInternetMoney, address(this)), false); amount = maxAmount > amount ? amount : maxAmount; bentoBox.withdraw(magicInternetMoney, address(this), msg.sender, amount, 0); } /// @notice allows to change the interest rate /// @param newInterestRate new interest rate function changeInterestRate(uint64 newInterestRate) public onlyMasterContractOwner { uint64 oldInterestRate = accrueInfo.INTEREST_PER_SECOND; require(newInterestRate < oldInterestRate + oldInterestRate * 3 / 4 || newInterestRate <= ONE_PERCENT_RATE, "Interest rate increase > 75%"); require(lastInterestUpdate + 3 days < block.timestamp, "Update only every 3 days"); lastInterestUpdate = block.timestamp; accrueInfo.INTEREST_PER_SECOND = newInterestRate; emit LogInterestChange(oldInterestRate, newInterestRate); } /// @notice allows to change the borrow limit /// @param newBorrowLimit new borrow limit /// @param perAddressPart new borrow limit per address function changeBorrowLimit(uint128 newBorrowLimit, uint128 perAddressPart) public onlyMasterContractOwner { borrowLimit = BorrowCap(newBorrowLimit, perAddressPart); emit LogChangeBorrowLimit(newBorrowLimit, perAddressPart); } /// @notice allows to change blacklisted callees /// @param callee callee to blacklist or not /// @param blacklisted true when the callee cannot be used in call cook action function setBlacklistedCallee(address callee, bool blacklisted) public onlyMasterContractOwner { require(callee != address(bentoBox) && callee != address(this), "invalid callee"); blacklistedCallees[callee] = blacklisted; emit LogChangeBlacklistedCallee(callee, blacklisted); } /// @notice Used to auto repay everyone liabilities'. /// Transfer MIM deposit to DegenBox for this Cauldron and increase the totalBorrow base or skim /// all mim inside this contract function repayForAll(uint128 amount, bool skim) public returns(uint128) { accrue(); if(skim) { // ignore amount and take every mim in this contract since it could be taken by anyone, the next block. amount = uint128(magicInternetMoney.balanceOf(address(this))); bentoBox.deposit(magicInternetMoney, address(this), address(this), amount, 0); } else { bentoBox.transfer(magicInternetMoney, msg.sender, address(this), bentoBox.toShare(magicInternetMoney, amount, true)); } uint128 previousElastic = totalBorrow.elastic; require(previousElastic - amount > 1000 * 1e18, "Total Elastic too small"); totalBorrow.elastic = previousElastic - amount; emit LogRepayForAll(amount, previousElastic, totalBorrow.elastic); return amount; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol + Claimable.sol // Simplified by BoringCrypto contract BoringOwnableData { address public owner; address public pendingOwner; } contract BoringOwnable is BoringOwnableData { event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /// @notice `owner` defaults to msg.sender on construction. constructor() { owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); } /// @notice Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner. /// Can only be invoked by the current `owner`. /// @param newOwner Address of the new owner. /// @param direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`. /// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect otherwise. function transferOwnership( address newOwner, bool direct, bool renounce ) public onlyOwner { if (direct) { // Checks require(newOwner != address(0) || renounce, "Ownable: zero address"); // Effects emit OwnershipTransferred(owner, newOwner); owner = newOwner; pendingOwner = address(0); } else { // Effects pendingOwner = newOwner; } } /// @notice Needs to be called by `pendingOwner` to claim ownership. function claimOwnership() public { address _pendingOwner = pendingOwner; // Checks require(msg.sender == _pendingOwner, "Ownable: caller != pending owner"); // Effects emit OwnershipTransferred(owner, _pendingOwner); owner = _pendingOwner; pendingOwner = address(0); } /// @notice Only allows the `owner` to execute the function. modifier onlyOwner() { require(msg.sender == owner, "Ownable: caller is not the owner"); _; } }
// SPDX-License-Identifier: MIT // Based on code and smartness by Ross Campbell and Keno // Uses immutable to store the domain separator to reduce gas usage // If the chain id changes due to a fork, the forked chain will calculate on the fly. pragma solidity ^0.8.0; // solhint-disable no-inline-assembly contract Domain { bytes32 private constant DOMAIN_SEPARATOR_SIGNATURE_HASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)"); // See https://eips.ethereum.org/EIPS/eip-191 string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = "\x19\x01"; // solhint-disable var-name-mixedcase bytes32 private immutable _DOMAIN_SEPARATOR; uint256 private immutable DOMAIN_SEPARATOR_CHAIN_ID; /// @dev Calculate the DOMAIN_SEPARATOR function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) { return keccak256(abi.encode(DOMAIN_SEPARATOR_SIGNATURE_HASH, chainId, address(this))); } constructor() { _DOMAIN_SEPARATOR = _calculateDomainSeparator(DOMAIN_SEPARATOR_CHAIN_ID = block.chainid); } /// @dev Return the DOMAIN_SEPARATOR // It's named internal to allow making it public from the contract that uses it by creating a simple view function // with the desired public name, such as DOMAIN_SEPARATOR or domainSeparator. // solhint-disable-next-line func-name-mixedcase function _domainSeparator() internal view returns (bytes32) { return block.chainid == DOMAIN_SEPARATOR_CHAIN_ID ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(block.chainid); } function _getDigest(bytes32 dataHash) internal view returns (bytes32 digest) { digest = keccak256(abi.encodePacked(EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA, _domainSeparator(), dataHash)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./interfaces/IERC20.sol"; import "./Domain.sol"; // solhint-disable no-inline-assembly // solhint-disable not-rely-on-time // Data part taken out for building of contracts that receive delegate calls contract ERC20Data { /// @notice owner > balance mapping. mapping(address => uint256) public balanceOf; /// @notice owner > spender > allowance mapping. mapping(address => mapping(address => uint256)) public allowance; /// @notice owner > nonce mapping. Used in `permit`. mapping(address => uint256) public nonces; } abstract contract ERC20 is IERC20, Domain { /// @notice owner > balance mapping. mapping(address => uint256) public override balanceOf; /// @notice owner > spender > allowance mapping. mapping(address => mapping(address => uint256)) public override allowance; /// @notice owner > nonce mapping. Used in `permit`. mapping(address => uint256) public nonces; /// @notice Transfers `amount` tokens from `msg.sender` to `to`. /// @param to The address to move the tokens. /// @param amount of the tokens to move. /// @return (bool) Returns True if succeeded. function transfer(address to, uint256 amount) public returns (bool) { // If `amount` is 0, or `msg.sender` is `to` nothing happens if (amount != 0 || msg.sender == to) { uint256 srcBalance = balanceOf[msg.sender]; require(srcBalance >= amount, "ERC20: balance too low"); if (msg.sender != to) { require(to != address(0), "ERC20: no zero address"); // Moved down so low balance calls safe some gas balanceOf[msg.sender] = srcBalance - amount; // Underflow is checked balanceOf[to] += amount; } } emit Transfer(msg.sender, to, amount); return true; } /// @notice Transfers `amount` tokens from `from` to `to`. Caller needs approval for `from`. /// @param from Address to draw tokens from. /// @param to The address to move the tokens. /// @param amount The token amount to move. /// @return (bool) Returns True if succeeded. function transferFrom( address from, address to, uint256 amount ) public returns (bool) { // If `amount` is 0, or `from` is `to` nothing happens if (amount != 0) { uint256 srcBalance = balanceOf[from]; require(srcBalance >= amount, "ERC20: balance too low"); if (from != to) { uint256 spenderAllowance = allowance[from][msg.sender]; // If allowance is infinite, don't decrease it to save on gas (breaks with EIP-20). if (spenderAllowance != type(uint256).max) { require(spenderAllowance >= amount, "ERC20: allowance too low"); allowance[from][msg.sender] = spenderAllowance - amount; // Underflow is checked } require(to != address(0), "ERC20: no zero address"); // Moved down so other failed calls safe some gas balanceOf[from] = srcBalance - amount; // Underflow is checked balanceOf[to] += amount; } } emit Transfer(from, to, amount); return true; } /// @notice Approves `amount` from sender to be spend by `spender`. /// @param spender Address of the party that can draw from msg.sender's account. /// @param amount The maximum collective amount that `spender` can draw. /// @return (bool) Returns True if approved. function approve(address spender, uint256 amount) public override returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32) { return _domainSeparator(); } // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 private constant PERMIT_SIGNATURE_HASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; /// @notice Approves `value` from `owner_` to be spend by `spender`. /// @param owner_ Address of the owner. /// @param spender The address of the spender that gets approved to draw from `owner_`. /// @param value The maximum collective amount that `spender` can draw. /// @param deadline This permit must be redeemed before this deadline (UTC timestamp in seconds). function permit( address owner_, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external override { require(owner_ != address(0), "ERC20: Owner cannot be 0"); require(block.timestamp < deadline, "ERC20: Expired"); require( ecrecover(_getDigest(keccak256(abi.encode(PERMIT_SIGNATURE_HASH, owner_, spender, value, nonces[owner_]++, deadline))), v, r, s) == owner_, "ERC20: Invalid Signature" ); allowance[owner_][spender] = value; emit Approval(owner_, spender, value); } } contract ERC20WithSupply is IERC20, ERC20 { uint256 public override totalSupply; function _mint(address user, uint256 amount) internal { uint256 newTotalSupply = totalSupply + amount; require(newTotalSupply >= totalSupply, "Mint overflow"); totalSupply = newTotalSupply; balanceOf[user] += amount; emit Transfer(address(0), user, amount); } function _burn(address user, uint256 amount) internal { require(balanceOf[user] >= amount, "Burn too much"); totalSupply -= amount; balanceOf[user] -= amount; emit Transfer(user, address(0), amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IERC20 { // transfer and tranferFrom have been removed, because they don't work on all tokens (some aren't ERC20 complaint). // By removing them you can't accidentally use them. // name, symbol and decimals have been removed, because they are optional and sometimes wrongly implemented (MKR). // Use BoringERC20 with `using BoringERC20 for IERC20` and call `safeTransfer`, `safeTransferFrom`, etc instead. function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); /// @notice EIP 2612 function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; } interface IStrictERC20 { // This is the strict ERC20 interface. Don't use this, certainly not if you don't control the ERC20 token you're calling. function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address _owner) external view returns (uint256 balance); function transfer(address _to, uint256 _value) external returns (bool success); function transferFrom(address _from, address _to, uint256 _value) external returns (bool success); function approve(address _spender, uint256 _value) external returns (bool success); function allowance(address _owner, address _spender) external view returns (uint256 remaining); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); /// @notice EIP 2612 function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IMasterContract { /// @notice Init function that gets called from `BoringFactory.deploy`. /// Also kown as the constructor for cloned contracts. /// Any ETH send to `BoringFactory.deploy` ends up here. /// @param data Can be abi encoded arguments or anything else. function init(bytes calldata data) external payable; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../interfaces/IERC20.sol"; // solhint-disable avoid-low-level-calls library BoringERC20 { bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol() bytes4 private constant SIG_NAME = 0x06fdde03; // name() bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals() bytes4 private constant SIG_BALANCE_OF = 0x70a08231; // balanceOf(address) bytes4 private constant SIG_TOTALSUPPLY = 0x18160ddd; // balanceOf(address) bytes4 private constant SIG_TRANSFER = 0xa9059cbb; // transfer(address,uint256) bytes4 private constant SIG_TRANSFER_FROM = 0x23b872dd; // transferFrom(address,address,uint256) function returnDataToString(bytes memory data) internal pure returns (string memory) { if (data.length >= 64) { return abi.decode(data, (string)); } else if (data.length == 32) { uint8 i = 0; while (i < 32 && data[i] != 0) { i++; } bytes memory bytesArray = new bytes(i); for (i = 0; i < 32 && data[i] != 0; i++) { bytesArray[i] = data[i]; } return string(bytesArray); } else { return "???"; } } /// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string. /// @param token The address of the ERC-20 token contract. /// @return (string) Token symbol. function safeSymbol(IERC20 token) internal view returns (string memory) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_SYMBOL)); return success ? returnDataToString(data) : "???"; } /// @notice Provides a safe ERC20.name version which returns '???' as fallback string. /// @param token The address of the ERC-20 token contract. /// @return (string) Token name. function safeName(IERC20 token) internal view returns (string memory) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_NAME)); return success ? returnDataToString(data) : "???"; } /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value. /// @param token The address of the ERC-20 token contract. /// @return (uint8) Token decimals. function safeDecimals(IERC20 token) internal view returns (uint8) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS)); return success && data.length == 32 ? abi.decode(data, (uint8)) : 18; } /// @notice Provides a gas-optimized balance check to avoid a redundant extcodesize check in addition to the returndatasize check. /// @param token The address of the ERC-20 token. /// @param to The address of the user to check. /// @return amount The token amount. function safeBalanceOf(IERC20 token, address to) internal view returns (uint256 amount) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_BALANCE_OF, to)); require(success && data.length >= 32, "BoringERC20: BalanceOf failed"); amount = abi.decode(data, (uint256)); } /// @notice Provides a gas-optimized totalSupply to avoid a redundant extcodesize check in addition to the returndatasize check. /// @param token The address of the ERC-20 token. /// @return totalSupply The token totalSupply. function safeTotalSupply(IERC20 token) internal view returns (uint256 totalSupply) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_TOTALSUPPLY)); require(success && data.length >= 32, "BoringERC20: totalSupply failed"); totalSupply = abi.decode(data, (uint256)); } /// @notice Provides a safe ERC20.transfer version for different ERC-20 implementations. /// Reverts on a failed transfer. /// @param token The address of the ERC-20 token. /// @param to Transfer tokens to. /// @param amount The token amount. function safeTransfer( IERC20 token, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(SIG_TRANSFER, to, amount)); require(success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: Transfer failed"); } /// @notice Provides a safe ERC20.transferFrom version for different ERC-20 implementations. /// Reverts on a failed transfer. /// @param token The address of the ERC-20 token. /// @param from Transfer tokens from. /// @param to Transfer tokens to. /// @param amount The token amount. function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(SIG_TRANSFER_FROM, from, to, amount)); require(success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: TransferFrom failed"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; struct Rebase { uint128 elastic; uint128 base; } /// @notice A rebasing library using overflow-/underflow-safe math. library RebaseLibrary { /// @notice Calculates the base value in relationship to `elastic` and `total`. function toBase( Rebase memory total, uint256 elastic, bool roundUp ) internal pure returns (uint256 base) { if (total.elastic == 0) { base = elastic; } else { base = (elastic * total.base) / total.elastic; if (roundUp && (base * total.elastic) / total.base < elastic) { base++; } } } /// @notice Calculates the elastic value in relationship to `base` and `total`. function toElastic( Rebase memory total, uint256 base, bool roundUp ) internal pure returns (uint256 elastic) { if (total.base == 0) { elastic = base; } else { elastic = (base * total.elastic) / total.base; if (roundUp && (elastic * total.base) / total.elastic < base) { elastic++; } } } /// @notice Add `elastic` to `total` and doubles `total.base`. /// @return (Rebase) The new total. /// @return base in relationship to `elastic`. function add( Rebase memory total, uint256 elastic, bool roundUp ) internal pure returns (Rebase memory, uint256 base) { base = toBase(total, elastic, roundUp); total.elastic += uint128(elastic); total.base += uint128(base); return (total, base); } /// @notice Sub `base` from `total` and update `total.elastic`. /// @return (Rebase) The new total. /// @return elastic in relationship to `base`. function sub( Rebase memory total, uint256 base, bool roundUp ) internal pure returns (Rebase memory, uint256 elastic) { elastic = toElastic(total, base, roundUp); total.elastic -= uint128(elastic); total.base -= uint128(base); return (total, elastic); } /// @notice Add `elastic` and `base` to `total`. function add( Rebase memory total, uint256 elastic, uint256 base ) internal pure returns (Rebase memory) { total.elastic += uint128(elastic); total.base += uint128(base); return total; } /// @notice Subtract `elastic` and `base` to `total`. function sub( Rebase memory total, uint256 elastic, uint256 base ) internal pure returns (Rebase memory) { total.elastic -= uint128(elastic); total.base -= uint128(base); return total; } /// @notice Add `elastic` to `total` and update storage. /// @return newElastic Returns updated `elastic`. function addElastic(Rebase storage total, uint256 elastic) internal returns (uint256 newElastic) { newElastic = total.elastic += uint128(elastic); } /// @notice Subtract `elastic` from `total` and update storage. /// @return newElastic Returns updated `elastic`. function subElastic(Rebase storage total, uint256 elastic) internal returns (uint256 newElastic) { newElastic = total.elastic -= uint128(elastic); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import "BoringSolidity/interfaces/IERC20.sol"; interface IBentoBoxOwner { function setStrategyTargetPercentageAndRebalance(IERC20 token, uint64 targetPercentage) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import "BoringSolidity/interfaces/IERC20.sol"; import "BoringSolidity/libraries/BoringRebase.sol"; import "interfaces/IStrategy.sol"; interface IFlashBorrower { /// @notice The flashloan callback. `amount` + `fee` needs to repayed to msg.sender before this call returns. /// @param sender The address of the invoker of this flashloan. /// @param token The address of the token that is loaned. /// @param amount of the `token` that is loaned. /// @param fee The fee that needs to be paid on top for this loan. Needs to be the same as `token`. /// @param data Additional data that was passed to the flashloan function. function onFlashLoan( address sender, IERC20 token, uint256 amount, uint256 fee, bytes calldata data ) external; } interface IBatchFlashBorrower { /// @notice The callback for batched flashloans. Every amount + fee needs to repayed to msg.sender before this call returns. /// @param sender The address of the invoker of this flashloan. /// @param tokens Array of addresses for ERC-20 tokens that is loaned. /// @param amounts A one-to-one map to `tokens` that is loaned. /// @param fees A one-to-one map to `tokens` that needs to be paid on top for each loan. Needs to be the same token. /// @param data Additional data that was passed to the flashloan function. function onBatchFlashLoan( address sender, IERC20[] calldata tokens, uint256[] calldata amounts, uint256[] calldata fees, bytes calldata data ) external; } interface IBentoBoxV1 { function balanceOf(IERC20, address) external view returns (uint256); function batch(bytes[] calldata calls, bool revertOnFail) external payable returns (bool[] memory successes, bytes[] memory results); function batchFlashLoan( IBatchFlashBorrower borrower, address[] calldata receivers, IERC20[] calldata tokens, uint256[] calldata amounts, bytes calldata data ) external; function claimOwnership() external; function flashLoan( IFlashBorrower borrower, address receiver, IERC20 token, uint256 amount, bytes calldata data ) external; function deploy( address masterContract, bytes calldata data, bool useCreate2 ) external payable returns (address); function deposit( IERC20 token_, address from, address to, uint256 amount, uint256 share ) external payable returns (uint256 amountOut, uint256 shareOut); function harvest( IERC20 token, bool balance, uint256 maxChangeAmount ) external; function masterContractApproved(address, address) external view returns (bool); function masterContractOf(address) external view returns (address); function nonces(address) external view returns (uint256); function owner() external view returns (address); function pendingOwner() external view returns (address); function pendingStrategy(IERC20) external view returns (IStrategy); function permitToken( IERC20 token, address from, address to, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; function registerProtocol() external; function setMasterContractApproval( address user, address masterContract, bool approved, uint8 v, bytes32 r, bytes32 s ) external; function setStrategy(IERC20 token, IStrategy newStrategy) external; function setStrategyTargetPercentage(IERC20 token, uint64 targetPercentage_) external; function strategy(IERC20) external view returns (IStrategy); function strategyData(IERC20) external view returns ( uint64 strategyStartDate, uint64 targetPercentage, uint128 balance ); function toAmount( IERC20 token, uint256 share, bool roundUp ) external view returns (uint256 amount); function toShare( IERC20 token, uint256 amount, bool roundUp ) external view returns (uint256 share); function totals(IERC20) external view returns (Rebase memory totals_); function transfer( IERC20 token, address from, address to, uint256 share ) external; function transferMultiple( IERC20 token, address from, address[] calldata tos, uint256[] calldata shares ) external; function transferOwnership( address newOwner, bool direct, bool renounce ) external; function whitelistMasterContract(address masterContract, bool approved) external; function whitelistedMasterContracts(address) external view returns (bool); function withdraw( IERC20 token_, address from, address to, uint256 amount, uint256 share ) external returns (uint256 amountOut, uint256 shareOut); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IOracle { /// @notice Get the latest exchange rate. /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle. /// For example: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256)); /// @return success if no valid (recent) rate is available, return false else true. /// @return rate The rate of the requested asset / pair / pool. function get(bytes calldata data) external returns (bool success, uint256 rate); /// @notice Check the last exchange rate without any state changes. /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle. /// For example: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256)); /// @return success if no valid (recent) rate is available, return false else true. /// @return rate The rate of the requested asset / pair / pool. function peek(bytes calldata data) external view returns (bool success, uint256 rate); /// @notice Check the current spot exchange rate without any state changes. For oracles like TWAP this will be different from peek(). /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle. /// For example: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256)); /// @return rate The rate of the requested asset / pair / pool. function peekSpot(bytes calldata data) external view returns (uint256 rate); /// @notice Returns a human readable (short) name about this oracle. /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle. /// For example: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256)); /// @return (string) A human readable symbol name about this oracle. function symbol(bytes calldata data) external view returns (string memory); /// @notice Returns a human readable name about this oracle. /// @param data Usually abi encoded, implementation specific data that contains information and arguments to & about the oracle. /// For example: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256)); /// @return (string) A human readable name about this oracle. function name(bytes calldata data) external view returns (string memory); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.0; interface IStrategy { /// @notice Send the assets to the Strategy and call skim to invest them. /// @param amount The amount of tokens to invest. function skim(uint256 amount) external; /// @notice Harvest any profits made converted to the asset and pass them to the caller. /// @param balance The amount of tokens the caller thinks it has invested. /// @param sender The address of the initiator of this transaction. Can be used for reimbursements, etc. /// @return amountAdded The delta (+profit or -loss) that occured in contrast to `balance`. function harvest(uint256 balance, address sender) external returns (int256 amountAdded); /// @notice Withdraw assets. The returned amount can differ from the requested amount due to rounding. /// @dev The `actualAmount` should be very close to the amount. /// The difference should NOT be used to report a loss. That's what harvest is for. /// @param amount The requested amount the caller wants to withdraw. /// @return actualAmount The real amount that is withdrawn. function withdraw(uint256 amount) external returns (uint256 actualAmount); /// @notice Withdraw all assets in the safest way possible. This shouldn't fail. /// @param balance The amount of tokens the caller thinks it has invested. /// @return amountAdded The delta (+profit or -loss) that occured in contrast to `balance`. function exit(uint256 balance) external returns (int256 amountAdded); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface ISwapperV2 { /// @notice Withdraws 'amountFrom' of token 'from' from the BentoBox account for this swapper. /// Swaps it for at least 'amountToMin' of token 'to'. /// Transfers the swapped tokens of 'to' into the BentoBox using a plain IERC20 transfer. /// Returns the amount of tokens 'to' transferred to BentoBox. /// (The BentoBox skim function will be used by the caller to get the swapped funds). function swap( address fromToken, address toToken, address recipient, uint256 shareToMin, uint256 shareFrom, bytes calldata data ) external returns (uint256 extraShare, uint256 shareReturned); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; library BoringMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } function to128(uint256 a) internal pure returns (uint128 c) { c = uint128(a); } function to64(uint256 a) internal pure returns (uint64 c) { c = uint64(a); } function to32(uint256 a) internal pure returns (uint32 c) { c = uint32(a); } } library BoringMath128 { function add(uint128 a, uint128 b) internal pure returns (uint128 c) { c = a + b; } function sub(uint128 a, uint128 b) internal pure returns (uint128 c) { c = a - b; } }
{ "remappings": [ "/=src/", "BoringSolidity/=lib/BoringSolidity/contracts/", "OpenZeppelin/=lib/openzeppelin-contracts/contracts/", "cauldrons/=src/cauldrons/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "interfaces/=src/interfaces/", "libraries/=src/libraries/", "mocks/=src/mocks/", "oracles/=src/oracles/", "periphery/=src/periphery/", "solmate/=lib/solmate/src/", "strategies/=src/strategies/", "swappers/=src/swappers/", "tokens/=src/tokens/", "utils/=utils/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IBentoBoxV1","name":"bentoBox_","type":"address"},{"internalType":"contract IERC20","name":"magicInternetMoney_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"accruedAmount","type":"uint128"}],"name":"LogAccrue","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":"share","type":"uint256"}],"name":"LogAddCollateral","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":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"part","type":"uint256"}],"name":"LogBorrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"blacklisted","type":"bool"}],"name":"LogChangeBlacklistedCallee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"newLimit","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"perAddressPart","type":"uint128"}],"name":"LogChangeBorrowLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rate","type":"uint256"}],"name":"LogExchangeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newFeeTo","type":"address"}],"name":"LogFeeTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"oldInterestRate","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"newInterestRate","type":"uint64"}],"name":"LogInterestChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowPart","type":"uint256"}],"name":"LogLiquidation","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":"share","type":"uint256"}],"name":"LogRemoveCollateral","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":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"part","type":"uint256"}],"name":"LogRepay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"previousElastic","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"newElastic","type":"uint128"}],"name":"LogRepayForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feeTo","type":"address"},{"indexed":false,"internalType":"uint256","name":"feesEarnedFraction","type":"uint256"}],"name":"LogWithdrawFees","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"BORROW_OPENING_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COLLATERIZATION_RATE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIQUIDATION_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"accrueInfo","outputs":[{"internalType":"uint64","name":"lastAccrued","type":"uint64"},{"internalType":"uint128","name":"feesEarned","type":"uint128"},{"internalType":"uint64","name":"INTEREST_PER_SECOND","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"skim","type":"bool"},{"internalType":"uint256","name":"share","type":"uint256"}],"name":"addCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bentoBox","outputs":[{"internalType":"contract IBentoBoxV1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"blacklistedCallees","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"uint256","name":"part","type":"uint256"},{"internalType":"uint256","name":"share","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowLimit","outputs":[{"internalType":"uint128","name":"total","type":"uint128"},{"internalType":"uint128","name":"borrowPartPerAddress","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"newBorrowLimit","type":"uint128"},{"internalType":"uint128","name":"perAddressPart","type":"uint128"}],"name":"changeBorrowLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newInterestRate","type":"uint64"}],"name":"changeInterestRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"actions","type":"uint8[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes[]","name":"datas","type":"bytes[]"}],"name":"cook","outputs":[{"internalType":"uint256","name":"value1","type":"uint256"},{"internalType":"uint256","name":"value2","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"exchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"init","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"uint256[]","name":"maxBorrowParts","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"contract ISwapperV2","name":"swapper","type":"address"},{"internalType":"bytes","name":"swapperData","type":"bytes"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"magicInternetMoney","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterContract","outputs":[{"internalType":"contract CauldronV4","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"reduceSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"share","type":"uint256"}],"name":"removeCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"skim","type":"bool"},{"internalType":"uint256","name":"part","type":"uint256"}],"name":"repay","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"bool","name":"skim","type":"bool"}],"name":"repayForAll","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"callee","type":"address"},{"internalType":"bool","name":"blacklisted","type":"bool"}],"name":"setBlacklistedCallee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFeeTo","type":"address"}],"name":"setFeeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalBorrow","outputs":[{"internalType":"uint128","name":"elastic","type":"uint128"},{"internalType":"uint128","name":"base","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCollateralShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"},{"internalType":"bool","name":"direct","type":"bool"},{"internalType":"bool","name":"renounce","type":"bool"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateExchangeRate","outputs":[{"internalType":"bool","name":"updated","type":"bool"},{"internalType":"uint256","name":"rate","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userBorrowPart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userCollateralShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60e06040523480156200001157600080fd5b50604051620057ed380380620057ed8339810160408190526200003491620000a8565b600080546001600160a01b0319163390811782556040519091907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a36001600160a01b039182166080521660c0523060a052620000e7565b6001600160a01b0381168114620000a557600080fd5b50565b60008060408385031215620000bc57600080fd5b8251620000c9816200008f565b6020840151909250620000dc816200008f565b809150509250929050565b60805160a05160c05161554e6200029f600039600081816105af01528181610d1701528181610dcb0152818161106a01528181611aa501528181612026015281816120af015281816121810152818161243e015281816125a7015281816131a2015281816132d60152818161338f01528181613444015281816135890152818161362a015281816139570152613a0a0152600081816106be01528181610a0601528181610c390152818161237f0152818161274a015261298701526000818161042001528181610ce201528181610d9e0152818161103a015281816111500152818161166a015281816118220152818161190001528181611a7601528181611cb901528181611d3001528181611e3c015281816120fd015281816121c8015281816124780152818161257a0152818161269b015281816127fc01528181612cfd015281816131750152818161322d01528181613362015281816134170152818161355a015281816135fb01528181613656015281816136e001528181613922015281816139dd01528181613b6f01528181613ce501528181613d9b01528181613e6801528181614277015261434d015261554e6000f3fe6080604052600436106102255760003560e01c80638062344411610123578063cb0dc548116100ab578063eeae797b1161006f578063eeae797b1461074b578063f46901ed1461076b578063f7dad4341461078b578063f8ba4cff146107ab578063ff6ff84b146107c057600080fd5b8063cb0dc5481461066c578063cd446e22146106ac578063d8dfeb45146106e0578063e30c397814610700578063e551d11d1461072057600080fd5b80638da5cb5b116100f25780638da5cb5b1461057d5780639b352ae11461059d578063aba024f4146105d1578063b27c0e74146105e7578063c7ee2a7b1461065657600080fd5b806380623444146104d25780638285ef40146104f2578063860ffea11461053d578063876467f81461055d57600080fd5b806348e4163e116101b15780636b2ace87116101755780636b2ace871461040e5780636ec097fb1461044257806374645ff3146104585780637dc0d1d01461047a5780637ef404551461049a57600080fd5b806348e4163e146103715780634b8a35291461039e5780634ddf47d4146103d35780634e71e0c8146103e6578063656f3d64146103fb57600080fd5b80631c9e379b116101f85780631c9e379b146102e35780631cd4c966146103105780633ba0b9a914610330578063473e3ce714610346578063476343ee1461035c57600080fd5b8063017e7e581461022a57806302ce728f14610267578063078dfbe71461029357806315294c40146102b5575b600080fd5b34801561023657600080fd5b5060025461024a906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561027357600080fd5b5061027c6107e0565b60408051921515835260208301919091520161025e565b34801561029f57600080fd5b506102b36102ae3660046144d4565b6108a4565b005b3480156102c157600080fd5b506102d56102d036600461451f565b6109e7565b60405190815260200161025e565b3480156102ef57600080fd5b506102d56102fe366004614560565b60096020526000908152604090205481565b34801561031c57600080fd5b506102b361032b366004614592565b610a04565b34801561033c57600080fd5b506102d5600c5481565b34801561035257600080fd5b506102d560075481565b34801561036857600080fd5b506102b3610c2d565b34801561037d57600080fd5b506102d561038c366004614560565b600a6020526000908152604090205481565b3480156103aa57600080fd5b506103be6103b93660046145af565b610e81565b6040805192835260208301919091520161025e565b6102b36103e13660046145db565b610ed6565b3480156103f257600080fd5b506102b3611231565b6103be610409366004614697565b6112ee565b34801561041a57600080fd5b5061024a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561044e57600080fd5b506102d560105481565b34801561046457600080fd5b5061046d611f73565b60405161025e9190614780565b34801561048657600080fd5b5060045461024a906001600160a01b031681565b3480156104a657600080fd5b506104ba6104b53660046147a8565b612001565b6040516001600160801b03909116815260200161025e565b3480156104de57600080fd5b506102b36104ed3660046147e1565b61237d565b3480156104fe57600080fd5b5060085461051d906001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161025e565b34801561054957600080fd5b506102b361055836600461451f565b612620565b34801561056957600080fd5b506102b36105783660046145af565b612703565b34801561058957600080fd5b5060005461024a906001600160a01b031681565b3480156105a957600080fd5b5061024a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156105dd57600080fd5b506102d560115481565b3480156105f357600080fd5b50600d54610624906001600160401b03808216916001600160801b03600160401b82041691600160c01b9091041683565b604080516001600160401b0394851681526001600160801b03909316602084015292169181019190915260600161025e565b34801561066257600080fd5b506102d5600f5481565b34801561067857600080fd5b5061069c610687366004614560565b600b6020526000908152604090205460ff1681565b604051901515815260200161025e565b3480156106b857600080fd5b5061024a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106ec57600080fd5b5060035461024a906001600160a01b031681565b34801561070c57600080fd5b5060015461024a906001600160a01b031681565b34801561072c57600080fd5b5060065461051d906001600160801b0380821691600160801b90041682565b34801561075757600080fd5b506102b36107663660046147fa565b612748565b34801561077757600080fd5b506102b3610786366004614560565b6128e1565b34801561079757600080fd5b506102b36107a6366004614818565b612985565b3480156107b757600080fd5b506102b3612a99565b3480156107cc57600080fd5b506102b36107db3660046149f6565b612cbd565b6004805460405163d6d7d52560e01b815260009283926001600160a01b03169163d6d7d525916108139160059101614ae1565b60408051808303816000875af1158015610831573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108559190614b7c565b9092509050811561089c57600c8190556040518181527f9f9192b5edb17356c524e08d9e025c8e2f6307e6ea52fb7968faa3081f51c3c89060200160405180910390a19091565b50600c549091565b6000546001600160a01b031633146109035760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b81156109c6576001600160a01b03831615158061091d5750805b6109615760405162461bcd60e51b81526020600482015260156024820152744f776e61626c653a207a65726f206164647265737360581b60448201526064016108fa565b600080546040516001600160a01b03808716939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0385166001600160a01b031991821617909155600180549091169055505050565b600180546001600160a01b0319166001600160a01b0385161790555b505050565b60006109f1612a99565b6109fc8484846134b1565b949350505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a869190614baa565b6001600160a01b0316336001600160a01b031614610ab65760405162461bcd60e51b81526004016108fa90614bc7565b600d54600160c01b90046001600160401b03166004610ad6826003614c14565b610ae09190614c59565b610aea9082614c7f565b6001600160401b0316826001600160401b03161080610b1657506312e687c06001600160401b03831611155b610b625760405162461bcd60e51b815260206004820152601c60248201527f496e746572657374207261746520696e637265617365203e203735250000000060448201526064016108fa565b42600e546203f480610b749190614ca6565b10610bc15760405162461bcd60e51b815260206004820152601860248201527f557064617465206f6e6c7920657665727920332064617973000000000000000060448201526064016108fa565b42600e55600d80546001600160c01b0316600160c01b6001600160401b038581169182029290921790925560408051918416825260208201929092527f76bc92b92b7755bcb03b25070431a80435c4d3fbf91c6c81c0c0cc350f6b5c6a91015b60405180910390a15050565b610c35612a99565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663017e7e586040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb99190614baa565b600d54604051636d289ce560e11b8152919250600160401b90046001600160801b0316906000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063da5139ca90610d43907f00000000000000000000000000000000000000000000000000000000000000009086908690600401614cb9565b602060405180830381865afa158015610d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d849190614cdc565b604051633c6340f360e21b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f18d03cc90610df9907f000000000000000000000000000000000000000000000000000000000000000090309088908790600401614cf5565b600060405180830381600087803b158015610e1357600080fd5b505af1158015610e27573d6000803e3d6000fd5b5050600d8054600160401b600160c01b031916905550506040518281526001600160a01b038416907fbe641c3ffc44b2d6c184f023fa4ed7bda4b6ffa71e03b3c98ae0c776da1f17e79060200160405180910390a2505050565b600080610e8c612a99565b610e968484613753565b90925090506000610ea56107e0565b915050610eb23382613ac2565b610ece5760405162461bcd60e51b81526004016108fa90614d1f565b509250929050565b6003546001600160a01b031615610f2f5760405162461bcd60e51b815260206004820152601d60248201527f4361756c64726f6e3a20616c726561647920696e697469616c697a656400000060448201526064016108fa565b610f3b81830183614d56565b6011819055600f8290556010839055600d80546001600160c01b0316600160c01b6001600160401b03871602179055600360006004816005610f7d8a82614e2b565b50815461010091820a6001600160a01b03818102199092169b8216029a909a17909155825491900a8089021990911698881602979097179096555050604080518082019091526001600160801b0380825260209091015250506000196006556003541690506110235760405162461bcd60e51b815260206004820152601260248201527121b0bab6323937b71d103130b2103830b4b960711b60448201526064016108fa565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301527f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b3906044016020604051808303816000875af11580156110b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d79190614eea565b506004805460405163d6d7d52560e01b81526001600160a01b039091169163d6d7d525916111089160059101614ae1565b60408051808303816000875af1158015611126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114a9190614b7c565b600c55507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166000818152600b602081815260408084208054600160ff1991821681179092553086528286208054909116821790558151638da5cb5b60e01b81529151909593949392638da5cb5b92600480820193918290030181865afa1580156111e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112059190614baa565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790555050565b6001546001600160a01b031633811461128c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c657220213d2070656e64696e67206f776e657260448201526064016108fa565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b604080518082019091526000808252602082018190529081906001600160401b0360005b89811015611e295760008b8b8381811061132e5761132e614f07565b90506020020160208101906113439190614f2c565b9050836020015115801561135a5750600a8160ff16105b1561136f57611367612a99565b600160208501525b60091960ff8216016113cf5760008060008a8a8681811061139257611392614f07565b90506020028101906113a49190614f49565b8101906113b19190614f8f565b9250925092506113c78282610558868d8d613c2a565b505050611e16565b60011960ff8216016114355760008060008a8a868181106113f2576113f2614f07565b90506020028101906114049190614f49565b8101906114119190614f8f565b92509250925061142c8282611427868d8d613c2a565b6134b1565b50505050611e16565b60031960ff8216016114985760008089898581811061145657611456614f07565b90506020028101906114689190614f49565b8101906114759190614fb6565b9150915061148d81611488848b8b613c2a565b613c51565b505060018452611e16565b60041960ff821601611501576000808989858181106114b9576114b9614f07565b90506020028101906114cb9190614f49565b8101906114d89190614fb6565b915091506114f0816114eb848b8b613c2a565b613753565b600188529098509650611e16915050565b600a1960ff8216016115ce5760008060008a8a8681811061152457611524614f07565b90506020028101906115369190614f49565b8101906115439190614fdb565b9250925092506000806115546107e0565b915091508415806115625750815b801561156d57508381115b8015611580575082158061158057508281115b6115c45760405162461bcd60e51b81526020600482015260156024820152744361756c64726f6e3a2072617465206e6f74206f6b60581b60448201526064016108fa565b5050505050611e16565b60171960ff8216016116d3576000806000806000808d8d898181106115f5576115f5614f07565b90506020028101906116079190614f49565b8101906116149190615010565b60405163c0a47c9360e01b81526001600160a01b0387811660048301528681166024830152851515604483015260ff851660648301526084820184905260a48201839052969c50949a50929850909650945092507f00000000000000000000000000000000000000000000000000000000000000009091169063c0a47c939060c401600060405180830381600087803b1580156116b057600080fd5b505af11580156116c4573d6000803e3d6000fd5b50505050505050505050611e16565b60131960ff8216016117675761175d8888848181106116f4576116f4614f07565b90506020028101906117069190614f49565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92508d915086905081811061174f5761174f614f07565b905060200201358888613d5a565b9096509450611e16565b60141960ff8216016117d85761175d88888481811061178857611788614f07565b905060200281019061179a9190614f49565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250899150613e419050565b60151960ff8216016118b65760008060008a8a868181106117fb576117fb614f07565b905060200281019061180d9190614f49565b81019061181a919061507e565b9250925092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f18d03cc84338561185d868f8f613c2a565b6040518563ffffffff1660e01b815260040161187c9493929190614cf5565b600060405180830381600087803b15801561189657600080fd5b505af11580156118aa573d6000803e3d6000fd5b50505050505050611e16565b60161960ff8216016119505760008060008a8a868181106118d9576118d9614f07565b90506020028101906118eb9190614f49565b8101906118f891906150ae565b9250925092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630fca8843843385856040518563ffffffff1660e01b815260040161187c9493929190615123565b601d1960ff821601611a33576000806119dd8c8c8681811061197457611974614f07565b905060200201358b8b8781811061198d5761198d614f07565b905060200281019061199f9190614f49565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508d92508c9150613f209050565b915091508060ff16600103611a075781806020019051810190611a009190614cdc565b9750611a2c565b8060ff16600203611a2c5781806020019051810190611a2691906151be565b90985096505b5050611e16565b60051960ff821601611b6b576000888884818110611a5357611a53614f07565b9050602002810190611a659190614f49565b810190611a7291906147e1565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663da5139ca7f0000000000000000000000000000000000000000000000000000000000000000611b02611ad2858c8c613c2a565b604080518082019091526008546001600160801b038082168352600160801b9091041660208201529060016140f5565b60016040518463ffffffff1660e01b8152600401611b2293929190614cb9565b602060405180830381865afa158015611b3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b639190614cdc565b965050611e16565b60061960ff821601611bea576000888884818110611b8b57611b8b614f07565b9050602002810190611b9d9190614f49565b810190611baa91906147e1565b9050611b63611bba828989613c2a565b604080518082019091526008546001600160801b038082168352600160801b909104166020820152906000614193565b601e1960ff821601611c2757611c22888884818110611c0b57611c0b614f07565b9050602002810190611c1d9190614f49565b614208565b611e16565b60201960ff821601611e16576001600160401b0383811614611c975760405162461bcd60e51b815260206004820152602360248201527f4361756c64726f6e3a20737472617465677920616c72656164792072656c65616044820152621cd95960ea1b60648201526084016108fa565b60035460405163df23b45b60e01b81526001600160a01b0391821660048201527f00000000000000000000000000000000000000000000000000000000000000009091169063df23b45b90602401606060405180830381865afa158015611d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2691906151e2565b90915050809350507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db09190614baa565b600354604051638483a07760e01b81526001600160a01b03918216600482015260006024820152911690638483a07790604401600060405180830381600087803b158015611dfd57600080fd5b505af1158015611e11573d6000803e3d6000fd5b505050505b5080611e2181615224565b915050611312565b506001600160401b0381811614611f2a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebc9190614baa565b600354604051638483a07760e01b81526001600160a01b0391821660048201526001600160401b0384166024820152911690638483a07790604401600060405180830381600087803b158015611f1157600080fd5b505af1158015611f25573d6000803e3d6000fd5b505050505b815115611f66576000611f3b6107e0565b915050611f483382613ac2565b611f645760405162461bcd60e51b81526004016108fa90614d1f565b505b5050965096945050505050565b60058054611f8090614aa7565b80601f0160208091040260200160405190810160405280929190818152602001828054611fac90614aa7565b8015611ff95780601f10611fce57610100808354040283529160200191611ff9565b820191906000526020600020905b815481529060010190602001808311611fdc57829003601f168201915b505050505081565b600061200b612a99565b8115612172576040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120999190614cdc565b60405162ae511b60e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152306024830181905260448301526001600160801b0383166064830152600060848301529194507f0000000000000000000000000000000000000000000000000000000000000000909116906302b9446c9060a40160408051808303816000875af1158015612147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216b91906151be565b5050612292565b604051636d289ce560e11b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0381811660048401526001600160801b0386166024840152600160448401527f0000000000000000000000000000000000000000000000000000000000000000169163f18d03cc919033903090859063da5139ca90606401602060405180830381865afa15801561221c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122409190614cdc565b6040518563ffffffff1660e01b815260040161225f9493929190614cf5565b600060405180830381600087803b15801561227957600080fd5b505af115801561228d573d6000803e3d6000fd5b505050505b6008546001600160801b0316683635c9adc5dea000006122b2858361523d565b6001600160801b0316116123085760405162461bcd60e51b815260206004820152601760248201527f546f74616c20456c617374696320746f6f20736d616c6c00000000000000000060448201526064016108fa565b612312848261523d565b600880546001600160801b0319166001600160801b0392831690811790915560408051878416815292841660208401528201527f205e179c3f9cd050c39f1a7f163e76d498f61757172cd2d7ec7097f4168246fe9060600160405180910390a1839150505b92915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ff9190614baa565b6001600160a01b0316336001600160a01b03161461242f5760405162461bcd60e51b81526004016108fa90614bc7565b604051633de222bb60e21b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0381811660048401523060248401526000927f00000000000000000000000000000000000000000000000000000000000000009190911691635662311891839063f7888aec90604401602060405180830381865afa1580156124ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ee9190614cdc565b60006040518463ffffffff1660e01b815260040161250e93929190614cb9565b602060405180830381865afa15801561252b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254f9190614cdc565b905081811161255e5780612560565b815b60405163097da6d360e41b81529092506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906397da6d30906125d8907f00000000000000000000000000000000000000000000000000000000000000009030903390889060009060040161525d565b60408051808303816000875af11580156125f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061261a91906151be565b50505050565b6001600160a01b038316600090815260096020526040902054612643908261423a565b6001600160a01b038416600090815260096020526040902055600754612669818361423a565b600755600354612684906001600160a01b0316838386614246565b836001600160a01b03168361269957336126bb565b7f00000000000000000000000000000000000000000000000000000000000000005b6001600160a01b03167f9ed03113de523cebfe5e49d5f8e12894b1c0d42ce805990461726444c90eab87846040516126f591815260200190565b60405180910390a350505050565b61270b612a99565b6127158282613c51565b600061271f6107e0565b91505061272c3382613ac2565b6109e25760405162461bcd60e51b81526004016108fa90614d1f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ca9190614baa565b6001600160a01b0316336001600160a01b0316146127fa5760405162461bcd60e51b81526004016108fa90614bc7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161415801561284557506001600160a01b0382163014155b6128825760405162461bcd60e51b815260206004820152600e60248201526d696e76616c69642063616c6c656560901b60448201526064016108fa565b6001600160a01b0382166000818152600b6020908152604091829020805460ff191685151590811790915591519182527fc5bd4365c17df9e09859dec0d4cd85d49349f6b2d710024a59a124925189615f910160405180910390a25050565b6000546001600160a01b0316331461293b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016108fa565b600280546001600160a01b0319166001600160a01b0383169081179091556040517fcf1d3f17e521c635e0d20b8acba94ba170afc041d0546d46dafa09d3c9c19eb390600090a250565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a079190614baa565b6001600160a01b0316336001600160a01b031614612a375760405162461bcd60e51b81526004016108fa90614bc7565b6040805180820182526001600160801b038481168083529084166020928301819052600160801b810282176006558351918252918101919091527ff1fce436bc22563026222b3b2bdc088cb69d25192974264114df12ab812628f69101610c21565b60408051606081018252600d546001600160401b038082168084526001600160801b03600160401b8404166020850152600160c01b909204169282019290925290600090612ae79042615291565b905080600003612af5575050565b6001600160401b0342168252604080518082019091526008546001600160801b038082168352600160801b9091041660208201819052600003612b8a5750508051600d805460208401516040909401516001600160401b03908116600160c01b026001600160c01b036001600160801b03909616600160401b026001600160c01b031990931691909416171792909216179055565b6000612bdc670de0b6b3a7640000612bcf85612bc988604001516001600160401b031687600001516001600160801b03166143c090919063ffffffff16565b906143c0565b612bd991906152a4565b90565b8251909150612bf4906001600160801b0316826143cc565b6001600160801b0390811683526020850151612c119116826143cc565b6001600160801b0390811660208681018290528451858201518416600160801b02908416176008558651600d80546040808b01516001600160401b03908116600160c01b026001600160c01b03600160401b9098026001600160c01b031990941691909516179190911794909416919091179055905191831682527fee527de5e142bcc7fe0eddc4b9a04816d73f6307dd74f9204585910d60a8c083910160405180910390a150505050565b6000612cc76107e0565b915050612cd2612a99565b600354604051634ffe34db60e01b81526001600160a01b0391821660048201526000918291829182917f000000000000000000000000000000000000000000000000000000000000000090911690634ffe34db906024016040805180830381865afa158015612d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6991906152b8565b905060005b8a51811015612ffc5760008b8281518110612d8b57612d8b614f07565b60200260200101519050612d9f8188613ac2565b612fe9576001600160a01b0381166000908152600a60205260408120548c5181908e9086908110612dd257612dd2614f07565b602002602001015111612dfe578c8481518110612df157612df1614f07565b6020026020010151612e00565b805b9150612e0c81836143d8565b6001600160a01b0384166000908152600a602090815260408083209390935582518084019093526008546001600160801b038082168552600160801b90910416908301529150612e5d9083836140f5565b90506000612ea5612e79670de0b6b3a7640000620186a0615316565b612e928c612bc9601054876143c090919063ffffffff16565b612e9c91906152a4565b87906000614193565b6001600160a01b038516600090815260096020526040902054909150612ecb90826143d8565b6001600160a01b0380861660008181526009602052604090819020939093559151908f1691907f8ad4d3ff00da092c7ad9a573ea4f5f6a3dffc6712dc06d3f78f49b862297c40290612f209085815260200190565b60405180910390a360408051838152602081018590526001600160a01b0386169133917fc8e512d8f188ca059984b5853d2bf653da902696b8512785b182b2c813789a6e910160405180910390a360408051828152602081018490529081018490526001600160a01b03808f16919086169033907f66b108dc29b952efc76dccea9b82dce6b59fab4d9af73d8dcc9789afcad5daf69060600160405180910390a4612fcb898261423a565b9850612fd7888361423a565b9750612fe3878461423a565b96505050505b5080612ff481615224565b915050612d6e565b508260000361304d5760405162461bcd60e51b815260206004820152601960248201527f4361756c64726f6e3a20616c6c2061726520736f6c76656e740000000000000060448201526064016108fa565b613063836008546001600160801b0316906143e4565b600880546001600160801b0319166001600160801b03928316179081905561309491600160801b90910416836143e4565b600880546001600160801b03928316600160801b0292169190911790556007546130be90856143d8565b600781905550600060646130fa600a612bc987620186a06130ea6010548b6143c090919063ffffffff16565b6130f491906152a4565b906143d8565b61310491906152a4565b9050613110848261423a565b935061312f81600d54600160401b90046001600160801b0316906143cc565b600d80546001600160801b0392909216600160401b02600160401b600160c01b031990921691909117905550604051636d289ce560e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063da5139ca906131cf907f0000000000000000000000000000000000000000000000000000000000000000908890600190600401614cb9565b602060405180830381865afa1580156131ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132109190614cdc565b600354604051633c6340f360e21b81529192506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169263f18d03cc9261326992169030908e908b90600401614cf5565b600060405180830381600087803b15801561328357600080fd5b505af1158015613297573d6000803e3d6000fd5b505050506001600160a01b0388161561334b5760035460405163a5d4096b60e01b81526001600160a01b038a81169263a5d4096b9261330692909116907f000000000000000000000000000000000000000000000000000000000000000090339087908c908f90600401615335565b60408051808303816000875af1158015613324573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061334891906151be565b50505b604051636d289ce560e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063da5139ca906133bc907f0000000000000000000000000000000000000000000000000000000000000000908890600190600401614cb9565b602060405180830381865afa1580156133d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133fd9190614cdc565b604051633c6340f360e21b81529091506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f18d03cc90613472907f000000000000000000000000000000000000000000000000000000000000000090339030908790600401614cf5565b600060405180830381600087803b15801561348c57600080fd5b505af11580156134a0573d6000803e3d6000fd5b505050505050505050505050505050565b604080518082019091526008546001600160801b038082168352600160801b9091041660208201526000906134e8908360016143f0565b81516020928301516001600160801b03908116600160801b029116176008556001600160a01b0386166000908152600a90925260409091205490915061352e90836143d8565b6001600160a01b038086166000908152600a6020526040808220939093559151636d289ce560e11b81527f00000000000000000000000000000000000000000000000000000000000000009091169063da5139ca906135b6907f0000000000000000000000000000000000000000000000000000000000000000908690600190600401614cb9565b602060405180830381865afa1580156135d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f79190614cdc565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f18d03cc7f0000000000000000000000000000000000000000000000000000000000000000866136545733613676565b7f00000000000000000000000000000000000000000000000000000000000000005b30856040518563ffffffff1660e01b81526004016136979493929190614cf5565b600060405180830381600087803b1580156136b157600080fd5b505af11580156136c5573d6000803e3d6000fd5b50505050846001600160a01b0316846136de5733613700565b7f00000000000000000000000000000000000000000000000000000000000000005b6001600160a01b03167fc8e512d8f188ca059984b5853d2bf653da902696b8512785b182b2c813789a6e8486604051613743929190918252602082015260400190565b60405180910390a3509392505050565b6000806000620186a0613771601154866143c090919063ffffffff16565b61377b91906152a4565b90506137ba61378a858361423a565b604080518082019091526008546001600160801b038082168352600160801b909104166020820152906001614459565b81516020928301516001600160801b03908116600160801b908102928216838117600855604080518082019091526006548085168083529390048416968101969096529397509116909117111561384a5760405162461bcd60e51b8152602060048201526014602482015273109bdc9c9bddc8131a5b5a5d081c995858da195960621b60448201526064016108fa565b600d5461386790600160401b90046001600160801b0316836143cc565b600d80546001600160801b0392909216600160401b02600160401b600160c01b0319909216919091179055336000908152600a60205260408120546138ac908661423a565b905081602001516001600160801b03168111156139025760405162461bcd60e51b8152602060048201526014602482015273109bdc9c9bddc8131a5b5a5d081c995858da195960621b60448201526064016108fa565b336000908152600a602052604080822083905551636d289ce560e11b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163da5139ca91613982917f0000000000000000000000000000000000000000000000000000000000000000918b9190600401614cb9565b602060405180830381865afa15801561399f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139c39190614cdc565b604051633c6340f360e21b81529094506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f18d03cc90613a38907f00000000000000000000000000000000000000000000000000000000000000009030908c908a90600401614cf5565b600060405180830381600087803b158015613a5257600080fd5b505af1158015613a66573d6000803e3d6000fd5b5050506001600160a01b0388169050337fb92cb6bca8e3270b9170930f03b17571e55791acdb1a0e9f339eec88bdb35e24613aa1898761423a565b60408051918252602082018a90520160405180910390a35050509250929050565b6001600160a01b0382166000908152600a6020526040812054808203613aec576001915050612377565b6001600160a01b03841660009081526009602052604081205490819003613b1857600092505050612377565b604080518082019091526008546001600160801b03808216808452600160801b909204166020830181905290613b55908790612bc99087906143c0565b613b5f91906152a4565b600354600f546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811692635662311892911690613bbd90612bc9613bb6620186a0670de0b6b3a76400006152a4565b89906143c0565b60006040518463ffffffff1660e01b8152600401613bdd93929190614cb9565b602060405180830381865afa158015613bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1e9190614cdc565b10159695505050505050565b600080841215613c49576000198414613c4357816109fc565b826109fc565b509192915050565b33600090815260096020526040902054613c6b90826143d8565b33600090815260096020526040902055600754613c8890826143d8565b6007556040518181526001600160a01b0383169033907f8ad4d3ff00da092c7ad9a573ea4f5f6a3dffc6712dc06d3f78f49b862297c4029060200160405180910390a3600354604051633c6340f360e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169263f18d03cc92613d24929190911690309087908790600401614cf5565b600060405180830381600087803b158015613d3e57600080fd5b505af1158015613d52573d6000803e3d6000fd5b505050505050565b60008060008060008089806020019051810190613d779190615383565b9350935093509350613d8a828989613c2a565b9150613d97818989613c2a565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166302b9446c8a86338787876040518763ffffffff1660e01b8152600401613dee95949392919061525d565b604080518083038185885af1158015613e0b573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613e3091906151be565b955095505050505094509492505050565b60008060008060008088806020019051810190613e5e9190615383565b93509350935093507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166397da6d30853386613ea3878e8e613c2a565b613eae878f8f613c2a565b6040518663ffffffff1660e01b8152600401613ece95949392919061525d565b60408051808303816000875af1158015613eec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f1091906151be565b9550955050505050935093915050565b606060008060008060008089806020019051810190613f3f91906153d6565b94509450945094509450828015613f54575081155b15613f82578389604051602001613f6c929190615493565b6040516020818303038152906040529350613fdb565b82158015613f8d5750815b15613fa5578388604051602001613f6c929190615493565b828015613faf5750815b15613fdb57838989604051602001613fc9939291906154b5565b60405160208183030381529060405293505b6001600160a01b0385166000908152600b602052604090205460ff161561403b5760405162461bcd60e51b815260206004820152601460248201527310d85d5b191c9bdb8e8818d85b89dd0818d85b1b60621b60448201526064016108fa565b600080866001600160a01b03168d8760405161405791906154dc565b60006040518083038185875af1925050503d8060008114614094576040519150601f19603f3d011682016040523d82523d6000602084013e614099565b606091505b5091509150816140e35760405162461bcd60e51b815260206004820152601560248201527410d85d5b191c9bdb8e8818d85b1b0819985a5b1959605a1b60448201526064016108fa565b9c919b50909950505050505050505050565b600083602001516001600160801b031660000361411357508161418c565b602084015184516001600160801b0391821691614131911685615316565b61413b91906152a4565b905081801561417957508284600001516001600160801b031685602001516001600160801b03168361416d9190615316565b61417791906152a4565b105b1561418c578061418881615224565b9150505b9392505050565b82516000906001600160801b031681036141ae57508161418c565b835160208501516001600160801b03918216916141cc911685615316565b6141d691906152a4565b905081801561417957508284602001516001600160801b031685600001516001600160801b03168361416d9190615316565b60008080808061421a868801886149f6565b945094509450945094506142318585858585612cbd565b50505050505050565b600061418c8284614ca6565b801561433657604051633de222bb60e21b81526001600160a01b0385811660048301523060248301526142e29184917f0000000000000000000000000000000000000000000000000000000000000000169063f7888aec90604401602060405180830381865afa1580156142be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f49190614cdc565b8311156143315760405162461bcd60e51b815260206004820152601760248201527f4361756c64726f6e3a20536b696d20746f6f206d75636800000000000000000060448201526064016108fa565b61261a565b604051633c6340f360e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f18d03cc90614388908790339030908990600401614cf5565b600060405180830381600087803b1580156143a257600080fd5b505af11580156143b6573d6000803e3d6000fd5b5050505050505050565b600061418c8284615316565b600061418c82846154f8565b600061418c8284615291565b600061418c828461523d565b604080518082019091526000808252602082015260006144118585856140f5565b90508085600001818151614425919061523d565b6001600160801b031690525060208501805185919061444590839061523d565b6001600160801b0316905250939492505050565b6040805180820190915260008082526020820152600061447a858585614193565b9050838560000181815161448e91906154f8565b6001600160801b03169052506020850180518291906144459083906154f8565b6001600160a01b03811681146144c357600080fd5b50565b80151581146144c357600080fd5b6000806000606084860312156144e957600080fd5b83356144f4816144ae565b92506020840135614504816144c6565b91506040840135614514816144c6565b809150509250925092565b60008060006060848603121561453457600080fd5b833561453f816144ae565b9250602084013561454f816144c6565b929592945050506040919091013590565b60006020828403121561457257600080fd5b813561418c816144ae565b6001600160401b03811681146144c357600080fd5b6000602082840312156145a457600080fd5b813561418c8161457d565b600080604083850312156145c257600080fd5b82356145cd816144ae565b946020939093013593505050565b600080602083850312156145ee57600080fd5b82356001600160401b038082111561460557600080fd5b818501915085601f83011261461957600080fd5b81358181111561462857600080fd5b86602082850101111561463a57600080fd5b60209290920196919550909350505050565b60008083601f84011261465e57600080fd5b5081356001600160401b0381111561467557600080fd5b6020830191508360208260051b850101111561469057600080fd5b9250929050565b600080600080600080606087890312156146b057600080fd5b86356001600160401b03808211156146c757600080fd5b6146d38a838b0161464c565b909850965060208901359150808211156146ec57600080fd5b6146f88a838b0161464c565b9096509450604089013591508082111561471157600080fd5b5061471e89828a0161464c565b979a9699509497509295939492505050565b60005b8381101561474b578181015183820152602001614733565b50506000910152565b6000815180845261476c816020860160208601614730565b601f01601f19169290920160200192915050565b60208152600061418c6020830184614754565b6001600160801b03811681146144c357600080fd5b600080604083850312156147bb57600080fd5b82356147c681614793565b915060208301356147d6816144c6565b809150509250929050565b6000602082840312156147f357600080fd5b5035919050565b6000806040838503121561480d57600080fd5b82356147c6816144ae565b6000806040838503121561482b57600080fd5b823561483681614793565b915060208301356147d681614793565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561488457614884614846565b604052919050565b60006001600160401b038211156148a5576148a5614846565b5060051b60200190565b600082601f8301126148c057600080fd5b813560206148d56148d08361488c565b61485c565b82815260059290921b840181019181810190868411156148f457600080fd5b8286015b8481101561491857803561490b816144ae565b83529183019183016148f8565b509695505050505050565b600082601f83011261493457600080fd5b813560206149446148d08361488c565b82815260059290921b8401810191818101908684111561496357600080fd5b8286015b848110156149185780358352918301918301614967565b60006001600160401b0382111561499757614997614846565b50601f01601f191660200190565b600082601f8301126149b657600080fd5b81356149c46148d08261497e565b8181528460208386010111156149d957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215614a0e57600080fd5b85356001600160401b0380821115614a2557600080fd5b614a3189838a016148af565b96506020880135915080821115614a4757600080fd5b614a5389838a01614923565b955060408801359150614a65826144ae565b909350606087013590614a77826144ae565b90925060808701359080821115614a8d57600080fd5b50614a9a888289016149a5565b9150509295509295909350565b600181811c90821680614abb57607f821691505b602082108103614adb57634e487b7160e01b600052602260045260246000fd5b50919050565b6000602080835260008454614af581614aa7565b80848701526040600180841660008114614b165760018114614b3057614b5e565b60ff1985168984015283151560051b890183019550614b5e565b896000528660002060005b85811015614b565781548b8201860152908301908801614b3b565b8a0184019650505b509398975050505050505050565b8051614b77816144c6565b919050565b60008060408385031215614b8f57600080fd5b8251614b9a816144c6565b6020939093015192949293505050565b600060208284031215614bbc57600080fd5b815161418c816144ae565b60208082526017908201527f43616c6c6572206973206e6f7420746865206f776e6572000000000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60006001600160401b0380831681851681830481118215151615614c3a57614c3a614bfe565b02949350505050565b634e487b7160e01b600052601260045260246000fd5b60006001600160401b0380841680614c7357614c73614c43565b92169190910492915050565b6001600160401b03818116838216019080821115614c9f57614c9f614bfe565b5092915050565b8082018082111561237757612377614bfe565b6001600160a01b0393909316835260208301919091521515604082015260600190565b600060208284031215614cee57600080fd5b5051919050565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b60208082526018908201527f4361756c64726f6e3a207573657220696e736f6c76656e740000000000000000604082015260600190565b600080600080600080600060e0888a031215614d7157600080fd5b8735614d7c816144ae565b96506020880135614d8c816144ae565b955060408801356001600160401b03811115614da757600080fd5b614db38a828b016149a5565b9550506060880135614dc48161457d565b9699959850939660808101359560a0820135955060c0909101359350915050565b601f8211156109e257600081815260208120601f850160051c81016020861015614e0c5750805b601f850160051c820191505b81811015613d5257828155600101614e18565b81516001600160401b03811115614e4457614e44614846565b614e5881614e528454614aa7565b84614de5565b602080601f831160018114614e8d5760008415614e755750858301515b600019600386901b1c1916600185901b178555613d52565b600085815260208120601f198616915b82811015614ebc57888601518255948401946001909101908401614e9d565b5085821015614eda5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215614efc57600080fd5b815161418c816144c6565b634e487b7160e01b600052603260045260246000fd5b60ff811681146144c357600080fd5b600060208284031215614f3e57600080fd5b813561418c81614f1d565b6000808335601e19843603018112614f6057600080fd5b8301803591506001600160401b03821115614f7a57600080fd5b60200191503681900382131561469057600080fd5b600080600060608486031215614fa457600080fd5b833592506020840135614504816144ae565b60008060408385031215614fc957600080fd5b8235915060208301356147d6816144ae565b600080600060608486031215614ff057600080fd5b8335614ffb816144c6565b95602085013595506040909401359392505050565b60008060008060008060c0878903121561502957600080fd5b8635615034816144ae565b95506020870135615044816144ae565b94506040870135615054816144c6565b9350606087013561506481614f1d565b9598949750929560808101359460a0909101359350915050565b60008060006060848603121561509357600080fd5b833561509e816144ae565b9250602084013561454f816144ae565b6000806000606084860312156150c357600080fd5b83356150ce816144ae565b925060208401356001600160401b03808211156150ea57600080fd5b6150f6878388016148af565b9350604086013591508082111561510c57600080fd5b5061511986828701614923565b9150509250925092565b60006080820160018060a01b0380881684526020818816818601526080604086015282875180855260a087019150828901945060005b81811015615177578551851683529483019491830191600101615159565b5050858103606087015286518082529082019350915080860160005b838110156151af57815185529382019390820190600101615193565b50929998505050505050505050565b600080604083850312156151d157600080fd5b505080516020909101519092909150565b6000806000606084860312156151f757600080fd5b83516152028161457d565b60208501519093506152138161457d565b604085015190925061451481614793565b60006001820161523657615236614bfe565b5060010190565b6001600160801b03828116828216039080821115614c9f57614c9f614bfe565b6001600160a01b03958616815293851660208501529190931660408301526060820192909252608081019190915260a00190565b8181038181111561237757612377614bfe565b6000826152b3576152b3614c43565b500490565b6000604082840312156152ca57600080fd5b604051604081018181106001600160401b03821117156152ec576152ec614846565b60405282516152fa81614793565b8152602083015161530a81614793565b60208201529392505050565b600081600019048311821515161561533057615330614bfe565b500290565b6001600160a01b038781168252868116602083015285166040820152606081018490526080810183905260c060a0820181905260009061537790830184614754565b98975050505050505050565b6000806000806080858703121561539957600080fd5b84516153a4816144ae565b60208601519094506153b5816144ae565b6040860151606090960151949790965092505050565b8051614b7781614f1d565b600080600080600060a086880312156153ee57600080fd5b85516153f9816144ae565b60208701519095506001600160401b0381111561541557600080fd5b8601601f8101881361542657600080fd5b80516154346148d08261497e565b81815289602083850101111561544957600080fd5b61545a826020830160208601614730565b955061546b91505060408701614b6c565b925061547960608701614b6c565b9150615487608087016153cb565b90509295509295909350565b600083516154a5818460208801614730565b9190910191825250602001919050565b600084516154c7818460208901614730565b91909101928352506020820152604001919050565b600082516154ee818460208701614730565b9190910192915050565b6001600160801b03818116838216019080821115614c9f57614c9f614bfe56fea2646970667358221220e8c207325426aae66c4d768daaf824232f34e431a0ac5b23162260dacc8cbbdb64736f6c63430008100033000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f3
Deployed Bytecode
0x6080604052600436106102255760003560e01c80638062344411610123578063cb0dc548116100ab578063eeae797b1161006f578063eeae797b1461074b578063f46901ed1461076b578063f7dad4341461078b578063f8ba4cff146107ab578063ff6ff84b146107c057600080fd5b8063cb0dc5481461066c578063cd446e22146106ac578063d8dfeb45146106e0578063e30c397814610700578063e551d11d1461072057600080fd5b80638da5cb5b116100f25780638da5cb5b1461057d5780639b352ae11461059d578063aba024f4146105d1578063b27c0e74146105e7578063c7ee2a7b1461065657600080fd5b806380623444146104d25780638285ef40146104f2578063860ffea11461053d578063876467f81461055d57600080fd5b806348e4163e116101b15780636b2ace87116101755780636b2ace871461040e5780636ec097fb1461044257806374645ff3146104585780637dc0d1d01461047a5780637ef404551461049a57600080fd5b806348e4163e146103715780634b8a35291461039e5780634ddf47d4146103d35780634e71e0c8146103e6578063656f3d64146103fb57600080fd5b80631c9e379b116101f85780631c9e379b146102e35780631cd4c966146103105780633ba0b9a914610330578063473e3ce714610346578063476343ee1461035c57600080fd5b8063017e7e581461022a57806302ce728f14610267578063078dfbe71461029357806315294c40146102b5575b600080fd5b34801561023657600080fd5b5060025461024a906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561027357600080fd5b5061027c6107e0565b60408051921515835260208301919091520161025e565b34801561029f57600080fd5b506102b36102ae3660046144d4565b6108a4565b005b3480156102c157600080fd5b506102d56102d036600461451f565b6109e7565b60405190815260200161025e565b3480156102ef57600080fd5b506102d56102fe366004614560565b60096020526000908152604090205481565b34801561031c57600080fd5b506102b361032b366004614592565b610a04565b34801561033c57600080fd5b506102d5600c5481565b34801561035257600080fd5b506102d560075481565b34801561036857600080fd5b506102b3610c2d565b34801561037d57600080fd5b506102d561038c366004614560565b600a6020526000908152604090205481565b3480156103aa57600080fd5b506103be6103b93660046145af565b610e81565b6040805192835260208301919091520161025e565b6102b36103e13660046145db565b610ed6565b3480156103f257600080fd5b506102b3611231565b6103be610409366004614697565b6112ee565b34801561041a57600080fd5b5061024a7f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce81565b34801561044e57600080fd5b506102d560105481565b34801561046457600080fd5b5061046d611f73565b60405161025e9190614780565b34801561048657600080fd5b5060045461024a906001600160a01b031681565b3480156104a657600080fd5b506104ba6104b53660046147a8565b612001565b6040516001600160801b03909116815260200161025e565b3480156104de57600080fd5b506102b36104ed3660046147e1565b61237d565b3480156104fe57600080fd5b5060085461051d906001600160801b0380821691600160801b90041682565b604080516001600160801b0393841681529290911660208301520161025e565b34801561054957600080fd5b506102b361055836600461451f565b612620565b34801561056957600080fd5b506102b36105783660046145af565b612703565b34801561058957600080fd5b5060005461024a906001600160a01b031681565b3480156105a957600080fd5b5061024a7f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f381565b3480156105dd57600080fd5b506102d560115481565b3480156105f357600080fd5b50600d54610624906001600160401b03808216916001600160801b03600160401b82041691600160c01b9091041683565b604080516001600160401b0394851681526001600160801b03909316602084015292169181019190915260600161025e565b34801561066257600080fd5b506102d5600f5481565b34801561067857600080fd5b5061069c610687366004614560565b600b6020526000908152604090205460ff1681565b604051901515815260200161025e565b3480156106b857600080fd5b5061024a7f00000000000000000000000043243f7bddcb850acb687c42bbf5066c224054a581565b3480156106ec57600080fd5b5060035461024a906001600160a01b031681565b34801561070c57600080fd5b5060015461024a906001600160a01b031681565b34801561072c57600080fd5b5060065461051d906001600160801b0380821691600160801b90041682565b34801561075757600080fd5b506102b36107663660046147fa565b612748565b34801561077757600080fd5b506102b3610786366004614560565b6128e1565b34801561079757600080fd5b506102b36107a6366004614818565b612985565b3480156107b757600080fd5b506102b3612a99565b3480156107cc57600080fd5b506102b36107db3660046149f6565b612cbd565b6004805460405163d6d7d52560e01b815260009283926001600160a01b03169163d6d7d525916108139160059101614ae1565b60408051808303816000875af1158015610831573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108559190614b7c565b9092509050811561089c57600c8190556040518181527f9f9192b5edb17356c524e08d9e025c8e2f6307e6ea52fb7968faa3081f51c3c89060200160405180910390a19091565b50600c549091565b6000546001600160a01b031633146109035760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b81156109c6576001600160a01b03831615158061091d5750805b6109615760405162461bcd60e51b81526020600482015260156024820152744f776e61626c653a207a65726f206164647265737360581b60448201526064016108fa565b600080546040516001600160a01b03808716939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0385166001600160a01b031991821617909155600180549091169055505050565b600180546001600160a01b0319166001600160a01b0385161790555b505050565b60006109f1612a99565b6109fc8484846134b1565b949350505050565b7f00000000000000000000000043243f7bddcb850acb687c42bbf5066c224054a56001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a869190614baa565b6001600160a01b0316336001600160a01b031614610ab65760405162461bcd60e51b81526004016108fa90614bc7565b600d54600160c01b90046001600160401b03166004610ad6826003614c14565b610ae09190614c59565b610aea9082614c7f565b6001600160401b0316826001600160401b03161080610b1657506312e687c06001600160401b03831611155b610b625760405162461bcd60e51b815260206004820152601c60248201527f496e746572657374207261746520696e637265617365203e203735250000000060448201526064016108fa565b42600e546203f480610b749190614ca6565b10610bc15760405162461bcd60e51b815260206004820152601860248201527f557064617465206f6e6c7920657665727920332064617973000000000000000060448201526064016108fa565b42600e55600d80546001600160c01b0316600160c01b6001600160401b038581169182029290921790925560408051918416825260208201929092527f76bc92b92b7755bcb03b25070431a80435c4d3fbf91c6c81c0c0cc350f6b5c6a91015b60405180910390a15050565b610c35612a99565b60007f00000000000000000000000043243f7bddcb850acb687c42bbf5066c224054a56001600160a01b031663017e7e586040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cb99190614baa565b600d54604051636d289ce560e11b8152919250600160401b90046001600160801b0316906000907f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b03169063da5139ca90610d43907f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f39086908690600401614cb9565b602060405180830381865afa158015610d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d849190614cdc565b604051633c6340f360e21b81529091506001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce169063f18d03cc90610df9907f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f390309088908790600401614cf5565b600060405180830381600087803b158015610e1357600080fd5b505af1158015610e27573d6000803e3d6000fd5b5050600d8054600160401b600160c01b031916905550506040518281526001600160a01b038416907fbe641c3ffc44b2d6c184f023fa4ed7bda4b6ffa71e03b3c98ae0c776da1f17e79060200160405180910390a2505050565b600080610e8c612a99565b610e968484613753565b90925090506000610ea56107e0565b915050610eb23382613ac2565b610ece5760405162461bcd60e51b81526004016108fa90614d1f565b509250929050565b6003546001600160a01b031615610f2f5760405162461bcd60e51b815260206004820152601d60248201527f4361756c64726f6e3a20616c726561647920696e697469616c697a656400000060448201526064016108fa565b610f3b81830183614d56565b6011819055600f8290556010839055600d80546001600160c01b0316600160c01b6001600160401b03871602179055600360006004816005610f7d8a82614e2b565b50815461010091820a6001600160a01b03818102199092169b8216029a909a17909155825491900a8089021990911698881602979097179096555050604080518082019091526001600160801b0380825260209091015250506000196006556003541690506110235760405162461bcd60e51b815260206004820152601260248201527121b0bab6323937b71d103130b2103830b4b960711b60448201526064016108fa565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce8116600483015260001960248301527f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f3169063095ea7b3906044016020604051808303816000875af11580156110b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110d79190614eea565b506004805460405163d6d7d52560e01b81526001600160a01b039091169163d6d7d525916111089160059101614ae1565b60408051808303816000875af1158015611126573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114a9190614b7c565b600c55507f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b03166000818152600b602081815260408084208054600160ff1991821681179092553086528286208054909116821790558151638da5cb5b60e01b81529151909593949392638da5cb5b92600480820193918290030181865afa1580156111e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112059190614baa565b6001600160a01b031681526020810191909152604001600020805460ff19169115159190911790555050565b6001546001600160a01b031633811461128c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c657220213d2070656e64696e67206f776e657260448201526064016108fa565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b604080518082019091526000808252602082018190529081906001600160401b0360005b89811015611e295760008b8b8381811061132e5761132e614f07565b90506020020160208101906113439190614f2c565b9050836020015115801561135a5750600a8160ff16105b1561136f57611367612a99565b600160208501525b60091960ff8216016113cf5760008060008a8a8681811061139257611392614f07565b90506020028101906113a49190614f49565b8101906113b19190614f8f565b9250925092506113c78282610558868d8d613c2a565b505050611e16565b60011960ff8216016114355760008060008a8a868181106113f2576113f2614f07565b90506020028101906114049190614f49565b8101906114119190614f8f565b92509250925061142c8282611427868d8d613c2a565b6134b1565b50505050611e16565b60031960ff8216016114985760008089898581811061145657611456614f07565b90506020028101906114689190614f49565b8101906114759190614fb6565b9150915061148d81611488848b8b613c2a565b613c51565b505060018452611e16565b60041960ff821601611501576000808989858181106114b9576114b9614f07565b90506020028101906114cb9190614f49565b8101906114d89190614fb6565b915091506114f0816114eb848b8b613c2a565b613753565b600188529098509650611e16915050565b600a1960ff8216016115ce5760008060008a8a8681811061152457611524614f07565b90506020028101906115369190614f49565b8101906115439190614fdb565b9250925092506000806115546107e0565b915091508415806115625750815b801561156d57508381115b8015611580575082158061158057508281115b6115c45760405162461bcd60e51b81526020600482015260156024820152744361756c64726f6e3a2072617465206e6f74206f6b60581b60448201526064016108fa565b5050505050611e16565b60171960ff8216016116d3576000806000806000808d8d898181106115f5576115f5614f07565b90506020028101906116079190614f49565b8101906116149190615010565b60405163c0a47c9360e01b81526001600160a01b0387811660048301528681166024830152851515604483015260ff851660648301526084820184905260a48201839052969c50949a50929850909650945092507f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce9091169063c0a47c939060c401600060405180830381600087803b1580156116b057600080fd5b505af11580156116c4573d6000803e3d6000fd5b50505050505050505050611e16565b60131960ff8216016117675761175d8888848181106116f4576116f4614f07565b90506020028101906117069190614f49565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508e92508d915086905081811061174f5761174f614f07565b905060200201358888613d5a565b9096509450611e16565b60141960ff8216016117d85761175d88888481811061178857611788614f07565b905060200281019061179a9190614f49565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508a9250899150613e419050565b60151960ff8216016118b65760008060008a8a868181106117fb576117fb614f07565b905060200281019061180d9190614f49565b81019061181a919061507e565b9250925092507f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b031663f18d03cc84338561185d868f8f613c2a565b6040518563ffffffff1660e01b815260040161187c9493929190614cf5565b600060405180830381600087803b15801561189657600080fd5b505af11580156118aa573d6000803e3d6000fd5b50505050505050611e16565b60161960ff8216016119505760008060008a8a868181106118d9576118d9614f07565b90506020028101906118eb9190614f49565b8101906118f891906150ae565b9250925092507f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b0316630fca8843843385856040518563ffffffff1660e01b815260040161187c9493929190615123565b601d1960ff821601611a33576000806119dd8c8c8681811061197457611974614f07565b905060200201358b8b8781811061198d5761198d614f07565b905060200281019061199f9190614f49565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508d92508c9150613f209050565b915091508060ff16600103611a075781806020019051810190611a009190614cdc565b9750611a2c565b8060ff16600203611a2c5781806020019051810190611a2691906151be565b90985096505b5050611e16565b60051960ff821601611b6b576000888884818110611a5357611a53614f07565b9050602002810190611a659190614f49565b810190611a7291906147e1565b90507f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b031663da5139ca7f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f3611b02611ad2858c8c613c2a565b604080518082019091526008546001600160801b038082168352600160801b9091041660208201529060016140f5565b60016040518463ffffffff1660e01b8152600401611b2293929190614cb9565b602060405180830381865afa158015611b3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b639190614cdc565b965050611e16565b60061960ff821601611bea576000888884818110611b8b57611b8b614f07565b9050602002810190611b9d9190614f49565b810190611baa91906147e1565b9050611b63611bba828989613c2a565b604080518082019091526008546001600160801b038082168352600160801b909104166020820152906000614193565b601e1960ff821601611c2757611c22888884818110611c0b57611c0b614f07565b9050602002810190611c1d9190614f49565b614208565b611e16565b60201960ff821601611e16576001600160401b0383811614611c975760405162461bcd60e51b815260206004820152602360248201527f4361756c64726f6e3a20737472617465677920616c72656164792072656c65616044820152621cd95960ea1b60648201526084016108fa565b60035460405163df23b45b60e01b81526001600160a01b0391821660048201527f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce9091169063df23b45b90602401606060405180830381865afa158015611d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d2691906151e2565b90915050809350507f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db09190614baa565b600354604051638483a07760e01b81526001600160a01b03918216600482015260006024820152911690638483a07790604401600060405180830381600087803b158015611dfd57600080fd5b505af1158015611e11573d6000803e3d6000fd5b505050505b5080611e2181615224565b915050611312565b506001600160401b0381811614611f2a577f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ebc9190614baa565b600354604051638483a07760e01b81526001600160a01b0391821660048201526001600160401b0384166024820152911690638483a07790604401600060405180830381600087803b158015611f1157600080fd5b505af1158015611f25573d6000803e3d6000fd5b505050505b815115611f66576000611f3b6107e0565b915050611f483382613ac2565b611f645760405162461bcd60e51b81526004016108fa90614d1f565b505b5050965096945050505050565b60058054611f8090614aa7565b80601f0160208091040260200160405190810160405280929190818152602001828054611fac90614aa7565b8015611ff95780601f10611fce57610100808354040283529160200191611ff9565b820191906000526020600020905b815481529060010190602001808311611fdc57829003601f168201915b505050505081565b600061200b612a99565b8115612172576040516370a0823160e01b81523060048201527f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f36001600160a01b0316906370a0823190602401602060405180830381865afa158015612075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120999190614cdc565b60405162ae511b60e21b81526001600160a01b037f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f381166004830152306024830181905260448301526001600160801b0383166064830152600060848301529194507f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce909116906302b9446c9060a40160408051808303816000875af1158015612147573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061216b91906151be565b5050612292565b604051636d289ce560e11b81527f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f36001600160a01b0381811660048401526001600160801b0386166024840152600160448401527f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce169163f18d03cc919033903090859063da5139ca90606401602060405180830381865afa15801561221c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122409190614cdc565b6040518563ffffffff1660e01b815260040161225f9493929190614cf5565b600060405180830381600087803b15801561227957600080fd5b505af115801561228d573d6000803e3d6000fd5b505050505b6008546001600160801b0316683635c9adc5dea000006122b2858361523d565b6001600160801b0316116123085760405162461bcd60e51b815260206004820152601760248201527f546f74616c20456c617374696320746f6f20736d616c6c00000000000000000060448201526064016108fa565b612312848261523d565b600880546001600160801b0319166001600160801b0392831690811790915560408051878416815292841660208401528201527f205e179c3f9cd050c39f1a7f163e76d498f61757172cd2d7ec7097f4168246fe9060600160405180910390a1839150505b92915050565b7f00000000000000000000000043243f7bddcb850acb687c42bbf5066c224054a56001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ff9190614baa565b6001600160a01b0316336001600160a01b03161461242f5760405162461bcd60e51b81526004016108fa90614bc7565b604051633de222bb60e21b81527f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f36001600160a01b0381811660048401523060248401526000927f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce9190911691635662311891839063f7888aec90604401602060405180830381865afa1580156124ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ee9190614cdc565b60006040518463ffffffff1660e01b815260040161250e93929190614cb9565b602060405180830381865afa15801561252b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254f9190614cdc565b905081811161255e5780612560565b815b60405163097da6d360e41b81529092506001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce16906397da6d30906125d8907f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f39030903390889060009060040161525d565b60408051808303816000875af11580156125f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061261a91906151be565b50505050565b6001600160a01b038316600090815260096020526040902054612643908261423a565b6001600160a01b038416600090815260096020526040902055600754612669818361423a565b600755600354612684906001600160a01b0316838386614246565b836001600160a01b03168361269957336126bb565b7f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce5b6001600160a01b03167f9ed03113de523cebfe5e49d5f8e12894b1c0d42ce805990461726444c90eab87846040516126f591815260200190565b60405180910390a350505050565b61270b612a99565b6127158282613c51565b600061271f6107e0565b91505061272c3382613ac2565b6109e25760405162461bcd60e51b81526004016108fa90614d1f565b7f00000000000000000000000043243f7bddcb850acb687c42bbf5066c224054a56001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156127a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ca9190614baa565b6001600160a01b0316336001600160a01b0316146127fa5760405162461bcd60e51b81526004016108fa90614bc7565b7f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b0316826001600160a01b03161415801561284557506001600160a01b0382163014155b6128825760405162461bcd60e51b815260206004820152600e60248201526d696e76616c69642063616c6c656560901b60448201526064016108fa565b6001600160a01b0382166000818152600b6020908152604091829020805460ff191685151590811790915591519182527fc5bd4365c17df9e09859dec0d4cd85d49349f6b2d710024a59a124925189615f910160405180910390a25050565b6000546001600160a01b0316331461293b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016108fa565b600280546001600160a01b0319166001600160a01b0383169081179091556040517fcf1d3f17e521c635e0d20b8acba94ba170afc041d0546d46dafa09d3c9c19eb390600090a250565b7f00000000000000000000000043243f7bddcb850acb687c42bbf5066c224054a56001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a079190614baa565b6001600160a01b0316336001600160a01b031614612a375760405162461bcd60e51b81526004016108fa90614bc7565b6040805180820182526001600160801b038481168083529084166020928301819052600160801b810282176006558351918252918101919091527ff1fce436bc22563026222b3b2bdc088cb69d25192974264114df12ab812628f69101610c21565b60408051606081018252600d546001600160401b038082168084526001600160801b03600160401b8404166020850152600160c01b909204169282019290925290600090612ae79042615291565b905080600003612af5575050565b6001600160401b0342168252604080518082019091526008546001600160801b038082168352600160801b9091041660208201819052600003612b8a5750508051600d805460208401516040909401516001600160401b03908116600160c01b026001600160c01b036001600160801b03909616600160401b026001600160c01b031990931691909416171792909216179055565b6000612bdc670de0b6b3a7640000612bcf85612bc988604001516001600160401b031687600001516001600160801b03166143c090919063ffffffff16565b906143c0565b612bd991906152a4565b90565b8251909150612bf4906001600160801b0316826143cc565b6001600160801b0390811683526020850151612c119116826143cc565b6001600160801b0390811660208681018290528451858201518416600160801b02908416176008558651600d80546040808b01516001600160401b03908116600160c01b026001600160c01b03600160401b9098026001600160c01b031990941691909516179190911794909416919091179055905191831682527fee527de5e142bcc7fe0eddc4b9a04816d73f6307dd74f9204585910d60a8c083910160405180910390a150505050565b6000612cc76107e0565b915050612cd2612a99565b600354604051634ffe34db60e01b81526001600160a01b0391821660048201526000918291829182917f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce90911690634ffe34db906024016040805180830381865afa158015612d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6991906152b8565b905060005b8a51811015612ffc5760008b8281518110612d8b57612d8b614f07565b60200260200101519050612d9f8188613ac2565b612fe9576001600160a01b0381166000908152600a60205260408120548c5181908e9086908110612dd257612dd2614f07565b602002602001015111612dfe578c8481518110612df157612df1614f07565b6020026020010151612e00565b805b9150612e0c81836143d8565b6001600160a01b0384166000908152600a602090815260408083209390935582518084019093526008546001600160801b038082168552600160801b90910416908301529150612e5d9083836140f5565b90506000612ea5612e79670de0b6b3a7640000620186a0615316565b612e928c612bc9601054876143c090919063ffffffff16565b612e9c91906152a4565b87906000614193565b6001600160a01b038516600090815260096020526040902054909150612ecb90826143d8565b6001600160a01b0380861660008181526009602052604090819020939093559151908f1691907f8ad4d3ff00da092c7ad9a573ea4f5f6a3dffc6712dc06d3f78f49b862297c40290612f209085815260200190565b60405180910390a360408051838152602081018590526001600160a01b0386169133917fc8e512d8f188ca059984b5853d2bf653da902696b8512785b182b2c813789a6e910160405180910390a360408051828152602081018490529081018490526001600160a01b03808f16919086169033907f66b108dc29b952efc76dccea9b82dce6b59fab4d9af73d8dcc9789afcad5daf69060600160405180910390a4612fcb898261423a565b9850612fd7888361423a565b9750612fe3878461423a565b96505050505b5080612ff481615224565b915050612d6e565b508260000361304d5760405162461bcd60e51b815260206004820152601960248201527f4361756c64726f6e3a20616c6c2061726520736f6c76656e740000000000000060448201526064016108fa565b613063836008546001600160801b0316906143e4565b600880546001600160801b0319166001600160801b03928316179081905561309491600160801b90910416836143e4565b600880546001600160801b03928316600160801b0292169190911790556007546130be90856143d8565b600781905550600060646130fa600a612bc987620186a06130ea6010548b6143c090919063ffffffff16565b6130f491906152a4565b906143d8565b61310491906152a4565b9050613110848261423a565b935061312f81600d54600160401b90046001600160801b0316906143cc565b600d80546001600160801b0392909216600160401b02600160401b600160c01b031990921691909117905550604051636d289ce560e11b81526000906001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce169063da5139ca906131cf907f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f3908890600190600401614cb9565b602060405180830381865afa1580156131ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132109190614cdc565b600354604051633c6340f360e21b81529192506001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce81169263f18d03cc9261326992169030908e908b90600401614cf5565b600060405180830381600087803b15801561328357600080fd5b505af1158015613297573d6000803e3d6000fd5b505050506001600160a01b0388161561334b5760035460405163a5d4096b60e01b81526001600160a01b038a81169263a5d4096b9261330692909116907f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f390339087908c908f90600401615335565b60408051808303816000875af1158015613324573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061334891906151be565b50505b604051636d289ce560e11b81526001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce169063da5139ca906133bc907f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f3908890600190600401614cb9565b602060405180830381865afa1580156133d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133fd9190614cdc565b604051633c6340f360e21b81529091506001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce169063f18d03cc90613472907f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f390339030908790600401614cf5565b600060405180830381600087803b15801561348c57600080fd5b505af11580156134a0573d6000803e3d6000fd5b505050505050505050505050505050565b604080518082019091526008546001600160801b038082168352600160801b9091041660208201526000906134e8908360016143f0565b81516020928301516001600160801b03908116600160801b029116176008556001600160a01b0386166000908152600a90925260409091205490915061352e90836143d8565b6001600160a01b038086166000908152600a6020526040808220939093559151636d289ce560e11b81527f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce9091169063da5139ca906135b6907f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f3908690600190600401614cb9565b602060405180830381865afa1580156135d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135f79190614cdc565b90507f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b031663f18d03cc7f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f3866136545733613676565b7f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce5b30856040518563ffffffff1660e01b81526004016136979493929190614cf5565b600060405180830381600087803b1580156136b157600080fd5b505af11580156136c5573d6000803e3d6000fd5b50505050846001600160a01b0316846136de5733613700565b7f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce5b6001600160a01b03167fc8e512d8f188ca059984b5853d2bf653da902696b8512785b182b2c813789a6e8486604051613743929190918252602082015260400190565b60405180910390a3509392505050565b6000806000620186a0613771601154866143c090919063ffffffff16565b61377b91906152a4565b90506137ba61378a858361423a565b604080518082019091526008546001600160801b038082168352600160801b909104166020820152906001614459565b81516020928301516001600160801b03908116600160801b908102928216838117600855604080518082019091526006548085168083529390048416968101969096529397509116909117111561384a5760405162461bcd60e51b8152602060048201526014602482015273109bdc9c9bddc8131a5b5a5d081c995858da195960621b60448201526064016108fa565b600d5461386790600160401b90046001600160801b0316836143cc565b600d80546001600160801b0392909216600160401b02600160401b600160c01b0319909216919091179055336000908152600a60205260408120546138ac908661423a565b905081602001516001600160801b03168111156139025760405162461bcd60e51b8152602060048201526014602482015273109bdc9c9bddc8131a5b5a5d081c995858da195960621b60448201526064016108fa565b336000908152600a602052604080822083905551636d289ce560e11b81527f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b03169163da5139ca91613982917f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f3918b9190600401614cb9565b602060405180830381865afa15801561399f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139c39190614cdc565b604051633c6340f360e21b81529094506001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce169063f18d03cc90613a38907f00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f39030908c908a90600401614cf5565b600060405180830381600087803b158015613a5257600080fd5b505af1158015613a66573d6000803e3d6000fd5b5050506001600160a01b0388169050337fb92cb6bca8e3270b9170930f03b17571e55791acdb1a0e9f339eec88bdb35e24613aa1898761423a565b60408051918252602082018a90520160405180910390a35050509250929050565b6001600160a01b0382166000908152600a6020526040812054808203613aec576001915050612377565b6001600160a01b03841660009081526009602052604081205490819003613b1857600092505050612377565b604080518082019091526008546001600160801b03808216808452600160801b909204166020830181905290613b55908790612bc99087906143c0565b613b5f91906152a4565b600354600f546001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce811692635662311892911690613bbd90612bc9613bb6620186a0670de0b6b3a76400006152a4565b89906143c0565b60006040518463ffffffff1660e01b8152600401613bdd93929190614cb9565b602060405180830381865afa158015613bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1e9190614cdc565b10159695505050505050565b600080841215613c49576000198414613c4357816109fc565b826109fc565b509192915050565b33600090815260096020526040902054613c6b90826143d8565b33600090815260096020526040902055600754613c8890826143d8565b6007556040518181526001600160a01b0383169033907f8ad4d3ff00da092c7ad9a573ea4f5f6a3dffc6712dc06d3f78f49b862297c4029060200160405180910390a3600354604051633c6340f360e21b81526001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce81169263f18d03cc92613d24929190911690309087908790600401614cf5565b600060405180830381600087803b158015613d3e57600080fd5b505af1158015613d52573d6000803e3d6000fd5b505050505050565b60008060008060008089806020019051810190613d779190615383565b9350935093509350613d8a828989613c2a565b9150613d97818989613c2a565b90507f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b03166302b9446c8a86338787876040518763ffffffff1660e01b8152600401613dee95949392919061525d565b604080518083038185885af1158015613e0b573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613e3091906151be565b955095505050505094509492505050565b60008060008060008088806020019051810190613e5e9190615383565b93509350935093507f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce6001600160a01b03166397da6d30853386613ea3878e8e613c2a565b613eae878f8f613c2a565b6040518663ffffffff1660e01b8152600401613ece95949392919061525d565b60408051808303816000875af1158015613eec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f1091906151be565b9550955050505050935093915050565b606060008060008060008089806020019051810190613f3f91906153d6565b94509450945094509450828015613f54575081155b15613f82578389604051602001613f6c929190615493565b6040516020818303038152906040529350613fdb565b82158015613f8d5750815b15613fa5578388604051602001613f6c929190615493565b828015613faf5750815b15613fdb57838989604051602001613fc9939291906154b5565b60405160208183030381529060405293505b6001600160a01b0385166000908152600b602052604090205460ff161561403b5760405162461bcd60e51b815260206004820152601460248201527310d85d5b191c9bdb8e8818d85b89dd0818d85b1b60621b60448201526064016108fa565b600080866001600160a01b03168d8760405161405791906154dc565b60006040518083038185875af1925050503d8060008114614094576040519150601f19603f3d011682016040523d82523d6000602084013e614099565b606091505b5091509150816140e35760405162461bcd60e51b815260206004820152601560248201527410d85d5b191c9bdb8e8818d85b1b0819985a5b1959605a1b60448201526064016108fa565b9c919b50909950505050505050505050565b600083602001516001600160801b031660000361411357508161418c565b602084015184516001600160801b0391821691614131911685615316565b61413b91906152a4565b905081801561417957508284600001516001600160801b031685602001516001600160801b03168361416d9190615316565b61417791906152a4565b105b1561418c578061418881615224565b9150505b9392505050565b82516000906001600160801b031681036141ae57508161418c565b835160208501516001600160801b03918216916141cc911685615316565b6141d691906152a4565b905081801561417957508284602001516001600160801b031685600001516001600160801b03168361416d9190615316565b60008080808061421a868801886149f6565b945094509450945094506142318585858585612cbd565b50505050505050565b600061418c8284614ca6565b801561433657604051633de222bb60e21b81526001600160a01b0385811660048301523060248301526142e29184917f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce169063f7888aec90604401602060405180830381865afa1580156142be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f49190614cdc565b8311156143315760405162461bcd60e51b815260206004820152601760248201527f4361756c64726f6e3a20536b696d20746f6f206d75636800000000000000000060448201526064016108fa565b61261a565b604051633c6340f360e21b81526001600160a01b037f000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce169063f18d03cc90614388908790339030908990600401614cf5565b600060405180830381600087803b1580156143a257600080fd5b505af11580156143b6573d6000803e3d6000fd5b5050505050505050565b600061418c8284615316565b600061418c82846154f8565b600061418c8284615291565b600061418c828461523d565b604080518082019091526000808252602082015260006144118585856140f5565b90508085600001818151614425919061523d565b6001600160801b031690525060208501805185919061444590839061523d565b6001600160801b0316905250939492505050565b6040805180820190915260008082526020820152600061447a858585614193565b9050838560000181815161448e91906154f8565b6001600160801b03169052506020850180518291906144459083906154f8565b6001600160a01b03811681146144c357600080fd5b50565b80151581146144c357600080fd5b6000806000606084860312156144e957600080fd5b83356144f4816144ae565b92506020840135614504816144c6565b91506040840135614514816144c6565b809150509250925092565b60008060006060848603121561453457600080fd5b833561453f816144ae565b9250602084013561454f816144c6565b929592945050506040919091013590565b60006020828403121561457257600080fd5b813561418c816144ae565b6001600160401b03811681146144c357600080fd5b6000602082840312156145a457600080fd5b813561418c8161457d565b600080604083850312156145c257600080fd5b82356145cd816144ae565b946020939093013593505050565b600080602083850312156145ee57600080fd5b82356001600160401b038082111561460557600080fd5b818501915085601f83011261461957600080fd5b81358181111561462857600080fd5b86602082850101111561463a57600080fd5b60209290920196919550909350505050565b60008083601f84011261465e57600080fd5b5081356001600160401b0381111561467557600080fd5b6020830191508360208260051b850101111561469057600080fd5b9250929050565b600080600080600080606087890312156146b057600080fd5b86356001600160401b03808211156146c757600080fd5b6146d38a838b0161464c565b909850965060208901359150808211156146ec57600080fd5b6146f88a838b0161464c565b9096509450604089013591508082111561471157600080fd5b5061471e89828a0161464c565b979a9699509497509295939492505050565b60005b8381101561474b578181015183820152602001614733565b50506000910152565b6000815180845261476c816020860160208601614730565b601f01601f19169290920160200192915050565b60208152600061418c6020830184614754565b6001600160801b03811681146144c357600080fd5b600080604083850312156147bb57600080fd5b82356147c681614793565b915060208301356147d6816144c6565b809150509250929050565b6000602082840312156147f357600080fd5b5035919050565b6000806040838503121561480d57600080fd5b82356147c6816144ae565b6000806040838503121561482b57600080fd5b823561483681614793565b915060208301356147d681614793565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561488457614884614846565b604052919050565b60006001600160401b038211156148a5576148a5614846565b5060051b60200190565b600082601f8301126148c057600080fd5b813560206148d56148d08361488c565b61485c565b82815260059290921b840181019181810190868411156148f457600080fd5b8286015b8481101561491857803561490b816144ae565b83529183019183016148f8565b509695505050505050565b600082601f83011261493457600080fd5b813560206149446148d08361488c565b82815260059290921b8401810191818101908684111561496357600080fd5b8286015b848110156149185780358352918301918301614967565b60006001600160401b0382111561499757614997614846565b50601f01601f191660200190565b600082601f8301126149b657600080fd5b81356149c46148d08261497e565b8181528460208386010111156149d957600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215614a0e57600080fd5b85356001600160401b0380821115614a2557600080fd5b614a3189838a016148af565b96506020880135915080821115614a4757600080fd5b614a5389838a01614923565b955060408801359150614a65826144ae565b909350606087013590614a77826144ae565b90925060808701359080821115614a8d57600080fd5b50614a9a888289016149a5565b9150509295509295909350565b600181811c90821680614abb57607f821691505b602082108103614adb57634e487b7160e01b600052602260045260246000fd5b50919050565b6000602080835260008454614af581614aa7565b80848701526040600180841660008114614b165760018114614b3057614b5e565b60ff1985168984015283151560051b890183019550614b5e565b896000528660002060005b85811015614b565781548b8201860152908301908801614b3b565b8a0184019650505b509398975050505050505050565b8051614b77816144c6565b919050565b60008060408385031215614b8f57600080fd5b8251614b9a816144c6565b6020939093015192949293505050565b600060208284031215614bbc57600080fd5b815161418c816144ae565b60208082526017908201527f43616c6c6572206973206e6f7420746865206f776e6572000000000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60006001600160401b0380831681851681830481118215151615614c3a57614c3a614bfe565b02949350505050565b634e487b7160e01b600052601260045260246000fd5b60006001600160401b0380841680614c7357614c73614c43565b92169190910492915050565b6001600160401b03818116838216019080821115614c9f57614c9f614bfe565b5092915050565b8082018082111561237757612377614bfe565b6001600160a01b0393909316835260208301919091521515604082015260600190565b600060208284031215614cee57600080fd5b5051919050565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b60208082526018908201527f4361756c64726f6e3a207573657220696e736f6c76656e740000000000000000604082015260600190565b600080600080600080600060e0888a031215614d7157600080fd5b8735614d7c816144ae565b96506020880135614d8c816144ae565b955060408801356001600160401b03811115614da757600080fd5b614db38a828b016149a5565b9550506060880135614dc48161457d565b9699959850939660808101359560a0820135955060c0909101359350915050565b601f8211156109e257600081815260208120601f850160051c81016020861015614e0c5750805b601f850160051c820191505b81811015613d5257828155600101614e18565b81516001600160401b03811115614e4457614e44614846565b614e5881614e528454614aa7565b84614de5565b602080601f831160018114614e8d5760008415614e755750858301515b600019600386901b1c1916600185901b178555613d52565b600085815260208120601f198616915b82811015614ebc57888601518255948401946001909101908401614e9d565b5085821015614eda5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215614efc57600080fd5b815161418c816144c6565b634e487b7160e01b600052603260045260246000fd5b60ff811681146144c357600080fd5b600060208284031215614f3e57600080fd5b813561418c81614f1d565b6000808335601e19843603018112614f6057600080fd5b8301803591506001600160401b03821115614f7a57600080fd5b60200191503681900382131561469057600080fd5b600080600060608486031215614fa457600080fd5b833592506020840135614504816144ae565b60008060408385031215614fc957600080fd5b8235915060208301356147d6816144ae565b600080600060608486031215614ff057600080fd5b8335614ffb816144c6565b95602085013595506040909401359392505050565b60008060008060008060c0878903121561502957600080fd5b8635615034816144ae565b95506020870135615044816144ae565b94506040870135615054816144c6565b9350606087013561506481614f1d565b9598949750929560808101359460a0909101359350915050565b60008060006060848603121561509357600080fd5b833561509e816144ae565b9250602084013561454f816144ae565b6000806000606084860312156150c357600080fd5b83356150ce816144ae565b925060208401356001600160401b03808211156150ea57600080fd5b6150f6878388016148af565b9350604086013591508082111561510c57600080fd5b5061511986828701614923565b9150509250925092565b60006080820160018060a01b0380881684526020818816818601526080604086015282875180855260a087019150828901945060005b81811015615177578551851683529483019491830191600101615159565b5050858103606087015286518082529082019350915080860160005b838110156151af57815185529382019390820190600101615193565b50929998505050505050505050565b600080604083850312156151d157600080fd5b505080516020909101519092909150565b6000806000606084860312156151f757600080fd5b83516152028161457d565b60208501519093506152138161457d565b604085015190925061451481614793565b60006001820161523657615236614bfe565b5060010190565b6001600160801b03828116828216039080821115614c9f57614c9f614bfe565b6001600160a01b03958616815293851660208501529190931660408301526060820192909252608081019190915260a00190565b8181038181111561237757612377614bfe565b6000826152b3576152b3614c43565b500490565b6000604082840312156152ca57600080fd5b604051604081018181106001600160401b03821117156152ec576152ec614846565b60405282516152fa81614793565b8152602083015161530a81614793565b60208201529392505050565b600081600019048311821515161561533057615330614bfe565b500290565b6001600160a01b038781168252868116602083015285166040820152606081018490526080810183905260c060a0820181905260009061537790830184614754565b98975050505050505050565b6000806000806080858703121561539957600080fd5b84516153a4816144ae565b60208601519094506153b5816144ae565b6040860151606090960151949790965092505050565b8051614b7781614f1d565b600080600080600060a086880312156153ee57600080fd5b85516153f9816144ae565b60208701519095506001600160401b0381111561541557600080fd5b8601601f8101881361542657600080fd5b80516154346148d08261497e565b81815289602083850101111561544957600080fd5b61545a826020830160208601614730565b955061546b91505060408701614b6c565b925061547960608701614b6c565b9150615487608087016153cb565b90509295509295909350565b600083516154a5818460208801614730565b9190910191825250602001919050565b600084516154c7818460208901614730565b91909101928352506020820152604001919050565b600082516154ee818460208701614730565b9190910192915050565b6001600160801b03818116838216019080821115614c9f57614c9f614bfe56fea2646970667358221220e8c207325426aae66c4d768daaf824232f34e431a0ac5b23162260dacc8cbbdb64736f6c63430008100033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f3
-----Decoded View---------------
Arg [0] : bentoBox_ (address): 0xd96f48665a1410C0cd669A88898ecA36B9Fc2cce
Arg [1] : magicInternetMoney_ (address): 0x99D8a9C45b2ecA8864373A26D1459e3Dff1e17F3
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000d96f48665a1410c0cd669a88898eca36b9fc2cce
Arg [1] : 00000000000000000000000099d8a9c45b2eca8864373a26d1459e3dff1e17f3
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.