Source Code
Latest 18 from a total of 18 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Rebalance | 17935524 | 927 days ago | IN | 0 ETH | 0.04339577 | ||||
| Rebalance | 17935512 | 927 days ago | IN | 0 ETH | 0.04290049 | ||||
| Rebalance | 17273597 | 1020 days ago | IN | 0 ETH | 0.036586 | ||||
| Rebalance | 16085578 | 1187 days ago | IN | 0 ETH | 0.00651996 | ||||
| Rebalance | 16085212 | 1187 days ago | IN | 0 ETH | 0.0057532 | ||||
| Rebalance | 16083932 | 1187 days ago | IN | 0 ETH | 0.00775164 | ||||
| Rebalance | 15796107 | 1227 days ago | IN | 0 ETH | 0.01474587 | ||||
| Rebalance | 14718339 | 1396 days ago | IN | 0 ETH | 0.03031113 | ||||
| Rebalance | 14673248 | 1403 days ago | IN | 0 ETH | 0.02495849 | ||||
| Rebalance | 14673240 | 1403 days ago | IN | 0 ETH | 0.02875819 | ||||
| Rebalance | 13890499 | 1525 days ago | IN | 0 ETH | 0.06140323 | ||||
| Rebalance | 13890499 | 1525 days ago | IN | 0 ETH | 0.06409959 | ||||
| Rebalance | 13863662 | 1529 days ago | IN | 0 ETH | 0.05453112 | ||||
| Rebalance | 13863657 | 1529 days ago | IN | 0 ETH | 0.05109964 | ||||
| Rebalance | 13863656 | 1529 days ago | IN | 0 ETH | 0.05541665 | ||||
| Rebalance | 13863585 | 1529 days ago | IN | 0 ETH | 0.04435919 | ||||
| Rebalance | 13863581 | 1529 days ago | IN | 0 ETH | 0.05145088 | ||||
| Rebalance | 13863554 | 1529 days ago | IN | 0 ETH | 0.0381068 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Rebalancer
Compiler Version
v0.8.7+commit.e28d00a7
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.7;
import "LinearMath.sol";
interface IERC20 {
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function balanceOf(address owner) external view returns (uint256);
function totalSupply() external view returns (uint256);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
interface IUniswapV3Pair {
function flash(
address recipient,
uint256 amount0,
uint256 amount1,
bytes calldata data
) external;
}
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
enum SwapKind { GIVEN_IN, GIVEN_OUT }
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
address assetIn;
address assetOut;
uint256 amount;
bytes userData;
}
interface IVault {
function getPoolTokens(bytes32 poolD) external view returns (address[] memory, uint256[] memory);
function swap(SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline) external payable returns (uint256);
}
interface WAToken {
function staticToDynamicAmount(uint256) external view returns (uint256);
function deposit(address, uint256, uint16, bool) external returns (uint256);
function withdraw(address, uint256, bool) external returns (uint256, uint256);
}
interface LinearPool {
//BasePool
function getPoolId() external view returns (bytes32);
function getSwapFeePercentage() external view returns (uint256);
function getScalingFactors() external view returns (uint256[] memory);
//LinearPool
function getMainToken() external view returns (address);
function getWrappedToken() external view returns (address);
function getBptIndex() external view returns (uint256);
function getMainIndex() external view returns (uint256);
function getWrappedIndex() external view returns (uint256);
function getRate() external view returns (uint256);
function getWrappedTokenRate() external view returns (uint256);
function getTargets() external view returns (uint256 lowerTarget, uint256 upperTarget);
}
contract Rebalancer {
using SafeERC20 for IERC20;
uint256 private constant MAX_UINT = 2 ** 256 - 1;
IVault constant private VAULT = IVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
IUniswapV3Pair constant private DAI_POOL = IUniswapV3Pair(0x5777d92f208679DB4b9778590Fa3CAB3aC9e2168);
IUniswapV3Pair constant private USDC_USDT_POOL = IUniswapV3Pair(0x3416cF6C708Da44DB2624D63ea0AAef7113527C6);
address constant private DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address constant private USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address constant private USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address constant private WDAI = 0x02d60b84491589974263d922D9cC7a3152618Ef6;
address constant private WUSDC = 0xd093fA4Fb80D09bB30817FDcd442d4d02eD3E5de;
address constant private WUSDT = 0xf8Fd466F12e236f4c96F7Cce6c79EAdB819abF58;
uint256 constant private ONE = 10**18;
constructor() {
IERC20(DAI).approve(address(WDAI), MAX_UINT);
IERC20(USDC).approve(address(WUSDC), MAX_UINT);
IERC20(USDT).safeApprove(address(WUSDT), MAX_UINT);
IERC20(DAI).approve(address(VAULT), MAX_UINT);
IERC20(USDC).approve(address(VAULT), MAX_UINT);
IERC20(USDT).safeApprove(address(VAULT), MAX_UINT);
IERC20(WDAI).approve(address(VAULT), MAX_UINT);
IERC20(WUSDC).approve(address(VAULT), MAX_UINT);
IERC20(WUSDT).approve(address(VAULT), MAX_UINT);
}
function rebalance(LinearPool _pool, uint256 _desiredBalance) public payable {
(SingleSwap memory _swap, uint256 _amountInNeededForSwap) = getSwapAndAmountInNeeded(_pool, _desiredBalance);
address _mainToken = _swap.kind == SwapKind.GIVEN_IN ? _swap.assetIn : _swap.assetOut;
// perform flash loan
IUniswapV3Pair _uniswapPool = _mainToken == DAI ? DAI_POOL : USDC_USDT_POOL;
uint256 _amountNeededForFlashLoan = _swap.kind == SwapKind.GIVEN_IN ? _amountInNeededForSwap : WAToken(address(_swap.assetIn)).staticToDynamicAmount(_amountInNeededForSwap);
bytes memory _swapData = abi.encode(_swap, _amountNeededForFlashLoan, _amountInNeededForSwap, msg.sender);
if (_mainToken == USDT) _uniswapPool.flash(address(this), 0, _amountNeededForFlashLoan, _swapData);
else _uniswapPool.flash(address(this), _amountNeededForFlashLoan, 0, _swapData);
}
function getSwapAndAmountInNeeded(LinearPool _pool, uint256 _desiredBalance) public view returns (SingleSwap memory _swap, uint256 _amountInNeededForSwap) {
LinearMath.Params memory _params = LinearMath.Params({
fee: _pool.getSwapFeePercentage(),
lowerTarget: 0,
upperTarget: 0
});
(_params.lowerTarget, _params.upperTarget) = _pool.getTargets();
uint256[] memory _scalingFactors = _pool.getScalingFactors();
uint256 _mainTokenIndex = _pool.getMainIndex();
(address[] memory _tokenAddresses, uint256[] memory _tokenBalances) = VAULT.getPoolTokens(_pool.getPoolId());
uint256 _mainTokenBalance = _tokenBalances[_mainTokenIndex];
if (_desiredBalance == 0) {
uint256 _scaledUpperTarget = _params.upperTarget * ONE / _scalingFactors[_mainTokenIndex];
uint256 _scaledLowerTarget = _params.upperTarget * ONE / _scalingFactors[_mainTokenIndex];
if (_mainTokenBalance > _scaledUpperTarget) {
_desiredBalance = _scaledUpperTarget;
} else if (_mainTokenBalance < _scaledLowerTarget) {
_desiredBalance = _scaledLowerTarget;
} else {
revert("Already in range and no desired balance specified");
}
}
// calculate amount needed.
uint256 _swapAmount = _mainTokenBalance < _desiredBalance ? _desiredBalance - _mainTokenBalance : _mainTokenBalance - _desiredBalance;
_amountInNeededForSwap = _mainTokenBalance < _desiredBalance ? _swapAmount : getWrappedInForMainOut(_swapAmount, _mainTokenBalance * _scalingFactors[_mainTokenIndex] / ONE, _scalingFactors[_mainTokenIndex], _scalingFactors[_pool.getWrappedIndex()], _params);
_swap = SingleSwap(
_pool.getPoolId(),
_mainTokenBalance > _desiredBalance ? SwapKind.GIVEN_OUT : SwapKind.GIVEN_IN,
_mainTokenBalance > _desiredBalance ? _tokenAddresses[_pool.getWrappedIndex()] : _tokenAddresses[_mainTokenIndex],
_mainTokenBalance > _desiredBalance ? _tokenAddresses[_mainTokenIndex] : _tokenAddresses[_pool.getWrappedIndex()],
_swapAmount,
new bytes(0)
);
return (_swap, _amountInNeededForSwap);
}
// Uniswap V3 Flash Callback
function uniswapV3FlashCallback(uint256, uint256, bytes calldata _data) external payable {
(SingleSwap memory _swap, uint256 _initialAmount, uint256 _requiredBalance, address _msgSender) = abi.decode(_data, (SingleSwap, uint256, uint256, address));
address mainToken = address(_swap.kind == SwapKind.GIVEN_IN ? _swap.assetIn : _swap.assetOut);
require(msg.sender == address(DAI_POOL) || msg.sender == address(USDC_USDT_POOL), "bad 3. no");
require(IERC20(mainToken).balanceOf(address(this)) >= _initialAmount, "Flash loan didnt do it");
doSwap(_swap, _initialAmount, _requiredBalance);
uint256 _repayment = _initialAmount + (_initialAmount / 10000) + 1;
uint256 _balance = IERC20(mainToken).balanceOf(address(this));
if (_balance < _repayment) {
uint256 _deficit = _repayment - _balance;
IERC20(mainToken).safeTransferFrom(_msgSender, address(this), _deficit);
}
IERC20(mainToken).safeTransfer(msg.sender, _repayment);
}
function getWrappedInForMainOut(uint256 _mainOut, uint256 _mainBalance, uint256 _mainScalingFactor, uint256 _wrappedScalingFactor, LinearMath.Params memory _params) public pure returns (uint256) {
_mainOut = _mainOut * _mainScalingFactor / ONE;
uint256 amountIn = LinearMath._calcWrappedInPerMainOut(_mainOut, _mainBalance, _params);
return (((amountIn * ONE) - 1) / _wrappedScalingFactor) + 1;
}
function getWrappedOutForMainIn(uint256 _mainIn, uint256 _mainBalance, uint256 _mainScalingFactor, uint256 _wrappedScalingFactor, LinearMath.Params memory _params) public pure returns (uint256) {
_mainIn = _mainIn * _mainScalingFactor / ONE;
uint256 amountOut = LinearMath._calcWrappedOutPerMainIn(_mainIn, _mainBalance, _params);
return amountOut * ONE / _wrappedScalingFactor;
}
function estimateDeficitRequirement(LinearPool _pool, uint256 _desiredBalance) external view returns (uint256) {
(SingleSwap memory _swap, uint256 _amountInNeededForSwap) = getSwapAndAmountInNeeded(_pool, _desiredBalance);
uint256 _amountNeededForFlashLoan = _swap.kind == SwapKind.GIVEN_IN ? _amountInNeededForSwap : WAToken(address(_swap.assetIn)).staticToDynamicAmount(_amountInNeededForSwap);
_amountNeededForFlashLoan += (_amountNeededForFlashLoan / 10000) + 1;
uint256 _amountOut = _swap.amount;
if (_swap.kind == SwapKind.GIVEN_IN) {
LinearMath.Params memory _params = LinearMath.Params({
fee: _pool.getSwapFeePercentage(),
lowerTarget: 0,
upperTarget: 0
});
(_params.lowerTarget, _params.upperTarget) = _pool.getTargets();
uint256[] memory _scalingFactors = _pool.getScalingFactors();
uint256 _mainTokenIndex = _pool.getMainIndex();
uint256 _wrappedTokenIndex = _pool.getWrappedIndex();
(, uint256[] memory _tokenBalances) = VAULT.getPoolTokens(_pool.getPoolId());
uint256 _mainTokenBalance = _tokenBalances[_mainTokenIndex];
_amountOut = getWrappedOutForMainIn(_swap.amount, _mainTokenBalance, _scalingFactors[_mainTokenIndex], _scalingFactors[_wrappedTokenIndex], _params);
_amountOut = WAToken(address(_swap.assetOut)).staticToDynamicAmount(_amountOut);
}
return _amountOut >= _amountNeededForFlashLoan ? 0 : _amountNeededForFlashLoan - _amountOut;
}
function doSwap(SingleSwap memory swap, uint256 _initialAmount, uint256 _requiredBalance) private {
uint256 limit = swap.kind == SwapKind.GIVEN_IN ? 0 : MAX_UINT;
FundManagement memory fundManagement = FundManagement(address(this), false, payable(address(this)), false);
if (swap.kind == SwapKind.GIVEN_OUT) wrapToken(address(swap.assetIn), _initialAmount);
require(IERC20(swap.assetIn).balanceOf(address(this)) >= _requiredBalance, "Not enough asset in balance");
VAULT.swap(swap, fundManagement, limit, block.timestamp);
if (swap.kind == SwapKind.GIVEN_IN) unwrapToken(address(swap.assetOut), IERC20(swap.assetOut).balanceOf(address(this)));
}
function wrapToken(address _wrappedToken, uint256 _amount) private {
WAToken(_wrappedToken).deposit(address(this), _amount, 0, true);
}
function unwrapToken(address _wrappedToken, uint256 _amount) private {
WAToken(_wrappedToken).withdraw(address(this), _amount, true);
}
receive() payable external {}
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity 0.8.7;
import "Math.sol";
import "FixedPoint.sol";
// These functions start with an underscore, as if they were part of a contract and not a library. At some point this
// should be fixed.
// solhint-disable private-vars-leading-underscore
library LinearMath {
using FixedPoint for uint256;
// A thorough derivation of the formulas and derivations found here exceeds the scope of this file, so only
// introductory notions will be presented.
// A Linear Pool holds three tokens: the main token, the wrapped token, and the Pool share token (BPT). It is
// possible to exchange any of these tokens for any of the other two (so we have three trading pairs) in both
// directions (the first token of each pair can be bought or sold for the second) and by specifying either the input
// or output amount (typically referred to as 'given in' or 'given out'). A full description thus requires
// 3*2*2 = 12 functions.
// Wrapped tokens have a known, trusted exchange rate to main tokens. All functions here assume such a rate has
// already been applied, meaning main and wrapped balances can be compared as they are both expressed in the same
// units (those of main token).
// Additionally, Linear Pools feature a lower and upper target that represent the desired range of values for the
// main token balance. Any action that moves the main balance away from this range is charged a proportional fee,
// and any action that moves it towards this range is incentivized by paying the actor using these collected fees.
// The collected fees are not stored in a separate data structure: they are a function of the current main balance,
// targets and fee percentage. The main balance sans fees is known as the 'nominal balance', which is always smaller
// than the real balance except when the real balance is within the targets.
// The rule under which Linear Pools conduct trades between main and wrapped tokens is by keeping the sum of nominal
// main balance and wrapped balance constant: this value is known as the 'invariant'. BPT is backed by nominal
// reserves, meaning its supply is proportional to the invariant. As the wrapped token appreciates in value and its
// exchange rate to the main token increases, so does the invariant and thus the value of BPT (in main token units).
struct Params {
uint256 fee;
uint256 lowerTarget;
uint256 upperTarget;
}
function _calcWrappedOutPerMainIn(
uint256 mainIn,
uint256 mainBalance,
Params memory params
) internal pure returns (uint256) {
// Amount out, so we round down overall.
uint256 previousNominalMain = _toNominal(mainBalance, params);
uint256 afterNominalMain = _toNominal(mainBalance.add(mainIn), params);
return afterNominalMain.sub(previousNominalMain);
}
function _calcWrappedInPerMainOut(
uint256 mainOut,
uint256 mainBalance,
Params memory params
) internal pure returns (uint256) {
// Amount in, so we round up overall.
uint256 previousNominalMain = _toNominal(mainBalance, params);
uint256 afterNominalMain = _toNominal(mainBalance.sub(mainOut), params);
return previousNominalMain.sub(afterNominalMain);
}
function _toNominal(uint256 real, Params memory params) internal pure returns (uint256) {
// Fees are always rounded down: either direction would work but we need to be consistent, and rounding down
// uses less gas.
if (real < params.lowerTarget) {
uint256 fees = (params.lowerTarget - real).mulDown(params.fee);
return real.sub(fees);
} else if (real <= params.upperTarget) {
return real;
} else {
uint256 fees = (real - params.upperTarget).mulDown(params.fee);
return real.sub(fees);
}
}
function _fromNominal(uint256 nominal, Params memory params) internal pure returns (uint256) {
// Since real = nominal + fees, rounding down fees is equivalent to rounding down real.
if (nominal < params.lowerTarget) {
return (nominal.add(params.fee.mulDown(params.lowerTarget))).divDown(FixedPoint.ONE.add(params.fee));
} else if (nominal <= params.upperTarget) {
return nominal;
} else {
return (nominal.sub(params.fee.mulDown(params.upperTarget)).divDown(FixedPoint.ONE.sub(params.fee)));
}
}
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity 0.8.7;
import "LogExpMath.sol";
import "BalancerErrors.sol";
/* solhint-disable private-vars-leading-underscore */
library FixedPoint {
uint256 internal constant ONE = 1e18; // 18 decimal places
uint256 internal constant MAX_POW_RELATIVE_ERROR = 10000; // 10^(-14)
// Minimum base for the power function when the exponent is 'free' (larger than ONE).
uint256 internal constant MIN_POW_BASE_FREE_EXPONENT = 0.7e18;
function add(uint256 a, uint256 b) internal pure returns (uint256) {
// Fixed Point addition is the same as regular checked addition
uint256 c = a + b;
_require(c >= a, Errors.ADD_OVERFLOW);
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
// Fixed Point addition is the same as regular checked addition
_require(b <= a, Errors.SUB_OVERFLOW);
uint256 c = a - b;
return c;
}
function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 product = a * b;
_require(a == 0 || product / a == b, Errors.MUL_OVERFLOW);
return product / ONE;
}
function mulUp(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 product = a * b;
_require(a == 0 || product / a == b, Errors.MUL_OVERFLOW);
if (product == 0) {
return 0;
} else {
// The traditional divUp formula is:
// divUp(x, y) := (x + y - 1) / y
// To avoid intermediate overflow in the addition, we distribute the division and get:
// divUp(x, y) := (x - 1) / y + 1
// Note that this requires x != 0, which we already tested for.
return ((product - 1) / ONE) + 1;
}
}
function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
_require(b != 0, Errors.ZERO_DIVISION);
if (a == 0) {
return 0;
} else {
uint256 aInflated = a * ONE;
_require(aInflated / a == ONE, Errors.DIV_INTERNAL); // mul overflow
return aInflated / b;
}
}
function divUp(uint256 a, uint256 b) internal pure returns (uint256) {
_require(b != 0, Errors.ZERO_DIVISION);
if (a == 0) {
return 0;
} else {
uint256 aInflated = a * ONE;
_require(aInflated / a == ONE, Errors.DIV_INTERNAL); // mul overflow
// The traditional divUp formula is:
// divUp(x, y) := (x + y - 1) / y
// To avoid intermediate overflow in the addition, we distribute the division and get:
// divUp(x, y) := (x - 1) / y + 1
// Note that this requires x != 0, which we already tested for.
return ((aInflated - 1) / b) + 1;
}
}
/**
* @dev Returns x^y, assuming both are fixed point numbers, rounding down. The result is guaranteed to not be above
* the true value (that is, the error function expected - actual is always positive).
*/
function powDown(uint256 x, uint256 y) internal pure returns (uint256) {
uint256 raw = LogExpMath.pow(x, y);
uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);
if (raw < maxError) {
return 0;
} else {
return sub(raw, maxError);
}
}
/**
* @dev Returns x^y, assuming both are fixed point numbers, rounding up. The result is guaranteed to not be below
* the true value (that is, the error function expected - actual is always negative).
*/
function powUp(uint256 x, uint256 y) internal pure returns (uint256) {
uint256 raw = LogExpMath.pow(x, y);
uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);
return add(raw, maxError);
}
/**
* @dev Returns the complement of a value (1 - x), capped to 0 if x is larger than 1.
*
* Useful when computing the complement for values with some level of relative error, as it strips this error and
* prevents intermediate negative values.
*/
function complement(uint256 x) internal pure returns (uint256) {
return (x < ONE) ? (ONE - x) : 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
import "BalancerErrors.sol";
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow checks.
* Adapted from OpenZeppelin's SafeMath library.
*/
library Math {
/**
* @dev Returns the absolute value of a signed integer.
*/
function abs(int256 a) internal pure returns (uint256) {
return a > 0 ? uint256(a) : uint256(-a);
}
/**
* @dev Returns the addition of two unsigned integers of 256 bits, reverting on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
_require(c >= a, Errors.ADD_OVERFLOW);
return c;
}
/**
* @dev Returns the addition of two signed integers, reverting on overflow.
*/
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
_require((b >= 0 && c >= a) || (b < 0 && c < a), Errors.ADD_OVERFLOW);
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers of 256 bits, reverting on overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
_require(b <= a, Errors.SUB_OVERFLOW);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the subtraction of two signed integers, reverting on overflow.
*/
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
_require((b >= 0 && c <= a) || (b < 0 && c > a), Errors.SUB_OVERFLOW);
return c;
}
/**
* @dev Returns the largest of two numbers of 256 bits.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers of 256 bits.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a * b;
_require(a == 0 || c / a == b, Errors.MUL_OVERFLOW);
return c;
}
function div(
uint256 a,
uint256 b,
bool roundUp
) internal pure returns (uint256) {
return roundUp ? divUp(a, b) : divDown(a, b);
}
function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
_require(b != 0, Errors.ZERO_DIVISION);
return a / b;
}
function divUp(uint256 a, uint256 b) internal pure returns (uint256) {
_require(b != 0, Errors.ZERO_DIVISION);
if (a == 0) {
return 0;
} else {
return 1 + (a - 1) / b;
}
}
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity 0.8.7;
// solhint-disable
/**
* @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are
* supported.
*/
function _require(bool condition, uint256 errorCode) pure {
if (!condition) _revert(errorCode);
}
/**
* @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.
*/
function _revert(uint256 errorCode) pure {
// We're going to dynamically create a revert string based on the error code, with the following format:
// 'BAL#{errorCode}'
// where the code is left-padded with zeroes to three digits (so they range from 000 to 999).
//
// We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a
// number (8 to 16 bits) than the individual string characters.
//
// The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a
// much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a
// safe place to rely on it without worrying about how its usage might affect e.g. memory contents.
assembly {
// First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999
// range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for
// the '0' character.
let units := add(mod(errorCode, 10), 0x30)
errorCode := div(errorCode, 10)
let tenths := add(mod(errorCode, 10), 0x30)
errorCode := div(errorCode, 10)
let hundreds := add(mod(errorCode, 10), 0x30)
// With the individual characters, we can now construct the full string. The "BAL#" part is a known constant
// (0x42414c23): we simply shift this by 24 (to provide space for the 3 bytes of the error code), and add the
// characters to it, each shifted by a multiple of 8.
// The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits
// per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte
// array).
let revertReason := shl(200, add(0x42414c23000000, add(add(units, shl(8, tenths)), shl(16, hundreds))))
// We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded
// message will have the following layout:
// [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ]
// The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We
// also write zeroes to the next 28 bytes of memory, but those are about to be overwritten.
mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
// Next is the offset to the location of the string, which will be placed immediately after (20 bytes away).
mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
// The string length is fixed: 7 characters.
mstore(0x24, 7)
// Finally, the string itself is stored.
mstore(0x44, revertReason)
// Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of
// the encoded message is therefore 4 + 32 + 32 + 32 = 100.
revert(0, 100)
}
}
library Errors {
// Math
uint256 internal constant ADD_OVERFLOW = 0;
uint256 internal constant SUB_OVERFLOW = 1;
uint256 internal constant SUB_UNDERFLOW = 2;
uint256 internal constant MUL_OVERFLOW = 3;
uint256 internal constant ZERO_DIVISION = 4;
uint256 internal constant DIV_INTERNAL = 5;
uint256 internal constant X_OUT_OF_BOUNDS = 6;
uint256 internal constant Y_OUT_OF_BOUNDS = 7;
uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8;
uint256 internal constant INVALID_EXPONENT = 9;
// Input
uint256 internal constant OUT_OF_BOUNDS = 100;
uint256 internal constant UNSORTED_ARRAY = 101;
uint256 internal constant UNSORTED_TOKENS = 102;
uint256 internal constant INPUT_LENGTH_MISMATCH = 103;
uint256 internal constant ZERO_TOKEN = 104;
// Shared pools
uint256 internal constant MIN_TOKENS = 200;
uint256 internal constant MAX_TOKENS = 201;
uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202;
uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203;
uint256 internal constant MINIMUM_BPT = 204;
uint256 internal constant CALLER_NOT_VAULT = 205;
uint256 internal constant UNINITIALIZED = 206;
uint256 internal constant BPT_IN_MAX_AMOUNT = 207;
uint256 internal constant BPT_OUT_MIN_AMOUNT = 208;
uint256 internal constant EXPIRED_PERMIT = 209;
uint256 internal constant NOT_TWO_TOKENS = 210;
// Pools
uint256 internal constant MIN_AMP = 300;
uint256 internal constant MAX_AMP = 301;
uint256 internal constant MIN_WEIGHT = 302;
uint256 internal constant MAX_STABLE_TOKENS = 303;
uint256 internal constant MAX_IN_RATIO = 304;
uint256 internal constant MAX_OUT_RATIO = 305;
uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306;
uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307;
uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308;
uint256 internal constant INVALID_TOKEN = 309;
uint256 internal constant UNHANDLED_JOIN_KIND = 310;
uint256 internal constant ZERO_INVARIANT = 311;
uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312;
uint256 internal constant ORACLE_NOT_INITIALIZED = 313;
uint256 internal constant ORACLE_QUERY_TOO_OLD = 314;
uint256 internal constant ORACLE_INVALID_INDEX = 315;
uint256 internal constant ORACLE_BAD_SECS = 316;
uint256 internal constant AMP_END_TIME_TOO_CLOSE = 317;
uint256 internal constant AMP_ONGOING_UPDATE = 318;
uint256 internal constant AMP_RATE_TOO_HIGH = 319;
uint256 internal constant AMP_NO_ONGOING_UPDATE = 320;
uint256 internal constant STABLE_INVARIANT_DIDNT_CONVERGE = 321;
uint256 internal constant STABLE_GET_BALANCE_DIDNT_CONVERGE = 322;
uint256 internal constant RELAYER_NOT_CONTRACT = 323;
uint256 internal constant BASE_POOL_RELAYER_NOT_CALLED = 324;
uint256 internal constant REBALANCING_RELAYER_REENTERED = 325;
uint256 internal constant GRADUAL_UPDATE_TIME_TRAVEL = 326;
uint256 internal constant SWAPS_DISABLED = 327;
uint256 internal constant CALLER_IS_NOT_LBP_OWNER = 328;
uint256 internal constant PRICE_RATE_OVERFLOW = 329;
uint256 internal constant INVALID_JOIN_EXIT_KIND_WHILE_SWAPS_DISABLED = 330;
uint256 internal constant WEIGHT_CHANGE_TOO_FAST = 331;
uint256 internal constant LOWER_GREATER_THAN_UPPER_TARGET = 332;
uint256 internal constant UPPER_TARGET_TOO_HIGH = 333;
uint256 internal constant UNHANDLED_BY_LINEAR_POOL = 334;
uint256 internal constant OUT_OF_TARGET_RANGE = 335;
uint256 internal constant UNHANDLED_EXIT_KIND = 336;
uint256 internal constant UNAUTHORIZED_EXIT = 337;
uint256 internal constant MAX_MANAGEMENT_SWAP_FEE_PERCENTAGE = 338;
uint256 internal constant UNHANDLED_BY_MANAGED_POOL = 339;
uint256 internal constant UNHANDLED_BY_PHANTOM_POOL = 340;
uint256 internal constant TOKEN_DOES_NOT_HAVE_RATE_PROVIDER = 341;
uint256 internal constant INVALID_INITIALIZATION = 342;
uint256 internal constant OUT_OF_NEW_TARGET_RANGE = 343;
uint256 internal constant UNAUTHORIZED_OPERATION = 344;
uint256 internal constant UNINITIALIZED_POOL_CONTROLLER = 345;
// Lib
uint256 internal constant REENTRANCY = 400;
uint256 internal constant SENDER_NOT_ALLOWED = 401;
uint256 internal constant PAUSED = 402;
uint256 internal constant PAUSE_WINDOW_EXPIRED = 403;
uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404;
uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405;
uint256 internal constant INSUFFICIENT_BALANCE = 406;
uint256 internal constant INSUFFICIENT_ALLOWANCE = 407;
uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408;
uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409;
uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410;
uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411;
uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412;
uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413;
uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414;
uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415;
uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416;
uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417;
uint256 internal constant SAFE_ERC20_CALL_FAILED = 418;
uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419;
uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420;
uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421;
uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422;
uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423;
uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424;
uint256 internal constant BUFFER_PERIOD_EXPIRED = 425;
uint256 internal constant CALLER_IS_NOT_OWNER = 426;
uint256 internal constant NEW_OWNER_IS_ZERO = 427;
uint256 internal constant CODE_DEPLOYMENT_FAILED = 428;
uint256 internal constant CALL_TO_NON_CONTRACT = 429;
uint256 internal constant LOW_LEVEL_CALL_FAILED = 430;
uint256 internal constant NOT_PAUSED = 431;
uint256 internal constant ADDRESS_ALREADY_ALLOWLISTED = 432;
uint256 internal constant ADDRESS_NOT_ALLOWLISTED = 433;
// Vault
uint256 internal constant INVALID_POOL_ID = 500;
uint256 internal constant CALLER_NOT_POOL = 501;
uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502;
uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503;
uint256 internal constant INVALID_SIGNATURE = 504;
uint256 internal constant EXIT_BELOW_MIN = 505;
uint256 internal constant JOIN_ABOVE_MAX = 506;
uint256 internal constant SWAP_LIMIT = 507;
uint256 internal constant SWAP_DEADLINE = 508;
uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509;
uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510;
uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511;
uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512;
uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513;
uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514;
uint256 internal constant INVALID_POST_LOAN_BALANCE = 515;
uint256 internal constant INSUFFICIENT_ETH = 516;
uint256 internal constant UNALLOCATED_ETH = 517;
uint256 internal constant ETH_TRANSFER = 518;
uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519;
uint256 internal constant TOKENS_MISMATCH = 520;
uint256 internal constant TOKEN_NOT_REGISTERED = 521;
uint256 internal constant TOKEN_ALREADY_REGISTERED = 522;
uint256 internal constant TOKENS_ALREADY_SET = 523;
uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524;
uint256 internal constant NONZERO_TOKEN_BALANCE = 525;
uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526;
uint256 internal constant POOL_NO_TOKENS = 527;
uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528;
// Fees
uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600;
uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601;
uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602;
}// SPDX-License-Identifier: MIT
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the “Software”), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
pragma solidity 0.8.7;
import "BalancerErrors.sol";
/* solhint-disable */
/**
* @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).
*
* Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural
* exponentiation and logarithm (where the base is Euler's number).
*
* @author Fernando Martinelli - @fernandomartinelli
* @author Sergio Yuhjtman - @sergioyuhjtman
* @author Daniel Fernandez - @dmf7z
*/
library LogExpMath {
// All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying
// two numbers, and multiply by ONE when dividing them.
// All arguments and return values are 18 decimal fixed point numbers.
int256 constant ONE_18 = 1e18;
// Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the
// case of ln36, 36 decimals.
int256 constant ONE_20 = 1e20;
int256 constant ONE_36 = 1e36;
// The domain of natural exponentiation is bound by the word size and number of decimals used.
//
// Because internally the result will be stored using 20 decimals, the largest possible result is
// (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.
// The smallest possible result is 10^(-18), which makes largest negative argument
// ln(10^(-18)) = -41.446531673892822312.
// We use 130.0 and -41.0 to have some safety margin.
int256 constant MAX_NATURAL_EXPONENT = 130e18;
int256 constant MIN_NATURAL_EXPONENT = -41e18;
// Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point
// 256 bit integer.
int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;
int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;
uint256 constant MILD_EXPONENT_BOUND = 2**254 / uint256(ONE_20);
// 18 decimal constants
int256 constant x0 = 128000000000000000000; // 2ˆ7
int256 constant a0 = 38877084059945950922200000000000000000000000000000000000; // eˆ(x0) (no decimals)
int256 constant x1 = 64000000000000000000; // 2ˆ6
int256 constant a1 = 6235149080811616882910000000; // eˆ(x1) (no decimals)
// 20 decimal constants
int256 constant x2 = 3200000000000000000000; // 2ˆ5
int256 constant a2 = 7896296018268069516100000000000000; // eˆ(x2)
int256 constant x3 = 1600000000000000000000; // 2ˆ4
int256 constant a3 = 888611052050787263676000000; // eˆ(x3)
int256 constant x4 = 800000000000000000000; // 2ˆ3
int256 constant a4 = 298095798704172827474000; // eˆ(x4)
int256 constant x5 = 400000000000000000000; // 2ˆ2
int256 constant a5 = 5459815003314423907810; // eˆ(x5)
int256 constant x6 = 200000000000000000000; // 2ˆ1
int256 constant a6 = 738905609893065022723; // eˆ(x6)
int256 constant x7 = 100000000000000000000; // 2ˆ0
int256 constant a7 = 271828182845904523536; // eˆ(x7)
int256 constant x8 = 50000000000000000000; // 2ˆ-1
int256 constant a8 = 164872127070012814685; // eˆ(x8)
int256 constant x9 = 25000000000000000000; // 2ˆ-2
int256 constant a9 = 128402541668774148407; // eˆ(x9)
int256 constant x10 = 12500000000000000000; // 2ˆ-3
int256 constant a10 = 113314845306682631683; // eˆ(x10)
int256 constant x11 = 6250000000000000000; // 2ˆ-4
int256 constant a11 = 106449445891785942956; // eˆ(x11)
/**
* @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.
*
* Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.
*/
function pow(uint256 x, uint256 y) internal pure returns (uint256) {
if (y == 0) {
// We solve the 0^0 indetermination by making it equal one.
return uint256(ONE_18);
}
if (x == 0) {
return 0;
}
// Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to
// arrive at that result. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means
// x^y = exp(y * ln(x)).
// The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.
_require(x < 2**255, Errors.X_OUT_OF_BOUNDS);
int256 x_int256 = int256(x);
// We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In
// both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.
// This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.
_require(y < MILD_EXPONENT_BOUND, Errors.Y_OUT_OF_BOUNDS);
int256 y_int256 = int256(y);
int256 logx_times_y;
if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {
int256 ln_36_x = _ln_36(x_int256);
// ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just
// bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal
// multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the
// (downscaled) last 18 decimals.
logx_times_y = ((ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18);
} else {
logx_times_y = _ln(x_int256) * y_int256;
}
logx_times_y /= ONE_18;
// Finally, we compute exp(y * ln(x)) to arrive at x^y
_require(
MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT,
Errors.PRODUCT_OUT_OF_BOUNDS
);
return uint256(exp(logx_times_y));
}
/**
* @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.
*
* Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.
*/
function exp(int256 x) internal pure returns (int256) {
_require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, Errors.INVALID_EXPONENT);
if (x < 0) {
// We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it
// fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).
// Fixed point division requires multiplying by ONE_18.
return ((ONE_18 * ONE_18) / exp(-x));
}
// First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,
// where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7
// because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the
// decomposition.
// At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this
// decomposition, which will be lower than the smallest x_n.
// exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.
// We mutate x by subtracting x_n, making it the remainder of the decomposition.
// The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause
// intermediate overflows. Instead we store them as plain integers, with 0 decimals.
// Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the
// decomposition.
// For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct
// it and compute the accumulated product.
int256 firstAN;
if (x >= x0) {
x -= x0;
firstAN = a0;
} else if (x >= x1) {
x -= x1;
firstAN = a1;
} else {
firstAN = 1; // One with no decimal places
}
// We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the
// smaller terms.
x *= 100;
// `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point
// one. Recall that fixed point multiplication requires dividing by ONE_20.
int256 product = ONE_20;
if (x >= x2) {
x -= x2;
product = (product * a2) / ONE_20;
}
if (x >= x3) {
x -= x3;
product = (product * a3) / ONE_20;
}
if (x >= x4) {
x -= x4;
product = (product * a4) / ONE_20;
}
if (x >= x5) {
x -= x5;
product = (product * a5) / ONE_20;
}
if (x >= x6) {
x -= x6;
product = (product * a6) / ONE_20;
}
if (x >= x7) {
x -= x7;
product = (product * a7) / ONE_20;
}
if (x >= x8) {
x -= x8;
product = (product * a8) / ONE_20;
}
if (x >= x9) {
x -= x9;
product = (product * a9) / ONE_20;
}
// x10 and x11 are unnecessary here since we have high enough precision already.
// Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series
// expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).
int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.
int256 term; // Each term in the sum, where the nth term is (x^n / n!).
// The first term is simply x.
term = x;
seriesSum += term;
// Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,
// multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.
term = ((term * x) / ONE_20) / 2;
seriesSum += term;
term = ((term * x) / ONE_20) / 3;
seriesSum += term;
term = ((term * x) / ONE_20) / 4;
seriesSum += term;
term = ((term * x) / ONE_20) / 5;
seriesSum += term;
term = ((term * x) / ONE_20) / 6;
seriesSum += term;
term = ((term * x) / ONE_20) / 7;
seriesSum += term;
term = ((term * x) / ONE_20) / 8;
seriesSum += term;
term = ((term * x) / ONE_20) / 9;
seriesSum += term;
term = ((term * x) / ONE_20) / 10;
seriesSum += term;
term = ((term * x) / ONE_20) / 11;
seriesSum += term;
term = ((term * x) / ONE_20) / 12;
seriesSum += term;
// 12 Taylor terms are sufficient for 18 decimal precision.
// We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor
// approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply
// all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),
// and then drop two digits to return an 18 decimal value.
return (((product * seriesSum) / ONE_20) * firstAN) / 100;
}
/**
* @dev Logarithm (log(arg, base), with signed 18 decimal fixed point base and argument.
*/
function log(int256 arg, int256 base) internal pure returns (int256) {
// This performs a simple base change: log(arg, base) = ln(arg) / ln(base).
// Both logBase and logArg are computed as 36 decimal fixed point numbers, either by using ln_36, or by
// upscaling.
int256 logBase;
if (LN_36_LOWER_BOUND < base && base < LN_36_UPPER_BOUND) {
logBase = _ln_36(base);
} else {
logBase = _ln(base) * ONE_18;
}
int256 logArg;
if (LN_36_LOWER_BOUND < arg && arg < LN_36_UPPER_BOUND) {
logArg = _ln_36(arg);
} else {
logArg = _ln(arg) * ONE_18;
}
// When dividing, we multiply by ONE_18 to arrive at a result with 18 decimal places
return (logArg * ONE_18) / logBase;
}
/**
* @dev Natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
*/
function ln(int256 a) internal pure returns (int256) {
// The real natural logarithm is not defined for negative numbers or zero.
_require(a > 0, Errors.OUT_OF_BOUNDS);
if (LN_36_LOWER_BOUND < a && a < LN_36_UPPER_BOUND) {
return _ln_36(a) / ONE_18;
} else {
return _ln(a);
}
}
/**
* @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.
*/
function _ln(int256 a) private pure returns (int256) {
if (a < ONE_18) {
// Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less
// than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.
// Fixed point division requires multiplying by ONE_18.
return (-_ln((ONE_18 * ONE_18) / a));
}
// First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which
// we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,
// ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot
// be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.
// At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this
// decomposition, which will be lower than the smallest a_n.
// ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.
// We mutate a by subtracting a_n, making it the remainder of the decomposition.
// For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point
// numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by
// ONE_18 to convert them to fixed point.
// For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide
// by it and compute the accumulated sum.
int256 sum = 0;
if (a >= a0 * ONE_18) {
a /= a0; // Integer, not fixed point division
sum += x0;
}
if (a >= a1 * ONE_18) {
a /= a1; // Integer, not fixed point division
sum += x1;
}
// All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.
sum *= 100;
a *= 100;
// Because further a_n are 20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.
if (a >= a2) {
a = (a * ONE_20) / a2;
sum += x2;
}
if (a >= a3) {
a = (a * ONE_20) / a3;
sum += x3;
}
if (a >= a4) {
a = (a * ONE_20) / a4;
sum += x4;
}
if (a >= a5) {
a = (a * ONE_20) / a5;
sum += x5;
}
if (a >= a6) {
a = (a * ONE_20) / a6;
sum += x6;
}
if (a >= a7) {
a = (a * ONE_20) / a7;
sum += x7;
}
if (a >= a8) {
a = (a * ONE_20) / a8;
sum += x8;
}
if (a >= a9) {
a = (a * ONE_20) / a9;
sum += x9;
}
if (a >= a10) {
a = (a * ONE_20) / a10;
sum += x10;
}
if (a >= a11) {
a = (a * ONE_20) / a11;
sum += x11;
}
// a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series
// that converges rapidly for values of `a` close to one - the same one used in ln_36.
// Let z = (a - 1) / (a + 1).
// ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))
// Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires
// division by ONE_20.
int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);
int256 z_squared = (z * z) / ONE_20;
// num is the numerator of the series: the z^(2 * n + 1) term
int256 num = z;
// seriesSum holds the accumulated sum of each term in the series, starting with the initial z
int256 seriesSum = num;
// In each step, the numerator is multiplied by z^2
num = (num * z_squared) / ONE_20;
seriesSum += num / 3;
num = (num * z_squared) / ONE_20;
seriesSum += num / 5;
num = (num * z_squared) / ONE_20;
seriesSum += num / 7;
num = (num * z_squared) / ONE_20;
seriesSum += num / 9;
num = (num * z_squared) / ONE_20;
seriesSum += num / 11;
// 6 Taylor terms are sufficient for 36 decimal precision.
// Finally, we multiply by 2 (non fixed point) to compute ln(remainder)
seriesSum *= 2;
// We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both
// with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal
// value.
return (sum + seriesSum) / 100;
}
/**
* @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,
* for x close to one.
*
* Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.
*/
function _ln_36(int256 x) private pure returns (int256) {
// Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits
// worthwhile.
// First, we transform x to a 36 digit fixed point value.
x *= ONE_18;
// We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).
// ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))
// Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires
// division by ONE_36.
int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);
int256 z_squared = (z * z) / ONE_36;
// num is the numerator of the series: the z^(2 * n + 1) term
int256 num = z;
// seriesSum holds the accumulated sum of each term in the series, starting with the initial z
int256 seriesSum = num;
// In each step, the numerator is multiplied by z^2
num = (num * z_squared) / ONE_36;
seriesSum += num / 3;
num = (num * z_squared) / ONE_36;
seriesSum += num / 5;
num = (num * z_squared) / ONE_36;
seriesSum += num / 7;
num = (num * z_squared) / ONE_36;
seriesSum += num / 9;
num = (num * z_squared) / ONE_36;
seriesSum += num / 11;
num = (num * z_squared) / ONE_36;
seriesSum += num / 13;
num = (num * z_squared) / ONE_36;
seriesSum += num / 15;
// 8 Taylor terms are sufficient for 36 decimal precision.
// All that remains is multiplying by 2 (non fixed point).
return seriesSum * 2;
}
}{
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"contract LinearPool","name":"_pool","type":"address"},{"internalType":"uint256","name":"_desiredBalance","type":"uint256"}],"name":"estimateDeficitRequirement","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract LinearPool","name":"_pool","type":"address"},{"internalType":"uint256","name":"_desiredBalance","type":"uint256"}],"name":"getSwapAndAmountInNeeded","outputs":[{"components":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"enum SwapKind","name":"kind","type":"uint8"},{"internalType":"address","name":"assetIn","type":"address"},{"internalType":"address","name":"assetOut","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"internalType":"struct SingleSwap","name":"_swap","type":"tuple"},{"internalType":"uint256","name":"_amountInNeededForSwap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mainOut","type":"uint256"},{"internalType":"uint256","name":"_mainBalance","type":"uint256"},{"internalType":"uint256","name":"_mainScalingFactor","type":"uint256"},{"internalType":"uint256","name":"_wrappedScalingFactor","type":"uint256"},{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lowerTarget","type":"uint256"},{"internalType":"uint256","name":"upperTarget","type":"uint256"}],"internalType":"struct LinearMath.Params","name":"_params","type":"tuple"}],"name":"getWrappedInForMainOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mainIn","type":"uint256"},{"internalType":"uint256","name":"_mainBalance","type":"uint256"},{"internalType":"uint256","name":"_mainScalingFactor","type":"uint256"},{"internalType":"uint256","name":"_wrappedScalingFactor","type":"uint256"},{"components":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"lowerTarget","type":"uint256"},{"internalType":"uint256","name":"upperTarget","type":"uint256"}],"internalType":"struct LinearMath.Params","name":"_params","type":"tuple"}],"name":"getWrappedOutForMainIn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"contract LinearPool","name":"_pool","type":"address"},{"internalType":"uint256","name":"_desiredBalance","type":"uint256"}],"name":"rebalance","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3FlashCallback","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b50736b175474e89094c44da98b954eedeac495271d0f73ffffffffffffffffffffffffffffffffffffffff1663095ea7b37302d60b84491589974263d922d9cc7a3152618ef67fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040518363ffffffff1660e01b81526004016200009792919062000d33565b602060405180830381600087803b158015620000b257600080fd5b505af1158015620000c7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000ed919062000b53565b5073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff1663095ea7b373d093fa4fb80d09bb30817fdcd442d4d02ed3e5de7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040518363ffffffff1660e01b81526004016200017392919062000d33565b602060405180830381600087803b1580156200018e57600080fd5b505af1158015620001a3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001c9919062000b53565b506200024473f8fd466f12e236f4c96f7cce6c79eadb819abf587fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73dac17f958d2ee523a2206206994597c13d831ec773ffffffffffffffffffffffffffffffffffffffff166200071060201b62001742179092919060201c565b736b175474e89094c44da98b954eedeac495271d0f73ffffffffffffffffffffffffffffffffffffffff1663095ea7b373ba12222222228d8ba445958a75a0704d566bf2c87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040518363ffffffff1660e01b8152600401620002c992919062000d33565b602060405180830381600087803b158015620002e457600080fd5b505af1158015620002f9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200031f919062000b53565b5073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff1663095ea7b373ba12222222228d8ba445958a75a0704d566bf2c87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040518363ffffffff1660e01b8152600401620003a592919062000d33565b602060405180830381600087803b158015620003c057600080fd5b505af1158015620003d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003fb919062000b53565b506200047673ba12222222228d8ba445958a75a0704d566bf2c87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff73dac17f958d2ee523a2206206994597c13d831ec773ffffffffffffffffffffffffffffffffffffffff166200071060201b62001742179092919060201c565b7302d60b84491589974263d922d9cc7a3152618ef673ffffffffffffffffffffffffffffffffffffffff1663095ea7b373ba12222222228d8ba445958a75a0704d566bf2c87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040518363ffffffff1660e01b8152600401620004fb92919062000d33565b602060405180830381600087803b1580156200051657600080fd5b505af11580156200052b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000551919062000b53565b5073d093fa4fb80d09bb30817fdcd442d4d02ed3e5de73ffffffffffffffffffffffffffffffffffffffff1663095ea7b373ba12222222228d8ba445958a75a0704d566bf2c87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040518363ffffffff1660e01b8152600401620005d792919062000d33565b602060405180830381600087803b158015620005f257600080fd5b505af115801562000607573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200062d919062000b53565b5073f8fd466f12e236f4c96f7cce6c79eadb819abf5873ffffffffffffffffffffffffffffffffffffffff1663095ea7b373ba12222222228d8ba445958a75a0704d566bf2c87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6040518363ffffffff1660e01b8152600401620006b392919062000d33565b602060405180830381600087803b158015620006ce57600080fd5b505af1158015620006e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000709919062000b53565b506200101e565b6000811480620007b2575060008373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b81526004016200075a92919062000d06565b602060405180830381600087803b1580156200077557600080fd5b505af11580156200078a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007b0919062000b85565b145b620007f4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620007eb9062000dea565b60405180910390fd5b6200087f8363095ea7b360e01b84846040516024016200081692919062000d33565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506200088460201b60201c565b505050565b6000620008ed826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166200095860201b620018a2179092919060201c565b905060008151111562000953578080602001905181019062000910919062000b53565b62000952576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620009499062000dc8565b60405180910390fd5b5b505050565b60606200096f84846000856200097860201b60201c565b90509392505050565b606082471015620009c0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620009b79062000d84565b60405180910390fd5b620009d18562000aa660201b60201c565b62000a13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000a0a9062000da6565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405162000a3e919062000ced565b60006040518083038185875af1925050503d806000811462000a7d576040519150601f19603f3d011682016040523d82523d6000602084013e62000a82565b606091505b509150915062000a9a82828662000ab960201b60201c565b92505050949350505050565b600080823b905060008111915050919050565b6060831562000acb5782905062000b1e565b60008351111562000adf5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000b15919062000d60565b60405180910390fd5b9392505050565b60008151905062000b368162000fea565b92915050565b60008151905062000b4d8162001004565b92915050565b60006020828403121562000b6c5762000b6b62000ebe565b5b600062000b7c8482850162000b25565b91505092915050565b60006020828403121562000b9e5762000b9d62000ebe565b5b600062000bae8482850162000b3c565b91505092915050565b62000bc28162000e3e565b82525050565b600062000bd58262000e0c565b62000be1818562000e22565b935062000bf381856020860162000e88565b80840191505092915050565b600062000c0c8262000e17565b62000c18818562000e2d565b935062000c2a81856020860162000e88565b62000c358162000ec3565b840191505092915050565b600062000c4f60268362000e2d565b915062000c5c8262000ed4565b604082019050919050565b600062000c76601d8362000e2d565b915062000c838262000f23565b602082019050919050565b600062000c9d602a8362000e2d565b915062000caa8262000f4c565b604082019050919050565b600062000cc460368362000e2d565b915062000cd18262000f9b565b604082019050919050565b62000ce78162000e7e565b82525050565b600062000cfb828462000bc8565b915081905092915050565b600060408201905062000d1d600083018562000bb7565b62000d2c602083018462000bb7565b9392505050565b600060408201905062000d4a600083018562000bb7565b62000d59602083018462000cdc565b9392505050565b6000602082019050818103600083015262000d7c818462000bff565b905092915050565b6000602082019050818103600083015262000d9f8162000c40565b9050919050565b6000602082019050818103600083015262000dc18162000c67565b9050919050565b6000602082019050818103600083015262000de38162000c8e565b9050919050565b6000602082019050818103600083015262000e058162000cb5565b9050919050565b600081519050919050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b600062000e4b8262000e5e565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b8381101562000ea857808201518184015260208101905062000e8b565b8381111562000eb8576000848401525b50505050565b600080fd5b6000601f19601f8301169050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60008201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000602082015250565b62000ff58162000e52565b81146200100157600080fd5b50565b6200100f8162000e7e565b81146200101b57600080fd5b50565b61394c806200102e6000396000f3fe6080604052600436106100595760003560e01c80631e5d7e0b1461006557806339e1acb9146100a25780633da9b9d0146100e05780636080763b146100fc578063e9cbafb014610139578063f072876b1461015557610060565b3661006057005b600080fd5b34801561007157600080fd5b5061008c60048036038101906100879190612a1d565b610192565b60405161009991906131f2565b60405180910390f35b3480156100ae57600080fd5b506100c960048036038101906100c49190612879565b610207565b6040516100d7929190613176565b60405180910390f35b6100fa60048036038101906100f59190612879565b610a77565b005b34801561010857600080fd5b50610123600480360381019061011e9190612a1d565b610d73565b60405161013091906131f2565b60405180910390f35b610153600480360381019061014e91906129a9565b610dd0565b005b34801561016157600080fd5b5061017c60048036038101906101779190612879565b611107565b60405161018991906131f2565b60405180910390f35b6000670de0b6b3a764000084876101a99190613396565b6101b39190613365565b955060006101c28787856118ba565b90506001846001670de0b6b3a7640000846101dd9190613396565b6101e791906133f0565b6101f19190613365565b6101fb919061330f565b91505095945050505050565b61020f6122f3565b60008060405180606001604052808673ffffffffffffffffffffffffffffffffffffffff166355c676286040518163ffffffff1660e01b815260040160206040518083038186803b15801561026357600080fd5b505afa158015610277573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061029b919061293c565b815260200160008152602001600081525090508473ffffffffffffffffffffffffffffffffffffffff166363fe3b566040518163ffffffff1660e01b8152600401604080518083038186803b1580156102f357600080fd5b505afa158015610307573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032b9190612969565b82602001836040018281525082815250505060008573ffffffffffffffffffffffffffffffffffffffff16631dd746ea6040518163ffffffff1660e01b815260040160006040518083038186803b15801561038557600080fd5b505afa158015610399573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906103c291906127d6565b905060008673ffffffffffffffffffffffffffffffffffffffff16634d64cd746040518163ffffffff1660e01b815260040160206040518083038186803b15801561040c57600080fd5b505afa158015610420573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610444919061293c565b905060008073ba12222222228d8ba445958a75a0704d566bf2c873ffffffffffffffffffffffffffffffffffffffff1663f94d46688a73ffffffffffffffffffffffffffffffffffffffff166338fff2d06040518163ffffffff1660e01b815260040160206040518083038186803b1580156104bf57600080fd5b505afa1580156104d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f7919061284c565b6040518263ffffffff1660e01b81526004016105139190612fed565b60006040518083038186803b15801561052b57600080fd5b505afa15801561053f573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610568919061275e565b915091506000818481518110610581576105806135f1565b5b6020026020010151905060008914156106755760008585815181106105a9576105a86135f1565b5b6020026020010151670de0b6b3a764000088604001516105c99190613396565b6105d39190613365565b905060008686815181106105ea576105e96135f1565b5b6020026020010151670de0b6b3a7640000896040015161060a9190613396565b6106149190613365565b90508183111561062657819a50610672565b8083101561063657809a50610671565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106689061302a565b60405180910390fd5b5b50505b600089821061068f57898261068a91906133f0565b61069c565b818a61069b91906133f0565b5b90508982106107a05761079b81670de0b6b3a76400008888815181106106c5576106c46135f1565b5b6020026020010151856106d89190613396565b6106e29190613365565b8888815181106106f5576106f46135f1565b5b6020026020010151898f73ffffffffffffffffffffffffffffffffffffffff166316b8d6ff6040518163ffffffff1660e01b815260040160206040518083038186803b15801561074457600080fd5b505afa158015610758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077c919061293c565b8151811061078d5761078c6135f1565b5b60200260200101518b610192565b6107a2565b805b97506040518060c001604052808c73ffffffffffffffffffffffffffffffffffffffff166338fff2d06040518163ffffffff1660e01b815260040160206040518083038186803b1580156107f557600080fd5b505afa158015610809573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082d919061284c565b81526020018b8411610840576000610843565b60015b6001811115610855576108546135c2565b5b81526020018b841161088157858781518110610874576108736135f1565b5b602002602001015161091a565b858d73ffffffffffffffffffffffffffffffffffffffff166316b8d6ff6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108c857600080fd5b505afa1580156108dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610900919061293c565b81518110610911576109106135f1565b5b60200260200101515b73ffffffffffffffffffffffffffffffffffffffff1681526020018b84116109d957858d73ffffffffffffffffffffffffffffffffffffffff166316b8d6ff6040518163ffffffff1660e01b815260040160206040518083038186803b15801561098357600080fd5b505afa158015610997573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bb919061293c565b815181106109cc576109cb6135f1565b5b60200260200101516109f5565b8587815181106109ec576109eb6135f1565b5b60200260200101515b73ffffffffffffffffffffffffffffffffffffffff168152602001828152602001600067ffffffffffffffff811115610a3157610a30613620565b5b6040519080825280601f01601f191660200182016040528015610a635781602001600182028036833780820191505090505b508152509850505050505050509250929050565b600080610a848484610207565b915091506000806001811115610a9d57610a9c6135c2565b5b83602001516001811115610ab457610ab36135c2565b5b14610ac3578260600151610ac9565b82604001515b90506000736b175474e89094c44da98b954eedeac495271d0f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610b2e57733416cf6c708da44db2624d63ea0aaef7113527c6610b44565b735777d92f208679db4b9778590fa3cab3ac9e21685b90506000806001811115610b5b57610b5a6135c2565b5b85602001516001811115610b7257610b716135c2565b5b14610c0957846040015173ffffffffffffffffffffffffffffffffffffffff1663f57d0b40856040518263ffffffff1660e01b8152600401610bb491906131f2565b60206040518083038186803b158015610bcc57600080fd5b505afa158015610be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c04919061293c565b610c0b565b835b9050600085828633604051602001610c2694939291906131a6565b604051602081830303815290604052905073dac17f958d2ee523a2206206994597c13d831ec773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415610cf6578273ffffffffffffffffffffffffffffffffffffffff1663490e6cbc30600085856040518563ffffffff1660e01b8152600401610cbf9493929190612eb0565b600060405180830381600087803b158015610cd957600080fd5b505af1158015610ced573d6000803e3d6000fd5b50505050610d69565b8273ffffffffffffffffffffffffffffffffffffffff1663490e6cbc30846000856040518563ffffffff1660e01b8152600401610d369493929190612fa1565b600060405180830381600087803b158015610d5057600080fd5b505af1158015610d64573d6000803e3d6000fd5b505050505b5050505050505050565b6000670de0b6b3a76400008487610d8a9190613396565b610d949190613365565b95506000610da3878785611907565b905083670de0b6b3a764000082610dba9190613396565b610dc49190613365565b91505095945050505050565b6000806000808585810190610de591906128b9565b93509350935093506000806001811115610e0257610e016135c2565b5b85602001516001811115610e1957610e186135c2565b5b14610e28578460600151610e2e565b84604001515b9050735777d92f208679db4b9778590fa3cab3ac9e216873ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610ebd5750733416cf6c708da44db2624d63ea0aaef7113527c673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b610efc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ef39061304a565b60405180910390fd5b838173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610f369190612e35565b60206040518083038186803b158015610f4e57600080fd5b505afa158015610f62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f86919061293c565b1015610fc7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fbe9061308a565b60405180910390fd5b610fd2858585611954565b6000600161271086610fe49190613365565b86610fef919061330f565b610ff9919061330f565b905060008273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016110369190612e35565b60206040518083038186803b15801561104e57600080fd5b505afa158015611062573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611086919061293c565b9050818110156110cf576000818361109e91906133f0565b90506110cd8530838773ffffffffffffffffffffffffffffffffffffffff16611c8e909392919063ffffffff16565b505b6110fa33838573ffffffffffffffffffffffffffffffffffffffff16611d179092919063ffffffff16565b5050505050505050505050565b60008060006111168585610207565b91509150600080600181111561112f5761112e6135c2565b5b83602001516001811115611146576111456135c2565b5b146111dd57826040015173ffffffffffffffffffffffffffffffffffffffff1663f57d0b40836040518263ffffffff1660e01b815260040161118891906131f2565b60206040518083038186803b1580156111a057600080fd5b505afa1580156111b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d8919061293c565b6111df565b815b90506001612710826111f19190613365565b6111fb919061330f565b81611206919061330f565b905060008360800151905060006001811115611225576112246135c2565b5b8460200151600181111561123c5761123b6135c2565b5b141561171a57600060405180606001604052808973ffffffffffffffffffffffffffffffffffffffff166355c676286040518163ffffffff1660e01b815260040160206040518083038186803b15801561129557600080fd5b505afa1580156112a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cd919061293c565b815260200160008152602001600081525090508773ffffffffffffffffffffffffffffffffffffffff166363fe3b566040518163ffffffff1660e01b8152600401604080518083038186803b15801561132557600080fd5b505afa158015611339573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135d9190612969565b82602001836040018281525082815250505060008873ffffffffffffffffffffffffffffffffffffffff16631dd746ea6040518163ffffffff1660e01b815260040160006040518083038186803b1580156113b757600080fd5b505afa1580156113cb573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906113f491906127d6565b905060008973ffffffffffffffffffffffffffffffffffffffff16634d64cd746040518163ffffffff1660e01b815260040160206040518083038186803b15801561143e57600080fd5b505afa158015611452573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611476919061293c565b905060008a73ffffffffffffffffffffffffffffffffffffffff166316b8d6ff6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114c057600080fd5b505afa1580156114d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f8919061293c565b9050600073ba12222222228d8ba445958a75a0704d566bf2c873ffffffffffffffffffffffffffffffffffffffff1663f94d46688d73ffffffffffffffffffffffffffffffffffffffff166338fff2d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561157257600080fd5b505afa158015611586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115aa919061284c565b6040518263ffffffff1660e01b81526004016115c69190612fed565b60006040518083038186803b1580156115de57600080fd5b505afa1580156115f2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061161b919061275e565b9150506000818481518110611633576116326135f1565b5b602002602001015190506116828a6080015182878781518110611659576116586135f1565b5b6020026020010151888781518110611674576116736135f1565b5b60200260200101518a610d73565b9650896060015173ffffffffffffffffffffffffffffffffffffffff1663f57d0b40886040518263ffffffff1660e01b81526004016116c191906131f2565b60206040518083038186803b1580156116d957600080fd5b505afa1580156116ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611711919061293c565b96505050505050505b8181101561173357808261172e91906133f0565b611736565b60005b94505050505092915050565b60008114806117dd575060008373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401611789929190612e50565b602060405180830381600087803b1580156117a357600080fd5b505af11580156117b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117db919061293c565b145b61181c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118139061310a565b60405180910390fd5b61189d8363095ea7b360e01b848460405160240161183b929190612efc565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611d9d565b505050565b60606118b18484600085611e64565b90509392505050565b6000806118c78484611f78565b905060006118e76118e1878761202590919063ffffffff16565b85611f78565b90506118fc818361202590919063ffffffff16565b925050509392505050565b6000806119148484611f78565b9050600061193461192e878761204f90919063ffffffff16565b85611f78565b9050611949828261202590919063ffffffff16565b925050509392505050565b6000806001811115611969576119686135c2565b5b846020015160018111156119805761197f6135c2565b5b146119ab577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6119ae565b60005b9050600060405180608001604052803073ffffffffffffffffffffffffffffffffffffffff1681526020016000151581526020013073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152509050600180811115611a1a57611a196135c2565b5b85602001516001811115611a3157611a306135c2565b5b1415611a4657611a45856040015185612078565b5b82856040015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611a849190612e35565b60206040518083038186803b158015611a9c57600080fd5b505afa158015611ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad4919061293c565b1015611b15576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b0c906130aa565b60405180910390fd5b73ba12222222228d8ba445958a75a0704d566bf2c873ffffffffffffffffffffffffffffffffffffffff166352bbbe29868385426040518563ffffffff1660e01b8152600401611b68949392919061312a565b602060405180830381600087803b158015611b8257600080fd5b505af1158015611b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bba919061293c565b5060006001811115611bcf57611bce6135c2565b5b85602001516001811115611be657611be56135c2565b5b1415611c8757611c868560600151866060015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611c319190612e35565b60206040518083038186803b158015611c4957600080fd5b505afa158015611c5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c81919061293c565b612110565b5b5050505050565b611d11846323b872dd60e01b858585604051602401611caf93929190612e79565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611d9d565b50505050565b611d988363a9059cbb60e01b8484604051602401611d36929190612efc565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611d9d565b505050565b6000611dff826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166118a29092919063ffffffff16565b9050600081511115611e5f5780806020019051810190611e1f919061281f565b611e5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e55906130ea565b60405180910390fd5b5b505050565b606082471015611ea9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ea09061306a565b60405180910390fd5b611eb2856121a5565b611ef1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ee8906130ca565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611f1a9190612e1e565b60006040518083038185875af1925050503d8060008114611f57576040519150601f19603f3d011682016040523d82523d6000602084013e611f5c565b606091505b5091509150611f6c8282866121b8565b92505050949350505050565b60008160200151831015611fcb576000611fae8360000151858560200151611fa091906133f0565b61221f90919063ffffffff16565b9050611fc3818561202590919063ffffffff16565b91505061201f565b81604001518311611fde5782905061201f565b60006120068360000151846040015186611ff891906133f0565b61221f90919063ffffffff16565b905061201b818561202590919063ffffffff16565b9150505b92915050565b6000612035838311156001612270565b6000828461204391906133f0565b90508091505092915050565b600080828461205e919061330f565b905061206e848210156000612270565b8091505092915050565b8173ffffffffffffffffffffffffffffffffffffffff16632f2cab873083600060016040518563ffffffff1660e01b81526004016120b99493929190612f5c565b602060405180830381600087803b1580156120d357600080fd5b505af11580156120e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210b919061293c565b505050565b8173ffffffffffffffffffffffffffffffffffffffff1663ead5d359308360016040518463ffffffff1660e01b815260040161214e93929190612f25565b6040805180830381600087803b15801561216757600080fd5b505af115801561217b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061219f9190612969565b50505050565b600080823b905060008111915050919050565b606083156121c857829050612218565b6000835111156121db5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161220f9190613008565b60405180910390fd5b9392505050565b600080828461222e9190613396565b9050612253600085148061224c575083858361224a9190613365565b145b6003612270565b670de0b6b3a7640000816122679190613365565b91505092915050565b8161227f5761227e81612283565b5b5050565b6030600a820601600a820491506030600a830601600a830492506030600a8406018060101b8260081b8401016642414c230000000160c81b7f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260076024528060445260646000fd5b6040518060c00160405280600080191681526020016000600181111561231c5761231b6135c2565b5b8152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001606081525090565b600061237d61237884613232565b61320d565b905080838252602082019050828560208602820111156123a05761239f613663565b5b60005b858110156123d057816123b688826124a1565b8452602084019350602083019250506001810190506123a3565b5050509392505050565b60006123ed6123e88461325e565b61320d565b905080838252602082019050828560208602820111156124105761240f613663565b5b60005b8581101561244057816124268882612749565b845260208401935060208301925050600181019050612413565b5050509392505050565b600061245d6124588461328a565b61320d565b90508281526020810184848401111561247957612478613668565b5b6124848482856134f1565b509392505050565b60008135905061249b8161387c565b92915050565b6000815190506124b08161387c565b92915050565b6000813590506124c581613893565b92915050565b600082601f8301126124e0576124df613654565b5b81516124f084826020860161236a565b91505092915050565b600082601f83011261250e5761250d613654565b5b815161251e8482602086016123da565b91505092915050565b600081519050612536816138aa565b92915050565b60008135905061254b816138c1565b92915050565b600081519050612560816138c1565b92915050565b60008083601f84011261257c5761257b613654565b5b8235905067ffffffffffffffff8111156125995761259861364f565b5b6020830191508360018202830111156125b5576125b4613663565b5b9250929050565b600082601f8301126125d1576125d0613654565b5b81356125e184826020860161244a565b91505092915050565b6000813590506125f9816138d8565b92915050565b60008135905061260e816138ef565b92915050565b60006060828403121561262a57612629613659565b5b612634606061320d565b9050600061264484828501612734565b600083015250602061265884828501612734565b602083015250604061266c84828501612734565b60408301525092915050565b600060c0828403121561268e5761268d613659565b5b61269860c061320d565b905060006126a88482850161253c565b60008301525060206126bc848285016125ff565b60208301525060406126d08482850161248c565b60408301525060606126e48482850161248c565b60608301525060806126f884828501612734565b60808301525060a082013567ffffffffffffffff81111561271c5761271b61365e565b5b612728848285016125bc565b60a08301525092915050565b600081359050612743816138ff565b92915050565b600081519050612758816138ff565b92915050565b6000806040838503121561277557612774613672565b5b600083015167ffffffffffffffff8111156127935761279261366d565b5b61279f858286016124cb565b925050602083015167ffffffffffffffff8111156127c0576127bf61366d565b5b6127cc858286016124f9565b9150509250929050565b6000602082840312156127ec576127eb613672565b5b600082015167ffffffffffffffff81111561280a5761280961366d565b5b612816848285016124f9565b91505092915050565b60006020828403121561283557612834613672565b5b600061284384828501612527565b91505092915050565b60006020828403121561286257612861613672565b5b600061287084828501612551565b91505092915050565b600080604083850312156128905761288f613672565b5b600061289e858286016125ea565b92505060206128af85828601612734565b9150509250929050565b600080600080608085870312156128d3576128d2613672565b5b600085013567ffffffffffffffff8111156128f1576128f061366d565b5b6128fd87828801612678565b945050602061290e87828801612734565b935050604061291f87828801612734565b9250506060612930878288016124b6565b91505092959194509250565b60006020828403121561295257612951613672565b5b600061296084828501612749565b91505092915050565b600080604083850312156129805761297f613672565b5b600061298e85828601612749565b925050602061299f85828601612749565b9150509250929050565b600080600080606085870312156129c3576129c2613672565b5b60006129d187828801612734565b94505060206129e287828801612734565b935050604085013567ffffffffffffffff811115612a0357612a0261366d565b5b612a0f87828801612566565b925092505092959194509250565b600080600080600060e08688031215612a3957612a38613672565b5b6000612a4788828901612734565b9550506020612a5888828901612734565b9450506040612a6988828901612734565b9350506060612a7a88828901612734565b9250506080612a8b88828901612614565b9150509295509295909350565b612aa181613436565b82525050565b612ab081613424565b82525050565b612abf81613424565b82525050565b612ace81613448565b82525050565b612add81613448565b82525050565b612aec81613454565b82525050565b612afb81613454565b82525050565b6000612b0c826132bb565b612b1681856132d1565b9350612b26818560208601613500565b612b2f81613677565b840191505092915050565b6000612b45826132bb565b612b4f81856132e2565b9350612b5f818560208601613500565b612b6881613677565b840191505092915050565b6000612b7e826132bb565b612b8881856132f3565b9350612b98818560208601613500565b80840191505092915050565b612bad816134bb565b82525050565b612bbc816134cd565b82525050565b612bcb816134df565b82525050565b6000612bdc826132c6565b612be681856132fe565b9350612bf6818560208601613500565b612bff81613677565b840191505092915050565b6000612c176031836132fe565b9150612c2282613688565b604082019050919050565b6000612c3a6009836132fe565b9150612c45826136d7565b602082019050919050565b6000612c5d6026836132fe565b9150612c6882613700565b604082019050919050565b6000612c806016836132fe565b9150612c8b8261374f565b602082019050919050565b6000612ca3601b836132fe565b9150612cae82613778565b602082019050919050565b6000612cc6601d836132fe565b9150612cd1826137a1565b602082019050919050565b6000612ce9602a836132fe565b9150612cf4826137ca565b604082019050919050565b6000612d0c6036836132fe565b9150612d1782613819565b604082019050919050565b608082016000820151612d386000850182612aa7565b506020820151612d4b6020850182612ac5565b506040820151612d5e6040850182612a98565b506060820151612d716060850182612ac5565b50505050565b600060c083016000830151612d8f6000860182612ae3565b506020830151612da26020860182612ba4565b506040830151612db56040860182612aa7565b506060830151612dc86060860182612aa7565b506080830151612ddb6080860182612e00565b5060a083015184820360a0860152612df38282612b01565b9150508091505092915050565b612e09816134b1565b82525050565b612e18816134b1565b82525050565b6000612e2a8284612b73565b915081905092915050565b6000602082019050612e4a6000830184612ab6565b92915050565b6000604082019050612e656000830185612ab6565b612e726020830184612ab6565b9392505050565b6000606082019050612e8e6000830186612ab6565b612e9b6020830185612ab6565b612ea86040830184612e0f565b949350505050565b6000608082019050612ec56000830187612ab6565b612ed26020830186612bc2565b612edf6040830185612e0f565b8181036060830152612ef18184612b3a565b905095945050505050565b6000604082019050612f116000830185612ab6565b612f1e6020830184612e0f565b9392505050565b6000606082019050612f3a6000830186612ab6565b612f476020830185612e0f565b612f546040830184612ad4565b949350505050565b6000608082019050612f716000830187612ab6565b612f7e6020830186612e0f565b612f8b6040830185612bb3565b612f986060830184612ad4565b95945050505050565b6000608082019050612fb66000830187612ab6565b612fc36020830186612e0f565b612fd06040830185612bc2565b8181036060830152612fe28184612b3a565b905095945050505050565b60006020820190506130026000830184612af2565b92915050565b600060208201905081810360008301526130228184612bd1565b905092915050565b6000602082019050818103600083015261304381612c0a565b9050919050565b6000602082019050818103600083015261306381612c2d565b9050919050565b6000602082019050818103600083015261308381612c50565b9050919050565b600060208201905081810360008301526130a381612c73565b9050919050565b600060208201905081810360008301526130c381612c96565b9050919050565b600060208201905081810360008301526130e381612cb9565b9050919050565b6000602082019050818103600083015261310381612cdc565b9050919050565b6000602082019050818103600083015261312381612cff565b9050919050565b600060e08201905081810360008301526131448187612d77565b90506131536020830186612d22565b61316060a0830185612e0f565b61316d60c0830184612e0f565b95945050505050565b600060408201905081810360008301526131908185612d77565b905061319f6020830184612e0f565b9392505050565b600060808201905081810360008301526131c08187612d77565b90506131cf6020830186612e0f565b6131dc6040830185612e0f565b6131e96060830184612ab6565b95945050505050565b60006020820190506132076000830184612e0f565b92915050565b6000613217613228565b90506132238282613533565b919050565b6000604051905090565b600067ffffffffffffffff82111561324d5761324c613620565b5b602082029050602081019050919050565b600067ffffffffffffffff82111561327957613278613620565b5b602082029050602081019050919050565b600067ffffffffffffffff8211156132a5576132a4613620565b5b6132ae82613677565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600061331a826134b1565b9150613325836134b1565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561335a57613359613564565b5b828201905092915050565b6000613370826134b1565b915061337b836134b1565b92508261338b5761338a613593565b5b828204905092915050565b60006133a1826134b1565b91506133ac836134b1565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156133e5576133e4613564565b5b828202905092915050565b60006133fb826134b1565b9150613406836134b1565b92508282101561341957613418613564565b5b828203905092915050565b600061342f82613491565b9050919050565b600061344182613491565b9050919050565b60008115159050919050565b6000819050919050565b600061346982613424565b9050919050565b600081905061347e82613868565b919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006134c682613470565b9050919050565b60006134d882613483565b9050919050565b60006134ea826134b1565b9050919050565b82818337600083830152505050565b60005b8381101561351e578082015181840152602081019050613503565b8381111561352d576000848401525b50505050565b61353c82613677565b810181811067ffffffffffffffff8211171561355b5761355a613620565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f416c726561647920696e2072616e676520616e64206e6f20646573697265642060008201527f62616c616e636520737065636966696564000000000000000000000000000000602082015250565b7f62616420332e206e6f0000000000000000000000000000000000000000000000600082015250565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b7f466c617368206c6f616e206469646e7420646f20697400000000000000000000600082015250565b7f4e6f7420656e6f75676820617373657420696e2062616c616e63650000000000600082015250565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60008201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000602082015250565b60028110613879576138786135c2565b5b50565b61388581613424565b811461389057600080fd5b50565b61389c81613436565b81146138a757600080fd5b50565b6138b381613448565b81146138be57600080fd5b50565b6138ca81613454565b81146138d557600080fd5b50565b6138e18161345e565b81146138ec57600080fd5b50565b600281106138fc57600080fd5b50565b613908816134b1565b811461391357600080fd5b5056fea264697066735822122024370afc30adeea5c7a13ebe78a7682b043835437839c3bbee9e629ec1c32e0764736f6c63430008070033
Deployed Bytecode
0x6080604052600436106100595760003560e01c80631e5d7e0b1461006557806339e1acb9146100a25780633da9b9d0146100e05780636080763b146100fc578063e9cbafb014610139578063f072876b1461015557610060565b3661006057005b600080fd5b34801561007157600080fd5b5061008c60048036038101906100879190612a1d565b610192565b60405161009991906131f2565b60405180910390f35b3480156100ae57600080fd5b506100c960048036038101906100c49190612879565b610207565b6040516100d7929190613176565b60405180910390f35b6100fa60048036038101906100f59190612879565b610a77565b005b34801561010857600080fd5b50610123600480360381019061011e9190612a1d565b610d73565b60405161013091906131f2565b60405180910390f35b610153600480360381019061014e91906129a9565b610dd0565b005b34801561016157600080fd5b5061017c60048036038101906101779190612879565b611107565b60405161018991906131f2565b60405180910390f35b6000670de0b6b3a764000084876101a99190613396565b6101b39190613365565b955060006101c28787856118ba565b90506001846001670de0b6b3a7640000846101dd9190613396565b6101e791906133f0565b6101f19190613365565b6101fb919061330f565b91505095945050505050565b61020f6122f3565b60008060405180606001604052808673ffffffffffffffffffffffffffffffffffffffff166355c676286040518163ffffffff1660e01b815260040160206040518083038186803b15801561026357600080fd5b505afa158015610277573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061029b919061293c565b815260200160008152602001600081525090508473ffffffffffffffffffffffffffffffffffffffff166363fe3b566040518163ffffffff1660e01b8152600401604080518083038186803b1580156102f357600080fd5b505afa158015610307573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061032b9190612969565b82602001836040018281525082815250505060008573ffffffffffffffffffffffffffffffffffffffff16631dd746ea6040518163ffffffff1660e01b815260040160006040518083038186803b15801561038557600080fd5b505afa158015610399573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906103c291906127d6565b905060008673ffffffffffffffffffffffffffffffffffffffff16634d64cd746040518163ffffffff1660e01b815260040160206040518083038186803b15801561040c57600080fd5b505afa158015610420573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610444919061293c565b905060008073ba12222222228d8ba445958a75a0704d566bf2c873ffffffffffffffffffffffffffffffffffffffff1663f94d46688a73ffffffffffffffffffffffffffffffffffffffff166338fff2d06040518163ffffffff1660e01b815260040160206040518083038186803b1580156104bf57600080fd5b505afa1580156104d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104f7919061284c565b6040518263ffffffff1660e01b81526004016105139190612fed565b60006040518083038186803b15801561052b57600080fd5b505afa15801561053f573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f82011682018060405250810190610568919061275e565b915091506000818481518110610581576105806135f1565b5b6020026020010151905060008914156106755760008585815181106105a9576105a86135f1565b5b6020026020010151670de0b6b3a764000088604001516105c99190613396565b6105d39190613365565b905060008686815181106105ea576105e96135f1565b5b6020026020010151670de0b6b3a7640000896040015161060a9190613396565b6106149190613365565b90508183111561062657819a50610672565b8083101561063657809a50610671565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106689061302a565b60405180910390fd5b5b50505b600089821061068f57898261068a91906133f0565b61069c565b818a61069b91906133f0565b5b90508982106107a05761079b81670de0b6b3a76400008888815181106106c5576106c46135f1565b5b6020026020010151856106d89190613396565b6106e29190613365565b8888815181106106f5576106f46135f1565b5b6020026020010151898f73ffffffffffffffffffffffffffffffffffffffff166316b8d6ff6040518163ffffffff1660e01b815260040160206040518083038186803b15801561074457600080fd5b505afa158015610758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061077c919061293c565b8151811061078d5761078c6135f1565b5b60200260200101518b610192565b6107a2565b805b97506040518060c001604052808c73ffffffffffffffffffffffffffffffffffffffff166338fff2d06040518163ffffffff1660e01b815260040160206040518083038186803b1580156107f557600080fd5b505afa158015610809573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082d919061284c565b81526020018b8411610840576000610843565b60015b6001811115610855576108546135c2565b5b81526020018b841161088157858781518110610874576108736135f1565b5b602002602001015161091a565b858d73ffffffffffffffffffffffffffffffffffffffff166316b8d6ff6040518163ffffffff1660e01b815260040160206040518083038186803b1580156108c857600080fd5b505afa1580156108dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610900919061293c565b81518110610911576109106135f1565b5b60200260200101515b73ffffffffffffffffffffffffffffffffffffffff1681526020018b84116109d957858d73ffffffffffffffffffffffffffffffffffffffff166316b8d6ff6040518163ffffffff1660e01b815260040160206040518083038186803b15801561098357600080fd5b505afa158015610997573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bb919061293c565b815181106109cc576109cb6135f1565b5b60200260200101516109f5565b8587815181106109ec576109eb6135f1565b5b60200260200101515b73ffffffffffffffffffffffffffffffffffffffff168152602001828152602001600067ffffffffffffffff811115610a3157610a30613620565b5b6040519080825280601f01601f191660200182016040528015610a635781602001600182028036833780820191505090505b508152509850505050505050509250929050565b600080610a848484610207565b915091506000806001811115610a9d57610a9c6135c2565b5b83602001516001811115610ab457610ab36135c2565b5b14610ac3578260600151610ac9565b82604001515b90506000736b175474e89094c44da98b954eedeac495271d0f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614610b2e57733416cf6c708da44db2624d63ea0aaef7113527c6610b44565b735777d92f208679db4b9778590fa3cab3ac9e21685b90506000806001811115610b5b57610b5a6135c2565b5b85602001516001811115610b7257610b716135c2565b5b14610c0957846040015173ffffffffffffffffffffffffffffffffffffffff1663f57d0b40856040518263ffffffff1660e01b8152600401610bb491906131f2565b60206040518083038186803b158015610bcc57600080fd5b505afa158015610be0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c04919061293c565b610c0b565b835b9050600085828633604051602001610c2694939291906131a6565b604051602081830303815290604052905073dac17f958d2ee523a2206206994597c13d831ec773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161415610cf6578273ffffffffffffffffffffffffffffffffffffffff1663490e6cbc30600085856040518563ffffffff1660e01b8152600401610cbf9493929190612eb0565b600060405180830381600087803b158015610cd957600080fd5b505af1158015610ced573d6000803e3d6000fd5b50505050610d69565b8273ffffffffffffffffffffffffffffffffffffffff1663490e6cbc30846000856040518563ffffffff1660e01b8152600401610d369493929190612fa1565b600060405180830381600087803b158015610d5057600080fd5b505af1158015610d64573d6000803e3d6000fd5b505050505b5050505050505050565b6000670de0b6b3a76400008487610d8a9190613396565b610d949190613365565b95506000610da3878785611907565b905083670de0b6b3a764000082610dba9190613396565b610dc49190613365565b91505095945050505050565b6000806000808585810190610de591906128b9565b93509350935093506000806001811115610e0257610e016135c2565b5b85602001516001811115610e1957610e186135c2565b5b14610e28578460600151610e2e565b84604001515b9050735777d92f208679db4b9778590fa3cab3ac9e216873ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610ebd5750733416cf6c708da44db2624d63ea0aaef7113527c673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b610efc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ef39061304a565b60405180910390fd5b838173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610f369190612e35565b60206040518083038186803b158015610f4e57600080fd5b505afa158015610f62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f86919061293c565b1015610fc7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fbe9061308a565b60405180910390fd5b610fd2858585611954565b6000600161271086610fe49190613365565b86610fef919061330f565b610ff9919061330f565b905060008273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016110369190612e35565b60206040518083038186803b15801561104e57600080fd5b505afa158015611062573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611086919061293c565b9050818110156110cf576000818361109e91906133f0565b90506110cd8530838773ffffffffffffffffffffffffffffffffffffffff16611c8e909392919063ffffffff16565b505b6110fa33838573ffffffffffffffffffffffffffffffffffffffff16611d179092919063ffffffff16565b5050505050505050505050565b60008060006111168585610207565b91509150600080600181111561112f5761112e6135c2565b5b83602001516001811115611146576111456135c2565b5b146111dd57826040015173ffffffffffffffffffffffffffffffffffffffff1663f57d0b40836040518263ffffffff1660e01b815260040161118891906131f2565b60206040518083038186803b1580156111a057600080fd5b505afa1580156111b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d8919061293c565b6111df565b815b90506001612710826111f19190613365565b6111fb919061330f565b81611206919061330f565b905060008360800151905060006001811115611225576112246135c2565b5b8460200151600181111561123c5761123b6135c2565b5b141561171a57600060405180606001604052808973ffffffffffffffffffffffffffffffffffffffff166355c676286040518163ffffffff1660e01b815260040160206040518083038186803b15801561129557600080fd5b505afa1580156112a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cd919061293c565b815260200160008152602001600081525090508773ffffffffffffffffffffffffffffffffffffffff166363fe3b566040518163ffffffff1660e01b8152600401604080518083038186803b15801561132557600080fd5b505afa158015611339573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135d9190612969565b82602001836040018281525082815250505060008873ffffffffffffffffffffffffffffffffffffffff16631dd746ea6040518163ffffffff1660e01b815260040160006040518083038186803b1580156113b757600080fd5b505afa1580156113cb573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906113f491906127d6565b905060008973ffffffffffffffffffffffffffffffffffffffff16634d64cd746040518163ffffffff1660e01b815260040160206040518083038186803b15801561143e57600080fd5b505afa158015611452573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611476919061293c565b905060008a73ffffffffffffffffffffffffffffffffffffffff166316b8d6ff6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114c057600080fd5b505afa1580156114d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f8919061293c565b9050600073ba12222222228d8ba445958a75a0704d566bf2c873ffffffffffffffffffffffffffffffffffffffff1663f94d46688d73ffffffffffffffffffffffffffffffffffffffff166338fff2d06040518163ffffffff1660e01b815260040160206040518083038186803b15801561157257600080fd5b505afa158015611586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115aa919061284c565b6040518263ffffffff1660e01b81526004016115c69190612fed565b60006040518083038186803b1580156115de57600080fd5b505afa1580156115f2573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f8201168201806040525081019061161b919061275e565b9150506000818481518110611633576116326135f1565b5b602002602001015190506116828a6080015182878781518110611659576116586135f1565b5b6020026020010151888781518110611674576116736135f1565b5b60200260200101518a610d73565b9650896060015173ffffffffffffffffffffffffffffffffffffffff1663f57d0b40886040518263ffffffff1660e01b81526004016116c191906131f2565b60206040518083038186803b1580156116d957600080fd5b505afa1580156116ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611711919061293c565b96505050505050505b8181101561173357808261172e91906133f0565b611736565b60005b94505050505092915050565b60008114806117dd575060008373ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30856040518363ffffffff1660e01b8152600401611789929190612e50565b602060405180830381600087803b1580156117a357600080fd5b505af11580156117b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117db919061293c565b145b61181c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118139061310a565b60405180910390fd5b61189d8363095ea7b360e01b848460405160240161183b929190612efc565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611d9d565b505050565b60606118b18484600085611e64565b90509392505050565b6000806118c78484611f78565b905060006118e76118e1878761202590919063ffffffff16565b85611f78565b90506118fc818361202590919063ffffffff16565b925050509392505050565b6000806119148484611f78565b9050600061193461192e878761204f90919063ffffffff16565b85611f78565b9050611949828261202590919063ffffffff16565b925050509392505050565b6000806001811115611969576119686135c2565b5b846020015160018111156119805761197f6135c2565b5b146119ab577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6119ae565b60005b9050600060405180608001604052803073ffffffffffffffffffffffffffffffffffffffff1681526020016000151581526020013073ffffffffffffffffffffffffffffffffffffffff168152602001600015158152509050600180811115611a1a57611a196135c2565b5b85602001516001811115611a3157611a306135c2565b5b1415611a4657611a45856040015185612078565b5b82856040015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611a849190612e35565b60206040518083038186803b158015611a9c57600080fd5b505afa158015611ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad4919061293c565b1015611b15576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b0c906130aa565b60405180910390fd5b73ba12222222228d8ba445958a75a0704d566bf2c873ffffffffffffffffffffffffffffffffffffffff166352bbbe29868385426040518563ffffffff1660e01b8152600401611b68949392919061312a565b602060405180830381600087803b158015611b8257600080fd5b505af1158015611b96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bba919061293c565b5060006001811115611bcf57611bce6135c2565b5b85602001516001811115611be657611be56135c2565b5b1415611c8757611c868560600151866060015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401611c319190612e35565b60206040518083038186803b158015611c4957600080fd5b505afa158015611c5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c81919061293c565b612110565b5b5050505050565b611d11846323b872dd60e01b858585604051602401611caf93929190612e79565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611d9d565b50505050565b611d988363a9059cbb60e01b8484604051602401611d36929190612efc565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611d9d565b505050565b6000611dff826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166118a29092919063ffffffff16565b9050600081511115611e5f5780806020019051810190611e1f919061281f565b611e5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e55906130ea565b60405180910390fd5b5b505050565b606082471015611ea9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ea09061306a565b60405180910390fd5b611eb2856121a5565b611ef1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ee8906130ca565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611f1a9190612e1e565b60006040518083038185875af1925050503d8060008114611f57576040519150601f19603f3d011682016040523d82523d6000602084013e611f5c565b606091505b5091509150611f6c8282866121b8565b92505050949350505050565b60008160200151831015611fcb576000611fae8360000151858560200151611fa091906133f0565b61221f90919063ffffffff16565b9050611fc3818561202590919063ffffffff16565b91505061201f565b81604001518311611fde5782905061201f565b60006120068360000151846040015186611ff891906133f0565b61221f90919063ffffffff16565b905061201b818561202590919063ffffffff16565b9150505b92915050565b6000612035838311156001612270565b6000828461204391906133f0565b90508091505092915050565b600080828461205e919061330f565b905061206e848210156000612270565b8091505092915050565b8173ffffffffffffffffffffffffffffffffffffffff16632f2cab873083600060016040518563ffffffff1660e01b81526004016120b99493929190612f5c565b602060405180830381600087803b1580156120d357600080fd5b505af11580156120e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061210b919061293c565b505050565b8173ffffffffffffffffffffffffffffffffffffffff1663ead5d359308360016040518463ffffffff1660e01b815260040161214e93929190612f25565b6040805180830381600087803b15801561216757600080fd5b505af115801561217b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061219f9190612969565b50505050565b600080823b905060008111915050919050565b606083156121c857829050612218565b6000835111156121db5782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161220f9190613008565b60405180910390fd5b9392505050565b600080828461222e9190613396565b9050612253600085148061224c575083858361224a9190613365565b145b6003612270565b670de0b6b3a7640000816122679190613365565b91505092915050565b8161227f5761227e81612283565b5b5050565b6030600a820601600a820491506030600a830601600a830492506030600a8406018060101b8260081b8401016642414c230000000160c81b7f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260076024528060445260646000fd5b6040518060c00160405280600080191681526020016000600181111561231c5761231b6135c2565b5b8152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001606081525090565b600061237d61237884613232565b61320d565b905080838252602082019050828560208602820111156123a05761239f613663565b5b60005b858110156123d057816123b688826124a1565b8452602084019350602083019250506001810190506123a3565b5050509392505050565b60006123ed6123e88461325e565b61320d565b905080838252602082019050828560208602820111156124105761240f613663565b5b60005b8581101561244057816124268882612749565b845260208401935060208301925050600181019050612413565b5050509392505050565b600061245d6124588461328a565b61320d565b90508281526020810184848401111561247957612478613668565b5b6124848482856134f1565b509392505050565b60008135905061249b8161387c565b92915050565b6000815190506124b08161387c565b92915050565b6000813590506124c581613893565b92915050565b600082601f8301126124e0576124df613654565b5b81516124f084826020860161236a565b91505092915050565b600082601f83011261250e5761250d613654565b5b815161251e8482602086016123da565b91505092915050565b600081519050612536816138aa565b92915050565b60008135905061254b816138c1565b92915050565b600081519050612560816138c1565b92915050565b60008083601f84011261257c5761257b613654565b5b8235905067ffffffffffffffff8111156125995761259861364f565b5b6020830191508360018202830111156125b5576125b4613663565b5b9250929050565b600082601f8301126125d1576125d0613654565b5b81356125e184826020860161244a565b91505092915050565b6000813590506125f9816138d8565b92915050565b60008135905061260e816138ef565b92915050565b60006060828403121561262a57612629613659565b5b612634606061320d565b9050600061264484828501612734565b600083015250602061265884828501612734565b602083015250604061266c84828501612734565b60408301525092915050565b600060c0828403121561268e5761268d613659565b5b61269860c061320d565b905060006126a88482850161253c565b60008301525060206126bc848285016125ff565b60208301525060406126d08482850161248c565b60408301525060606126e48482850161248c565b60608301525060806126f884828501612734565b60808301525060a082013567ffffffffffffffff81111561271c5761271b61365e565b5b612728848285016125bc565b60a08301525092915050565b600081359050612743816138ff565b92915050565b600081519050612758816138ff565b92915050565b6000806040838503121561277557612774613672565b5b600083015167ffffffffffffffff8111156127935761279261366d565b5b61279f858286016124cb565b925050602083015167ffffffffffffffff8111156127c0576127bf61366d565b5b6127cc858286016124f9565b9150509250929050565b6000602082840312156127ec576127eb613672565b5b600082015167ffffffffffffffff81111561280a5761280961366d565b5b612816848285016124f9565b91505092915050565b60006020828403121561283557612834613672565b5b600061284384828501612527565b91505092915050565b60006020828403121561286257612861613672565b5b600061287084828501612551565b91505092915050565b600080604083850312156128905761288f613672565b5b600061289e858286016125ea565b92505060206128af85828601612734565b9150509250929050565b600080600080608085870312156128d3576128d2613672565b5b600085013567ffffffffffffffff8111156128f1576128f061366d565b5b6128fd87828801612678565b945050602061290e87828801612734565b935050604061291f87828801612734565b9250506060612930878288016124b6565b91505092959194509250565b60006020828403121561295257612951613672565b5b600061296084828501612749565b91505092915050565b600080604083850312156129805761297f613672565b5b600061298e85828601612749565b925050602061299f85828601612749565b9150509250929050565b600080600080606085870312156129c3576129c2613672565b5b60006129d187828801612734565b94505060206129e287828801612734565b935050604085013567ffffffffffffffff811115612a0357612a0261366d565b5b612a0f87828801612566565b925092505092959194509250565b600080600080600060e08688031215612a3957612a38613672565b5b6000612a4788828901612734565b9550506020612a5888828901612734565b9450506040612a6988828901612734565b9350506060612a7a88828901612734565b9250506080612a8b88828901612614565b9150509295509295909350565b612aa181613436565b82525050565b612ab081613424565b82525050565b612abf81613424565b82525050565b612ace81613448565b82525050565b612add81613448565b82525050565b612aec81613454565b82525050565b612afb81613454565b82525050565b6000612b0c826132bb565b612b1681856132d1565b9350612b26818560208601613500565b612b2f81613677565b840191505092915050565b6000612b45826132bb565b612b4f81856132e2565b9350612b5f818560208601613500565b612b6881613677565b840191505092915050565b6000612b7e826132bb565b612b8881856132f3565b9350612b98818560208601613500565b80840191505092915050565b612bad816134bb565b82525050565b612bbc816134cd565b82525050565b612bcb816134df565b82525050565b6000612bdc826132c6565b612be681856132fe565b9350612bf6818560208601613500565b612bff81613677565b840191505092915050565b6000612c176031836132fe565b9150612c2282613688565b604082019050919050565b6000612c3a6009836132fe565b9150612c45826136d7565b602082019050919050565b6000612c5d6026836132fe565b9150612c6882613700565b604082019050919050565b6000612c806016836132fe565b9150612c8b8261374f565b602082019050919050565b6000612ca3601b836132fe565b9150612cae82613778565b602082019050919050565b6000612cc6601d836132fe565b9150612cd1826137a1565b602082019050919050565b6000612ce9602a836132fe565b9150612cf4826137ca565b604082019050919050565b6000612d0c6036836132fe565b9150612d1782613819565b604082019050919050565b608082016000820151612d386000850182612aa7565b506020820151612d4b6020850182612ac5565b506040820151612d5e6040850182612a98565b506060820151612d716060850182612ac5565b50505050565b600060c083016000830151612d8f6000860182612ae3565b506020830151612da26020860182612ba4565b506040830151612db56040860182612aa7565b506060830151612dc86060860182612aa7565b506080830151612ddb6080860182612e00565b5060a083015184820360a0860152612df38282612b01565b9150508091505092915050565b612e09816134b1565b82525050565b612e18816134b1565b82525050565b6000612e2a8284612b73565b915081905092915050565b6000602082019050612e4a6000830184612ab6565b92915050565b6000604082019050612e656000830185612ab6565b612e726020830184612ab6565b9392505050565b6000606082019050612e8e6000830186612ab6565b612e9b6020830185612ab6565b612ea86040830184612e0f565b949350505050565b6000608082019050612ec56000830187612ab6565b612ed26020830186612bc2565b612edf6040830185612e0f565b8181036060830152612ef18184612b3a565b905095945050505050565b6000604082019050612f116000830185612ab6565b612f1e6020830184612e0f565b9392505050565b6000606082019050612f3a6000830186612ab6565b612f476020830185612e0f565b612f546040830184612ad4565b949350505050565b6000608082019050612f716000830187612ab6565b612f7e6020830186612e0f565b612f8b6040830185612bb3565b612f986060830184612ad4565b95945050505050565b6000608082019050612fb66000830187612ab6565b612fc36020830186612e0f565b612fd06040830185612bc2565b8181036060830152612fe28184612b3a565b905095945050505050565b60006020820190506130026000830184612af2565b92915050565b600060208201905081810360008301526130228184612bd1565b905092915050565b6000602082019050818103600083015261304381612c0a565b9050919050565b6000602082019050818103600083015261306381612c2d565b9050919050565b6000602082019050818103600083015261308381612c50565b9050919050565b600060208201905081810360008301526130a381612c73565b9050919050565b600060208201905081810360008301526130c381612c96565b9050919050565b600060208201905081810360008301526130e381612cb9565b9050919050565b6000602082019050818103600083015261310381612cdc565b9050919050565b6000602082019050818103600083015261312381612cff565b9050919050565b600060e08201905081810360008301526131448187612d77565b90506131536020830186612d22565b61316060a0830185612e0f565b61316d60c0830184612e0f565b95945050505050565b600060408201905081810360008301526131908185612d77565b905061319f6020830184612e0f565b9392505050565b600060808201905081810360008301526131c08187612d77565b90506131cf6020830186612e0f565b6131dc6040830185612e0f565b6131e96060830184612ab6565b95945050505050565b60006020820190506132076000830184612e0f565b92915050565b6000613217613228565b90506132238282613533565b919050565b6000604051905090565b600067ffffffffffffffff82111561324d5761324c613620565b5b602082029050602081019050919050565b600067ffffffffffffffff82111561327957613278613620565b5b602082029050602081019050919050565b600067ffffffffffffffff8211156132a5576132a4613620565b5b6132ae82613677565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600061331a826134b1565b9150613325836134b1565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561335a57613359613564565b5b828201905092915050565b6000613370826134b1565b915061337b836134b1565b92508261338b5761338a613593565b5b828204905092915050565b60006133a1826134b1565b91506133ac836134b1565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156133e5576133e4613564565b5b828202905092915050565b60006133fb826134b1565b9150613406836134b1565b92508282101561341957613418613564565b5b828203905092915050565b600061342f82613491565b9050919050565b600061344182613491565b9050919050565b60008115159050919050565b6000819050919050565b600061346982613424565b9050919050565b600081905061347e82613868565b919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006134c682613470565b9050919050565b60006134d882613483565b9050919050565b60006134ea826134b1565b9050919050565b82818337600083830152505050565b60005b8381101561351e578082015181840152602081019050613503565b8381111561352d576000848401525b50505050565b61353c82613677565b810181811067ffffffffffffffff8211171561355b5761355a613620565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f416c726561647920696e2072616e676520616e64206e6f20646573697265642060008201527f62616c616e636520737065636966696564000000000000000000000000000000602082015250565b7f62616420332e206e6f0000000000000000000000000000000000000000000000600082015250565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b7f466c617368206c6f616e206469646e7420646f20697400000000000000000000600082015250565b7f4e6f7420656e6f75676820617373657420696e2062616c616e63650000000000600082015250565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b7f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60008201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000602082015250565b60028110613879576138786135c2565b5b50565b61388581613424565b811461389057600080fd5b50565b61389c81613436565b81146138a757600080fd5b50565b6138b381613448565b81146138be57600080fd5b50565b6138ca81613454565b81146138d557600080fd5b50565b6138e18161345e565b81146138ec57600080fd5b50565b600281106138fc57600080fd5b50565b613908816134b1565b811461391357600080fd5b5056fea264697066735822122024370afc30adeea5c7a13ebe78a7682b043835437839c3bbee9e629ec1c32e0764736f6c63430008070033
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.