Source Code
Latest 25 from a total of 101 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Bond | 18535731 | 274 days ago | IN | 0 ETH | 0.00000002 | ||||
| Bond | 18535508 | 274 days ago | IN | 0 ETH | 0.00000002 | ||||
| Unstake And Remo... | 5397497 | 579 days ago | IN | 0 ETH | 0.00001177 | ||||
| Unstake And Remo... | 5397479 | 579 days ago | IN | 0 ETH | 0.00000515 | ||||
| Unstake And Remo... | 5397473 | 579 days ago | IN | 0 ETH | 0.00001188 | ||||
| Unstake And Remo... | 5397468 | 579 days ago | IN | 0 ETH | 0.00000923 | ||||
| Add LP And Stake | 5397454 | 579 days ago | IN | 0 ETH | 0.0000153 | ||||
| Bond | 5397436 | 579 days ago | IN | 0 ETH | 0.00000942 | ||||
| Bond | 5397431 | 579 days ago | IN | 0 ETH | 0.00000514 | ||||
| Bond | 5397418 | 579 days ago | IN | 0 ETH | 0.00001269 | ||||
| Bond | 5396884 | 579 days ago | IN | 0 ETH | 0.00000959 | ||||
| Bond | 5396802 | 579 days ago | IN | 0 ETH | 0.00001405 | ||||
| Unstake And Remo... | 5396558 | 579 days ago | IN | 0 ETH | 0.0000162 | ||||
| Bond | 5396129 | 579 days ago | IN | 0 ETH | 0.00000932 | ||||
| Bond | 5394658 | 579 days ago | IN | 0 ETH | 0.00000973 | ||||
| Bond | 5392575 | 579 days ago | IN | 0 ETH | 0.00000883 | ||||
| Unstake And Remo... | 5391120 | 579 days ago | IN | 0 ETH | 0.00001166 | ||||
| Bond | 5389304 | 579 days ago | IN | 0 ETH | 0.00000327 | ||||
| Unstake And Remo... | 5388828 | 579 days ago | IN | 0 ETH | 0.00001288 | ||||
| Unstake And Remo... | 5388775 | 579 days ago | IN | 0 ETH | 0.00001281 | ||||
| Unstake And Remo... | 5388769 | 579 days ago | IN | 0 ETH | 0.00000685 | ||||
| Unstake And Remo... | 5388761 | 579 days ago | IN | 0 ETH | 0.00001415 | ||||
| Unstake And Remo... | 5388728 | 579 days ago | IN | 0 ETH | 0.00001239 | ||||
| Unstake And Remo... | 5388690 | 579 days ago | IN | 0 ETH | 0.00001201 | ||||
| Unstake And Remo... | 5388584 | 579 days ago | IN | 0 ETH | 0.00001157 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
IndexUtils
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 100 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@uniswap/v3-core/contracts/libraries/FixedPoint96.sol";
import "@uniswap/v3-periphery/contracts/interfaces/IPeripheryImmutableState.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "./interfaces/IDecentralizedIndex.sol";
import "./interfaces/IERC20Metadata.sol";
import "./interfaces/IStakingPoolToken.sol";
import "./interfaces/ITokenRewards.sol";
import "./interfaces/IUniswapV2Factory.sol";
import "./interfaces/IUniswapV3Pool.sol";
import "./interfaces/IUniswapV2Router02.sol";
import "./interfaces/IWETH.sol";
import "./Zapper.sol";
contract IndexUtils is Context, Zapper {
using SafeERC20 for IERC20;
constructor(
address _v2Router,
IV3TwapUtilities _v3TwapUtilities
) Zapper(_v2Router, _v3TwapUtilities) {}
function bond(
IDecentralizedIndex _indexFund,
address _token,
uint256 _amount,
uint256 _amountMintMin
) external {
if (_indexFund.indexType() == IDecentralizedIndex.IndexType.WEIGHTED) {
IDecentralizedIndex.IndexAssetInfo[] memory _assets = _indexFund
.getAllAssets();
uint256[] memory _balsBefore = new uint256[](_assets.length);
uint256 _tokenCurSupply = IERC20(_token).balanceOf(
address(_indexFund)
);
uint256 _tokenAmtSupplyRatioX96 = _indexFund.totalSupply() == 0
? FixedPoint96.Q96
: (_amount * FixedPoint96.Q96) / _tokenCurSupply;
for (uint256 _i; _i < _assets.length; _i++) {
uint256 _amountNeeded = _indexFund.totalSupply() == 0
? _indexFund.getInitialAmount(
_token,
_amount,
_assets[_i].token
)
: (IERC20(_assets[_i].token).balanceOf(
address(_indexFund)
) * _tokenAmtSupplyRatioX96) / FixedPoint96.Q96;
_balsBefore[_i] = IERC20(_assets[_i].token).balanceOf(
address(this)
);
IERC20(_assets[_i].token).safeTransferFrom(
_msgSender(),
address(this),
_amountNeeded
);
IERC20(_assets[_i].token).safeIncreaseAllowance(
address(_indexFund),
_amountNeeded
);
}
uint256 _idxBalBefore = IERC20(_indexFund).balanceOf(address(this));
_indexFund.bond(_token, _amount, _amountMintMin);
IERC20(_indexFund).safeTransfer(
_msgSender(),
IERC20(_indexFund).balanceOf(address(this)) - _idxBalBefore
);
// refund any excess tokens to user we didn't use to bond
for (uint256 _i; _i < _assets.length; _i++) {
_checkAndRefundERC20(
_msgSender(),
_assets[_i].token,
_balsBefore[_i]
);
}
} else {
require(
_indexFund.indexType() ==
IDecentralizedIndex.IndexType.UNWEIGHTED,
"UW"
);
IERC20(_token).safeTransferFrom(
_msgSender(),
address(this),
_amount
);
IERC20(_token).safeIncreaseAllowance(address(_indexFund), _amount);
uint256 _idxBalBefore = IERC20(_indexFund).balanceOf(address(this));
_indexFund.bond(_token, _amount, _amountMintMin);
IERC20(_indexFund).safeTransfer(
_msgSender(),
IERC20(_indexFund).balanceOf(address(this)) - _idxBalBefore
);
}
}
function bondWeightedFromNative(
IDecentralizedIndex _indexFund,
uint256 _assetIdx,
uint256 _amountTokensForAssetIdx,
uint256 _amountMintMin,
uint256 _amountPairedLpTokenMin,
uint256 _slippage, // 1 == 0.1%, 10 == 1%, 1000 == 100%
uint256 _deadline,
bool _stakeAsWell
) external payable {
require(msg.value > 0, "NATIVE");
uint256 _ethBalBefore = address(this).balance - msg.value;
IDecentralizedIndex.IndexAssetInfo[] memory _assets = _indexFund
.getAllAssets();
(
uint256[] memory _balancesBefore,
uint256[] memory _amountsReceived
) = _swapNativeForTokensWeightedV2(
_indexFund,
_stakeAsWell ? msg.value / 2 : msg.value,
_assets,
_assetIdx,
_amountTokensForAssetIdx
);
// allowance for _assetIdx is increased in _bondToRecipient below,
// we just need to increase allowance for any other index tokens here first
for (uint256 _i; _i < _assets.length; _i++) {
if (_i == _assetIdx) {
continue;
}
IERC20(_assets[_i].token).safeIncreaseAllowance(
address(_indexFund),
_amountsReceived[_i]
);
}
uint256 _idxTokensGained = _bondToRecipient(
_indexFund,
_assets[_assetIdx].token,
_amountsReceived[_assetIdx],
_amountMintMin,
_stakeAsWell ? address(this) : _msgSender()
);
if (_stakeAsWell) {
_zapIndexTokensAndNative(
_msgSender(),
_indexFund,
_idxTokensGained,
msg.value / 2,
_amountPairedLpTokenMin,
_slippage,
_deadline
);
}
// refund any excess tokens to user we didn't use to bond
for (uint256 _i; _i < _assets.length; _i++) {
_checkAndRefundERC20(
_msgSender(),
_assets[_i].token,
_balancesBefore[_i]
);
}
// refund excess ETH
if (address(this).balance > _ethBalBefore) {
(bool _s, ) = payable(_msgSender()).call{
value: address(this).balance - _ethBalBefore
}("");
require(_s, "ETHREFUND");
}
}
function addLPAndStake(
IDecentralizedIndex _indexFund, //TODO: lYEL
uint256 _amountIdxTokens, //TODO: 2 yel
address _pairedLpTokenProvided,//TODO: 0x
uint256 _amtPairedLpTokenProvided,//TODO: 0.007
uint256 _amountPairedLpTokenMin,//TODO: 0
uint256 _slippage,//TODO: 80
uint256 _deadline
) external payable {
address _v2Pool = IUniswapV2Factory(
IUniswapV2Router02(V2_ROUTER).factory()
).getPair(address(_indexFund), _indexFund.PAIRED_LP_TOKEN());
uint256 _idxTokensBefore = IERC20(address(_indexFund)).balanceOf(
address(this)
);
uint256 _pairedLpTokenBefore = IERC20(_indexFund.PAIRED_LP_TOKEN())
.balanceOf(address(this));
uint256 _ethBefore = address(this).balance - msg.value;
uint256 _v2PoolBefore = IERC20(_v2Pool).balanceOf(address(this));
IERC20(address(_indexFund)).safeTransferFrom(
_msgSender(),
address(this),
_amountIdxTokens
);
if (_pairedLpTokenProvided == address(0)) {
require(msg.value > 0, "NEEDETH");
_amtPairedLpTokenProvided = msg.value;
} else {
IERC20(_pairedLpTokenProvided).safeTransferFrom(
_msgSender(),
address(this),
_amtPairedLpTokenProvided
);
}
if (_pairedLpTokenProvided != _indexFund.PAIRED_LP_TOKEN()) {
_zap(
_pairedLpTokenProvided,
_indexFund.PAIRED_LP_TOKEN(),
_amtPairedLpTokenProvided,
_amountPairedLpTokenMin
);
}
IERC20(_indexFund.PAIRED_LP_TOKEN()).safeIncreaseAllowance(
address(_indexFund),
IERC20(_indexFund.PAIRED_LP_TOKEN()).balanceOf(address(this)) -
_pairedLpTokenBefore
);
_indexFund.addLiquidityV2(
IERC20(address(_indexFund)).balanceOf(address(this)) -
_idxTokensBefore,
IERC20(_indexFund.PAIRED_LP_TOKEN()).balanceOf(address(this)) -
_pairedLpTokenBefore,
_slippage,
_deadline
);
IERC20(_v2Pool).safeIncreaseAllowance(
_indexFund.lpStakingPool(),
IERC20(_v2Pool).balanceOf(address(this)) - _v2PoolBefore
);
IStakingPoolToken(_indexFund.lpStakingPool()).stake(
_msgSender(),
IERC20(_v2Pool).balanceOf(address(this)) - _v2PoolBefore
);
// refunds if needed for index tokens and pairedLpToken
if (address(this).balance > _ethBefore) {
(bool _s, ) = payable(_msgSender()).call{
value: address(this).balance - _ethBefore
}("");
require(_s && address(this).balance >= _ethBefore, "TOOMUCH");
}
_checkAndRefundERC20(
_msgSender(),
address(_indexFund),
_idxTokensBefore
);
_checkAndRefundERC20(
_msgSender(),
_indexFund.PAIRED_LP_TOKEN(),
_pairedLpTokenBefore
);
}
function unstakeAndRemoveLP(
IDecentralizedIndex _indexFund,
uint256 _amountStakedTokens,
uint256 _minLPTokens,
uint256 _minPairedLpToken,
uint256 _deadline
) external {
address _stakingPool = _indexFund.lpStakingPool();
address _pairedLpToken = _indexFund.PAIRED_LP_TOKEN();
uint256 _stakingBalBefore = IERC20(_stakingPool).balanceOf(
address(this)
);
uint256 _pairedLpTokenBefore = IERC20(_pairedLpToken).balanceOf(
address(this)
);
IERC20(_stakingPool).safeTransferFrom(
_msgSender(),
address(this),
_amountStakedTokens
);
uint256 _indexBalBefore = _unstakeAndRemoveLP(
_indexFund,
_stakingPool,
IERC20(_stakingPool).balanceOf(address(this)) - _stakingBalBefore,
_minLPTokens,
_minPairedLpToken,
_deadline
);
if (
IERC20(address(_indexFund)).balanceOf(address(this)) >
_indexBalBefore
) {
IERC20(address(_indexFund)).safeTransfer(
_msgSender(),
IERC20(address(_indexFund)).balanceOf(address(this)) -
_indexBalBefore
);
}
if (
IERC20(_pairedLpToken).balanceOf(address(this)) >
_pairedLpTokenBefore
) {
IERC20(_pairedLpToken).safeTransfer(
_msgSender(),
IERC20(_pairedLpToken).balanceOf(address(this)) -
_pairedLpTokenBefore
);
}
}
function claimRewardsMulti(address[] memory _rewards) external {
for (uint256 _i; _i < _rewards.length; _i++) {
ITokenRewards(_rewards[_i]).claimReward(_msgSender());
}
}
function _swapNativeForTokensWeightedV2(
IDecentralizedIndex _indexFund,
uint256 _amountNative,
IDecentralizedIndex.IndexAssetInfo[] memory _assets,
uint256 _poolIdx,
uint256 _amountForPoolIdx
) internal returns (uint256[] memory, uint256[] memory) {
uint256[] memory _amountBefore = new uint256[](_assets.length);
uint256[] memory _amountReceived = new uint256[](_assets.length);
uint256 _tokenCurSupply = IERC20(_assets[_poolIdx].token).balanceOf(
address(_indexFund)
);
uint256 _tokenAmtSupplyRatioX96 = _indexFund.totalSupply() == 0
? FixedPoint96.Q96
: (_amountForPoolIdx * FixedPoint96.Q96) / _tokenCurSupply;
uint256 _nativeLeft = _amountNative;
for (uint256 _i; _i < _assets.length; _i++) {
(
_nativeLeft,
_amountBefore[_i],
_amountReceived[_i]
) = _swapForIdxToken(
_indexFund,
_assets[_poolIdx].token,
_amountForPoolIdx,
_assets[_i].token,
_tokenAmtSupplyRatioX96,
_nativeLeft
);
}
return (_amountBefore, _amountReceived);
}
function _swapForIdxToken(
IDecentralizedIndex _indexFund,
address _initToken,
uint256 _initTokenAmount,
address _outToken,
uint256 _tokenAmtSupplyRatioX96,
uint256 _nativeLeft
)
internal
returns (
uint256 _newNativeLeft,
uint256 _amountBefore,
uint256 _amountReceived
)
{
uint256 _nativeBefore = address(this).balance;
_amountBefore = IERC20(_outToken).balanceOf(address(this));
uint256 _amountOut = _indexFund.totalSupply() == 0
? _indexFund.getInitialAmount(
_initToken,
_initTokenAmount,
_outToken
)
: (IERC20(_outToken).balanceOf(address(_indexFund)) *
_tokenAmtSupplyRatioX96) / FixedPoint96.Q96;
address[] memory _path = new address[](2);
_path[0] = IUniswapV2Router02(V2_ROUTER).WETH();
_path[1] = _outToken;
IUniswapV2Router02(V2_ROUTER).swapETHForExactTokens{value: _nativeLeft}(
_amountOut,
_path,
address(this),
block.timestamp
);
_newNativeLeft = _nativeLeft - (_nativeBefore - address(this).balance);
_amountReceived =
IERC20(_outToken).balanceOf(address(this)) -
_amountBefore;
}
function _unstakeAndRemoveLP(
IDecentralizedIndex _indexFund,
address _stakingPool,
uint256 _unstakeAmount,
uint256 _minLPTokens,
uint256 _minPairedLpTokens,
uint256 _deadline
) internal returns (uint256 _fundTokensBefore) {
address _pairedLpToken = _indexFund.PAIRED_LP_TOKEN();
address _v2Pool = IUniswapV2Factory(
IUniswapV2Router02(V2_ROUTER).factory()
).getPair(address(_indexFund), _pairedLpToken);
uint256 _v2TokensBefore = IERC20(_v2Pool).balanceOf(address(this));
IStakingPoolToken(_stakingPool).unstake(_unstakeAmount);
_fundTokensBefore = _indexFund.balanceOf(address(this));
IERC20(_v2Pool).safeIncreaseAllowance(
address(_indexFund),
IERC20(_v2Pool).balanceOf(address(this)) - _v2TokensBefore
);
_indexFund.removeLiquidityV2(
IERC20(_v2Pool).balanceOf(address(this)) - _v2TokensBefore,
_minLPTokens,
_minPairedLpTokens,
_deadline
);
}
function _bondToRecipient(
IDecentralizedIndex _indexFund,
address _indexToken,
uint256 _bondTokens,
uint256 _amountMintMin,
address _recipient
) internal returns (uint256) {
uint256 _idxTokensBefore = IERC20(address(_indexFund)).balanceOf(
address(this)
);
IERC20(_indexToken).safeIncreaseAllowance(
address(_indexFund),
_bondTokens
);
_indexFund.bond(_indexToken, _bondTokens, _amountMintMin);
uint256 _idxTokensGained = IERC20(address(_indexFund)).balanceOf(
address(this)
) - _idxTokensBefore;
if (_recipient != address(this)) {
IERC20(address(_indexFund)).safeTransfer(
_recipient,
_idxTokensGained
);
}
return _idxTokensGained;
}
function _zapIndexTokensAndNative(
address _user,
IDecentralizedIndex _indexFund,
uint256 _amountTokens,
uint256 _amountETH,
uint256 _amtPairedLpTokenMin,
uint256 _slippage,
uint256 _deadline
) internal {
address _pairedLpToken = _indexFund.PAIRED_LP_TOKEN();
uint256 _tokensBefore = IERC20(address(_indexFund)).balanceOf(
address(this)
) - _amountTokens;
uint256 _pairedLpTokenBefore = IERC20(_pairedLpToken).balanceOf(
address(this)
);
address _stakingPool = _indexFund.lpStakingPool();
_zap(address(0), _pairedLpToken, _amountETH, _amtPairedLpTokenMin);
address _v2Pool = IUniswapV2Factory(
IUniswapV2Router02(V2_ROUTER).factory()
).getPair(address(_indexFund), _pairedLpToken);
uint256 _lpTokensBefore = IERC20(_v2Pool).balanceOf(address(this));
IERC20(_pairedLpToken).safeIncreaseAllowance(
address(_indexFund),
IERC20(_pairedLpToken).balanceOf(address(this)) -
_pairedLpTokenBefore
);
_indexFund.addLiquidityV2(
_amountTokens,
IERC20(_pairedLpToken).balanceOf(address(this)) -
_pairedLpTokenBefore,
_slippage,
_deadline
);
IERC20(_v2Pool).safeIncreaseAllowance(
_stakingPool,
IERC20(_v2Pool).balanceOf(address(this)) - _lpTokensBefore
);
IStakingPoolToken(_stakingPool).stake(
_user,
IERC20(_v2Pool).balanceOf(address(this)) - _lpTokensBefore
);
// check & refund excess tokens from LPing as needed
if (
IERC20(address(_indexFund)).balanceOf(address(this)) > _tokensBefore
) {
IERC20(address(_indexFund)).safeTransfer(
_user,
IERC20(address(_indexFund)).balanceOf(address(this)) -
_tokensBefore
);
}
if (
IERC20(_pairedLpToken).balanceOf(address(this)) >
_pairedLpTokenBefore
) {
IERC20(_pairedLpToken).safeTransfer(
_user,
IERC20(_pairedLpToken).balanceOf(address(this)) -
_pairedLpTokenBefore
);
}
}
function _checkAndRefundERC20(
address _user,
address _asset,
uint256 _beforeBal
) internal {
uint256 _curBal = IERC20(_asset).balanceOf(address(this));
if (_curBal > _beforeBal) {
IERC20(_asset).safeTransfer(_user, _curBal - _beforeBal);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
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'
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 Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @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).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// 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 cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// 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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
/// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
/// @dev In the implementation you must pay the pool tokens owed for the swap.
/// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
/// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
/// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
/// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
/// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.4.0;
/// @title FixedPoint96
/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)
/// @dev Used in SqrtPriceMath.sol
library FixedPoint96 {
uint8 internal constant RESOLUTION = 96;
uint256 internal constant Q96 = 0x1000000000000000000000000;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Immutable state
/// @notice Functions that return immutable state of the router
interface IPeripheryImmutableState {
/// @return Returns the address of the Uniswap V3 factory
function factory() external view returns (address);
/// @return Returns the address of WETH9
function WETH9() external view returns (address);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;
import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol';
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface ICurvePool {
function coins(uint256 _idx) external returns (address);
function exchange(
int128 i,
int128 j,
uint256 dx,
uint256 minDy,
address receiver
) external returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
interface IDecentralizedIndex is IERC20 {
enum IndexType {
WEIGHTED,
UNWEIGHTED
}
// all fees: 1 == 0.01%, 10 == 0.1%, 100 == 1%
struct Fees {
uint256 burn;
uint256 bond;
uint256 debond;
uint256 buy;
uint256 sell;
uint256 partner;
}
struct IndexAssetInfo {
address token;
uint256 weighting;
uint256 basePriceUSDX96;
address c1; // arbitrary contract/address field we can use for an index
uint256 q1; // arbitrary quantity/number field we can use for an index
}
event Create(address indexed newIdx, address indexed wallet);
event Bond(
address indexed wallet,
address indexed token,
uint256 amountTokensBonded,
uint256 amountTokensMinted
);
event Debond(address indexed wallet, uint256 amountDebonded);
event AddLiquidity(
address indexed wallet,
uint256 amountTokens,
uint256 amountDAI
);
event RemoveLiquidity(address indexed wallet, uint256 amountLiquidity);
function DAI() external view returns (address);
function BOND_FEE() external view returns (uint256);
function DEBOND_FEE() external view returns (uint256);
function FLASH_FEE() external view returns (uint256);
function PAIRED_LP_TOKEN() external view returns (address);
function indexType() external view returns (IndexType);
function created() external view returns (uint256);
function lpStakingPool() external view returns (address);
function lpRewardsToken() external view returns (address);
function partner() external view returns (address);
function getIdxPriceUSDX96() external view returns (uint256, uint256);
function isAsset(address token) external view returns (bool);
function getAllAssets() external view returns (IndexAssetInfo[] memory);
function getInitialAmount(
address sToken,
uint256 sAmount,
address tToken
) external view returns (uint256);
function getTokenPriceUSDX96(address token) external view returns (uint256);
function processPreSwapFeesAndSwap() external;
function bond(address token, uint256 amount, uint256 amountMintMin) external;
function debond(
uint256 amount,
address[] memory token,
uint8[] memory percentage
) external;
function addLiquidityV2(
uint256 idxTokens,
uint256 daiTokens,
uint256 slippage,
uint256 deadline
) external;
function removeLiquidityV2(
uint256 lpTokens,
uint256 minTokens,
uint256 minDAI,
uint256 deadline
) external;
function flash(
address recipient,
address token,
uint256 amount,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IERC20Metadata {
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IERC4626 {
function deposit(
uint256 yETHAmount,
address receiver
) external returns (uint256 styETHAmount);
function withdraw(
uint256 styETHAmount,
address receiver
) external returns (uint256 yETHAmount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IStakingPoolToken {
event Stake(address indexed executor, address indexed user, uint256 amount);
event Unstake(address indexed user, uint256 amount);
function indexFund() external view returns (address);
function stakingToken() external view returns (address);
function poolRewards() external view returns (address);
function stakeUserRestriction() external view returns (address);
function stake(address user, uint256 amount) external;
function unstake(uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface ITokenRewards {
event AddShares(address indexed wallet, uint256 amount);
event RemoveShares(address indexed wallet, uint256 amount);
event ClaimReward(address indexed wallet);
event DistributeReward(address indexed wallet, uint256 amount);
event DepositRewards(address indexed wallet, uint256 amount);
function totalShares() external view returns (uint256);
function totalStakers() external view returns (uint256);
function rewardsToken() external view returns (address);
function trackingToken() external view returns (address);
function depositFromPairedLpToken(
uint256 amount,
uint256 slippageOverride
) external;
function depositRewards(uint256 amount) external;
function claimReward(address wallet) external;
function setShares(
address wallet,
uint256 amount,
bool sharesRemoving
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IUniswapV2Factory {
function createPair(
address tokenA,
address tokenB
) external returns (address pair);
function getPair(
address tokenA,
address tokenB
) external view returns (address pair);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IUniswapV2Pair {
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IUniswapV2Router02 {
function factory() external view returns (address);
function WETH() external view returns (address);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IUniswapV3Pool {
/// @notice The first of the two tokens of the pool, sorted by address
/// @return The token contract address
function token0() external view returns (address);
/// @notice The second of the two tokens of the pool, sorted by address
/// @return The token contract address
function token1() external view returns (address);
/// @notice The pool's fee in hundredths of a bip, i.e. 1e-6
/// @return The fee
function fee() external view returns (uint24);
/// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp
/// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing
/// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,
/// you must call it with secondsAgos = [3600, 0].
/// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in
/// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.
/// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned
/// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp
/// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block
/// timestamp
function observe(
uint32[] calldata secondsAgos
)
external
view
returns (
int56[] memory tickCumulatives,
uint160[] memory secondsPerLiquidityCumulativeX128s
);
/// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas
/// when accessed externally.
/// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value
/// tick The current tick of the pool, i.e. according to the last tick transition that was run.
/// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
/// boundary.
/// observationIndex The index of the last oracle observation that was written,
/// observationCardinality The current maximum number of observations stored in the pool,
/// observationCardinalityNext The next maximum number of observations, to be updated when the observation.
/// feeProtocol The protocol fee for both tokens of the pool.
/// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0
/// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.
/// unlocked Whether the pool is currently locked to reentrancy
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint8 feeProtocol,
bool unlocked
);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IV3TwapUtilities {
function getV3Pool(
address v3Factory,
address token0,
address token1,
uint24 poolFee
) external view returns (address);
function getPoolPriceUSDX96(
address pricePool,
address nativeStablePool,
address WETH9
) external view returns (uint256);
function sqrtPriceX96FromPoolAndInterval(
address pool
) external view returns (uint160);
function priceX96FromSqrtPriceX96(
uint160 sqrtPriceX96
) external pure returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IWETH {
function deposit() external payable;
function withdraw(uint256 _amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IZapper {
enum PoolType {
CURVE,
V2,
V3
}
struct Pools {
PoolType poolType; // assume same for both pool1 and pool2
address pool1;
address pool2;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@uniswap/v3-core/contracts/libraries/FixedPoint96.sol";
import "@uniswap/v3-periphery/contracts/interfaces/IPeripheryImmutableState.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "./interfaces/ICurvePool.sol";
import "./interfaces/IDecentralizedIndex.sol";
import "./interfaces/IERC4626.sol";
import "./interfaces/IUniswapV2Pair.sol";
import "./interfaces/IUniswapV3Pool.sol";
import "./interfaces/IUniswapV2Router02.sol";
import "./interfaces/IV3TwapUtilities.sol";
import "./interfaces/IWETH.sol";
import "./interfaces/IZapper.sol";
contract Zapper is IZapper, Context, Ownable {
using SafeERC20 for IERC20;
address constant V3_ROUTER = 0x2626664c2603336E57B271c5C0b26F421741e481; //TODO: BASE
address immutable V2_ROUTER;
address immutable WETH;
IV3TwapUtilities immutable V3_TWAP_UTILS;
uint256 _slippage = 30; // 3%
// token in => token out => swap pool(s)
mapping(address => mapping(address => Pools)) public zapMap;
// curve pool => token => idx
mapping(address => mapping(address => int128)) public curveTokenIdx;
mapping(address => address) public second_liqs;
constructor(address _v2Router, IV3TwapUtilities _v3TwapUtilities) {
V2_ROUTER = _v2Router;
V3_TWAP_UTILS = _v3TwapUtilities;
WETH = IUniswapV2Router02(V2_ROUTER).WETH();
}
function _zap(
address _in,
address _out,
uint256 _amountIn,
uint256 _amountOutMin
) internal returns (uint256 _amountOut) {
if (_in == address(0)) {
_amountIn = _ethToWETH(_amountIn);
_in = WETH;
}
// handle secondLiqToken separately through potion, modularize later
bool _isOutsecondLiqToken;
address secondLiqToken;
if (second_liqs[_out] != address(0)) {
secondLiqToken = _out; //Here it's wRap token wArb
_isOutsecondLiqToken = true;
_out = second_liqs[_out]; //Here is unWrap token Arb
}
Pools memory _poolInfo = zapMap[_in][_out];
// no pool so just try to swap over one path univ2
if (_poolInfo.pool1 == address(0)) {
address[] memory _path = new address[](2);
_path[0] = _in;
_path[1] = _out;
if(_in != _out) {
_amountOut = _swapV2(_path, _amountIn, _amountOutMin);
} else {
_amountOut = _amountIn;
}
} else {
bool _twoHops = _poolInfo.pool2 != address(0);
if (_poolInfo.poolType == PoolType.CURVE) {
// curve
_amountOut = _swapCurve(
_poolInfo.pool1,
curveTokenIdx[_poolInfo.pool1][_in],
curveTokenIdx[_poolInfo.pool1][_out],
_amountIn,
_amountOutMin
);
} else if (_poolInfo.poolType == PoolType.V2) {
// univ2
address _token0 = IUniswapV2Pair(_poolInfo.pool1).token0();
address[] memory _path = new address[](_twoHops ? 3 : 2);
_path[0] = _in;
_path[1] = !_twoHops ? _out : _token0 == _in
? IUniswapV2Pair(_poolInfo.pool1).token1()
: _token0;
if (_twoHops) {
_path[2] = _out;
}
_amountOut = _swapV2(_path, _amountIn, _amountOutMin);
} else {
// univ3
if (_twoHops) {
address _t0 = IUniswapV3Pool(_poolInfo.pool1).token0();
_amountOut = _swapV3Multi(
_in,
IUniswapV3Pool(_poolInfo.pool1).fee(),
_t0 == _in
? IUniswapV3Pool(_poolInfo.pool1).token0()
: _t0,
IUniswapV3Pool(_poolInfo.pool2).fee(),
_out,
_amountIn,
_amountOutMin
);
} else {
_amountOut = _swapV3Single(
_in,
IUniswapV3Pool(_poolInfo.pool1).fee(),
_out,
_amountIn,
_amountOutMin
);
}
}
}
if (!_isOutsecondLiqToken) {
return _amountOut;
}
uint256 _secondLiqTokenBefore = IERC20(secondLiqToken).balanceOf(
address(this)
);
IERC20(_out).safeIncreaseAllowance(
secondLiqToken,
_amountOut
);
IDecentralizedIndex(secondLiqToken).bond(
_out,
_amountOut,
0
);
return
IERC20(secondLiqToken).balanceOf(address(this)) -
_secondLiqTokenBefore;
}
function _ethToWETH(uint256 _amountETH) internal returns (uint256) {
uint256 _wethBal = IERC20(WETH).balanceOf(address(this));
IWETH(WETH).deposit{value: _amountETH}();
return IERC20(WETH).balanceOf(address(this)) - _wethBal;
}
function _swapV3Single(
address _in,
uint24 _fee,
address _out,
uint256 _amountIn,
uint256 _amountOutMin
) internal returns (uint256 _amountOut) {
if (_amountOutMin == 0) {
address _v3Pool = V3_TWAP_UTILS.getV3Pool(
IPeripheryImmutableState(V3_ROUTER).factory(),
_in,
_out,
_fee
);
address _token0 = _in < _out ? _in : _out;
uint256 _poolPriceX96 = V3_TWAP_UTILS.priceX96FromSqrtPriceX96(
V3_TWAP_UTILS.sqrtPriceX96FromPoolAndInterval(_v3Pool)
);
_amountOutMin = _in == _token0
? (_poolPriceX96 * _amountIn) / FixedPoint96.Q96
: (_amountIn * FixedPoint96.Q96) / _poolPriceX96;
}
uint256 _outBefore = IERC20(_out).balanceOf(address(this));
IERC20(_in).safeIncreaseAllowance(V3_ROUTER, _amountIn);
ISwapRouter(V3_ROUTER).exactInputSingle(
ISwapRouter.ExactInputSingleParams({
tokenIn: _in,
tokenOut: _out,
fee: _fee,
recipient: address(this),
amountIn: _amountIn,
amountOutMinimum: (_amountOutMin * (1000 - _slippage)) / 1000,
sqrtPriceLimitX96: 0
})
);
return IERC20(_out).balanceOf(address(this)) - _outBefore;
}
function _swapV3Multi(
address _in,
uint24 _fee1,
address _in2,
uint24 _fee2,
address _out,
uint256 _amountIn,
uint256 _amountOutMin
) internal returns (uint256) {
uint256 _outBefore = IERC20(_out).balanceOf(address(this));
IERC20(_in).safeIncreaseAllowance(V3_ROUTER, _amountIn);
bytes memory _path = abi.encodePacked(_in, _fee1, _in2, _fee2, _out);
ISwapRouter(V3_ROUTER).exactInput(
ISwapRouter.ExactInputParams({
path: _path,
recipient: address(this),
deadline: block.timestamp,
amountIn: _amountIn,
amountOutMinimum: _amountOutMin
})
);
return IERC20(_out).balanceOf(address(this)) - _outBefore;
}
function _swapV2(
address[] memory _path,
uint256 _amountIn,
uint256 _amountOutMin
) internal returns (uint256) {
address _out = _path.length == 3 ? _path[2] : _path[1];
uint256 _outBefore = IERC20(_out).balanceOf(address(this));
IERC20(_path[0]).safeIncreaseAllowance(V2_ROUTER, _amountIn);
IUniswapV2Router02(V2_ROUTER)
.swapExactTokensForTokensSupportingFeeOnTransferTokens(
_amountIn,
_amountOutMin,
_path,
address(this),
block.timestamp
);
return IERC20(_out).balanceOf(address(this)) - _outBefore;
}
function _swapCurve(
address _pool,
int128 _i,
int128 _j,
uint256 _amountIn,
uint256 _amountOutMin
) internal returns (uint256) {
return
ICurvePool(_pool).exchange(
_i,
_j,
_amountIn,
_amountOutMin,
address(this)
);
}
function _setZapMapFromPoolSingle(PoolType _type, address _pool) internal {
address _t0;
address _t1;
if (_type == PoolType.CURVE) {
_t0 = ICurvePool(_pool).coins(0);
_t1 = ICurvePool(_pool).coins(1);
curveTokenIdx[_pool][_t0] = 0;
curveTokenIdx[_pool][_t1] = 1;
} else {
_t0 = IUniswapV3Pool(_pool).token0();
_t1 = IUniswapV3Pool(_pool).token1();
}
Pools memory _poolConf = Pools({
poolType: _type,
pool1: _pool,
pool2: address(0)
});
zapMap[_t0][_t1] = _poolConf;
zapMap[_t1][_t0] = _poolConf;
}
function setsecondLiqToken(address _wrapper, address _secondLiqToken) external onlyOwner {
second_liqs[_wrapper] = _secondLiqToken;
}
function setSlippage(uint256 _slip) external onlyOwner {
_slippage = _slip;
}
function setZapMap(
address _in,
address _out,
Pools memory _pools
) external onlyOwner {
zapMap[_in][_out] = _pools;
}
function setZapMapFromPoolSingle(
PoolType _type,
address _pool
) external onlyOwner {
_setZapMapFromPoolSingle(_type, _pool);
}
function rescueETH() external onlyOwner {
(bool _sent, ) = payable(owner()).call{value: address(this).balance}(
""
);
require(_sent);
}
function rescueERC20(IERC20 _token) external onlyOwner {
require(_token.balanceOf(address(this)) > 0);
_token.safeTransfer(owner(), _token.balanceOf(address(this)));
}
receive() external payable {}
}{
"optimizer": {
"enabled": true,
"runs": 100
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_v2Router","type":"address"},{"internalType":"contract IV3TwapUtilities","name":"_v3TwapUtilities","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"contract IDecentralizedIndex","name":"_indexFund","type":"address"},{"internalType":"uint256","name":"_amountIdxTokens","type":"uint256"},{"internalType":"address","name":"_pairedLpTokenProvided","type":"address"},{"internalType":"uint256","name":"_amtPairedLpTokenProvided","type":"uint256"},{"internalType":"uint256","name":"_amountPairedLpTokenMin","type":"uint256"},{"internalType":"uint256","name":"_slippage","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"addLPAndStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDecentralizedIndex","name":"_indexFund","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_amountMintMin","type":"uint256"}],"name":"bond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IDecentralizedIndex","name":"_indexFund","type":"address"},{"internalType":"uint256","name":"_assetIdx","type":"uint256"},{"internalType":"uint256","name":"_amountTokensForAssetIdx","type":"uint256"},{"internalType":"uint256","name":"_amountMintMin","type":"uint256"},{"internalType":"uint256","name":"_amountPairedLpTokenMin","type":"uint256"},{"internalType":"uint256","name":"_slippage","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"bool","name":"_stakeAsWell","type":"bool"}],"name":"bondWeightedFromNative","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_rewards","type":"address[]"}],"name":"claimRewardsMulti","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"curveTokenIdx","outputs":[{"internalType":"int128","name":"","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_token","type":"address"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescueETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"second_liqs","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_slip","type":"uint256"}],"name":"setSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_in","type":"address"},{"internalType":"address","name":"_out","type":"address"},{"components":[{"internalType":"enum IZapper.PoolType","name":"poolType","type":"uint8"},{"internalType":"address","name":"pool1","type":"address"},{"internalType":"address","name":"pool2","type":"address"}],"internalType":"struct IZapper.Pools","name":"_pools","type":"tuple"}],"name":"setZapMap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IZapper.PoolType","name":"_type","type":"uint8"},{"internalType":"address","name":"_pool","type":"address"}],"name":"setZapMapFromPoolSingle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wrapper","type":"address"},{"internalType":"address","name":"_secondLiqToken","type":"address"}],"name":"setsecondLiqToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IDecentralizedIndex","name":"_indexFund","type":"address"},{"internalType":"uint256","name":"_amountStakedTokens","type":"uint256"},{"internalType":"uint256","name":"_minLPTokens","type":"uint256"},{"internalType":"uint256","name":"_minPairedLpToken","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"unstakeAndRemoveLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"zapMap","outputs":[{"internalType":"enum IZapper.PoolType","name":"poolType","type":"uint8"},{"internalType":"address","name":"pool1","type":"address"},{"internalType":"address","name":"pool2","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60e0604052601e6001553480156200001657600080fd5b5060405162005cef38038062005cef83398101604081905262000039916200013e565b81816200004633620000d5565b6001600160a01b03808316608081905290821660c052604080516315ab88c960e31b8152905163ad5c4648916004808201926020929091908290030181865afa15801562000098573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000be91906200017d565b6001600160a01b031660a05250620001a492505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146200013b57600080fd5b50565b600080604083850312156200015257600080fd5b82516200015f8162000125565b6020840151909250620001728162000125565b809150509250929050565b6000602082840312156200019057600080fd5b81516200019d8162000125565b9392505050565b60805160a05160c051615ace6200022160003960008181614755015281816148a601526148d5015260008181612aaa015281816140dd0152818161416c01526141f5015260008181610907015281816122a401528181613a1d0152818161433e015281816143a801528181614e7e0152614f6a0152615ace6000f3fe6080604052600436106100e25760003560e01c8063a1879d9011610085578063a1879d9014610207578063ccec371614610227578063d71f11fb14610247578063e2a3bd6914610267578063e42f53431461029d578063e679daf514610302578063f0fa55a914610315578063f2fde38b14610335578063fc173e3d1461035557600080fd5b80631fd8ecd9146100ee57806320800a001461011057806338e781111461012557806353eedc6714610145578063715018a614610165578063816846c81461017a57806384614e1a146101cd5780638da5cb5b146101e057600080fd5b366100e957005b600080fd5b3480156100fa57600080fd5b5061010e6101093660046151b8565b610375565b005b34801561011c57600080fd5b5061010e6107d2565b34801561013157600080fd5b5061010e610140366004615210565b61083d565b34801561015157600080fd5b5061010e6101603660046152b5565b610853565b34801561017157600080fd5b5061010e6108ef565b34801561018657600080fd5b506101b5610195366004615362565b6003602090815260009283526040808420909152908252902054600f0b81565b604051600f9190910b81526020015b60405180910390f35b61010e6101db366004615380565b610903565b3480156101ec57600080fd5b506000546001600160a01b03165b6040516101c491906153e5565b34801561021357600080fd5b5061010e61022236600461541c565b6113db565b34801561023357600080fd5b5061010e6102423660046154af565b611470565b34801561025357600080fd5b5061010e6102623660046154cc565b611585565b34801561027357600080fd5b506101fa6102823660046154af565b6004602052600090815260409020546001600160a01b031681565b3480156102a957600080fd5b506102f36102b8366004615362565b60026020908152600092835260408084209091529082529020805460019091015460ff8216916001600160a01b036101009091048116911683565b6040516101c493929190615528565b61010e610310366004615576565b611e91565b34801561032157600080fd5b5061010e6103303660046155e9565b612115565b34801561034157600080fd5b5061010e6103503660046154af565b612122565b34801561036157600080fd5b5061010e610370366004615362565b612198565b6000856001600160a01b03166394cc699e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103d99190615602565b90506000866001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561041b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043f9190615602565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161046f91906153e5565b602060405180830381865afa15801561048c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b0919061561f565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016104e091906153e5565b602060405180830381865afa1580156104fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610521919061561f565b90506105386001600160a01b03851633308b6121ce565b60006105bf8a8685886001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161056c91906153e5565b602060405180830381865afa158015610589573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ad919061561f565b6105b7919061564e565b8b8b8b612239565b9050808a6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016105ee91906153e5565b602060405180830381865afa15801561060b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062f919061561f565b11156106c3576106c3336040516370a0823160e01b815283906001600160a01b038e16906370a08231906106679030906004016153e5565b602060405180830381865afa158015610684573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a8919061561f565b6106b2919061564e565b6001600160a01b038d169190612656565b6040516370a0823160e01b815282906001600160a01b038616906370a08231906106f19030906004016153e5565b602060405180830381865afa15801561070e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610732919061561f565b11156107c6576107c6336040516370a0823160e01b815284906001600160a01b038816906370a082319061076a9030906004016153e5565b602060405180830381865afa158015610787573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ab919061561f565b6107b5919061564e565b6001600160a01b0387169190612656565b50505050505050505050565b6107da61267a565b600080546040516001600160a01b039091169047908381818185875af1925050503d8060008114610827576040519150601f19603f3d011682016040523d82523d6000602084013e61082c565b606091505b505090508061083a57600080fd5b50565b61084561267a565b61084f82826126d4565b5050565b61085b61267a565b6001600160a01b0380841660009081526002602081815260408084209487168452939052919020825181548493839160ff19169060019084908111156108a3576108a3615512565b021790555060208201518154610100600160a81b0319166101006001600160a01b0392831602178255604090920151600190910180546001600160a01b03191691909216179055505050565b6108f761267a565b6109016000612a3d565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015610963573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109879190615602565b6001600160a01b031663e6a43905898a6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f89190615602565b6040518363ffffffff1660e01b8152600401610a15929190615667565b602060405180830381865afa158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a569190615602565b90506000886001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610a8691906153e5565b602060405180830381865afa158015610aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac7919061561f565b90506000896001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2d9190615602565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b5891906153e5565b602060405180830381865afa158015610b75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b99919061561f565b90506000610ba7344761564e565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610bd791906153e5565b602060405180830381865afa158015610bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c18919061561f565b9050610c2f6001600160a01b038d1633308e6121ce565b6001600160a01b038a16610c845760003411610c7c5760405162461bcd60e51b815260206004820152600760248201526609c8a8a888aa8960cb1b60448201526064015b60405180910390fd5b349850610c99565b610c996001600160a01b038b1633308c6121ce565b8b6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cfb9190615602565b6001600160a01b03168a6001600160a01b031614610d8257610d808a8d6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d799190615602565b8b8b612a8d565b505b610ed18c848e6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de99190615602565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610e1491906153e5565b602060405180830381865afa158015610e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e55919061561f565b610e5f919061564e565b8e6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec19190615602565b6001600160a01b03169190613330565b6040516370a0823160e01b81526001600160a01b038d169063a9e9c8bc90869083906370a0823190610f079030906004016153e5565b602060405180830381865afa158015610f24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f48919061561f565b610f52919061564e565b858f6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb59190615602565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610fe091906153e5565b602060405180830381865afa158015610ffd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611021919061561f565b61102b919061564e565b6040516001600160e01b031960e085901b16815260048101929092526024820152604481018a905260648101899052608401600060405180830381600087803b15801561107757600080fd5b505af115801561108b573d6000803e3d6000fd5b5050505061117e8c6001600160a01b03166394cc699e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f49190615602565b6040516370a0823160e01b815283906001600160a01b038916906370a08231906111229030906004016153e5565b602060405180830381865afa15801561113f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611163919061561f565b61116d919061564e565b6001600160a01b0388169190613330565b8b6001600160a01b03166394cc699e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e09190615602565b6001600160a01b031663adc9772e336040516370a0823160e01b815284906001600160a01b038a16906370a082319061121d9030906004016153e5565b602060405180830381865afa15801561123a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125e919061561f565b611268919061564e565b6040518363ffffffff1660e01b8152600401611285929190615681565b600060405180830381600087803b15801561129f57600080fd5b505af11580156112b3573d6000803e3d6000fd5b5050505081471115611356576000336112cc844761564e565b604051600081818185875af1925050503d8060008114611308576040519150601f19603f3d011682016040523d82523d6000602084013e61130d565b606091505b5050905080801561131e5750824710155b6113545760405162461bcd60e51b81526020600482015260076024820152660a89e9e9aaa86960cb1b6044820152606401610c73565b505b611361338d866133cc565b6113cd338d6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c79190615602565b856133cc565b505050505050505050505050565b60005b815181101561084f578181815181106113f9576113f961569a565b60200260200101516001600160a01b031663d279c1916114163390565b6040518263ffffffff1660e01b815260040161143291906153e5565b600060405180830381600087803b15801561144c57600080fd5b505af1158015611460573d6000803e3d6000fd5b5050600190920191506113de9050565b61147861267a565b6040516370a0823160e01b81526000906001600160a01b038316906370a08231906114a79030906004016153e5565b602060405180830381865afa1580156114c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e8919061561f565b116114f257600080fd5b61083a6115076000546001600160a01b031690565b6040516370a0823160e01b81526001600160a01b038416906370a08231906115339030906004016153e5565b602060405180830381865afa158015611550573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611574919061561f565b6001600160a01b0384169190612656565b6000846001600160a01b03166353f504476040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e991906156b0565b60018111156115fa576115fa615512565b03611c50576000846001600160a01b0316632acada4d6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561163f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261166791908101906156d1565b9050600081516001600160401b0381111561168457611684615247565b6040519080825280602002602001820160405280156116ad578160200160208202803683370190505b5090506000856001600160a01b03166370a08231886040518263ffffffff1660e01b81526004016116de91906153e5565b602060405180830381865afa1580156116fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171f919061561f565b90506000876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611761573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611785919061561f565b156117a85781611799600160601b886157b4565b6117a391906157cb565b6117ae565b600160601b5b905060005b8451811015611a86576000896001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611820919061561f565b156118ce57600160601b8387848151811061183d5761183d61569a565b6020026020010151600001516001600160a01b03166370a082318d6040518263ffffffff1660e01b815260040161187491906153e5565b602060405180830381865afa158015611891573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b5919061561f565b6118bf91906157b4565b6118c991906157cb565b61195c565b896001600160a01b031663e4b549578a8a8986815181106118f1576118f161569a565b6020026020010151600001516040518463ffffffff1660e01b815260040161191b939291906157ed565b602060405180830381865afa158015611938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195c919061561f565b90508582815181106119705761197061569a565b6020026020010151600001516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016119a791906153e5565b602060405180830381865afa1580156119c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e8919061561f565b8583815181106119fa576119fa61569a565b6020908102919091010152611a42333083898681518110611a1d57611a1d61569a565b6020026020010151600001516001600160a01b03166121ce909392919063ffffffff16565b611a7d8a82888581518110611a5957611a5961569a565b6020026020010151600001516001600160a01b03166133309092919063ffffffff16565b506001016117b3565b506040516370a0823160e01b81526000906001600160a01b038a16906370a0823190611ab69030906004016153e5565b602060405180830381865afa158015611ad3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af7919061561f565b60405163b08d033360e01b81529091506001600160a01b038a169063b08d033390611b2a908b908b908b90600401615810565b600060405180830381600087803b158015611b4457600080fd5b505af1158015611b58573d6000803e3d6000fd5b50505050611bf0611b663390565b6040516370a0823160e01b815283906001600160a01b038d16906370a0823190611b949030906004016153e5565b602060405180830381865afa158015611bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd5919061561f565b611bdf919061564e565b6001600160a01b038c169190612656565b60005b8551811015611c4557611c3d33878381518110611c1257611c1261569a565b602002602001015160000151878481518110611c3057611c3061569a565b60200260200101516133cc565b600101611bf3565b505050505050611e8b565b6001846001600160a01b03166353f504476040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb491906156b0565b6001811115611cc557611cc5615512565b14611cf75760405162461bcd60e51b8152602060048201526002602482015261555760f01b6044820152606401610c73565b611d0c6001600160a01b0384163330856121ce565b611d206001600160a01b0384168584613330565b6040516370a0823160e01b81526000906001600160a01b038616906370a0823190611d4f9030906004016153e5565b602060405180830381865afa158015611d6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d90919061561f565b60405163b08d033360e01b81529091506001600160a01b0386169063b08d033390611dc390879087908790600401615810565b600060405180830381600087803b158015611ddd57600080fd5b505af1158015611df1573d6000803e3d6000fd5b50505050611e89611dff3390565b6040516370a0823160e01b815283906001600160a01b038916906370a0823190611e2d9030906004016153e5565b602060405180830381865afa158015611e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6e919061561f565b611e78919061564e565b6001600160a01b0388169190612656565b505b50505050565b60003411611eca5760405162461bcd60e51b81526020600482015260066024820152654e415449564560d01b6044820152606401610c73565b6000611ed6344761564e565b90506000896001600160a01b0316632acada4d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015611f18573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f4091908101906156d1565b9050600080611f678c86611f545734611f5f565b611f5f6002346157cb565b858e8e613465565b9150915060005b8351811015611fb657808c14611fae57611fae8d838381518110611f9457611f9461569a565b6020026020010151868481518110611a5957611a5961569a565b600101611f6e565b5060006120078d858e81518110611fcf57611fcf61569a565b602002602001015160000151848f81518110611fed57611fed61569a565b60200260200101518d8a61200157336136bf565b306136bf565b9050851561202857612028338e836120206002346157cb565b8d8d8d613852565b60005b8451811015612070576120683386838151811061204a5761204a61569a565b602002602001015160000151868481518110611c3057611c3061569a565b60010161202b565b508447111561210657600033612086874761564e565b604051600081818185875af1925050503d80600081146120c2576040519150601f19603f3d011682016040523d82523d6000602084013e6120c7565b606091505b50509050806121045760405162461bcd60e51b815260206004820152600960248201526811551214915195539160ba1b6044820152606401610c73565b505b50505050505050505050505050565b61211d61267a565b600155565b61212a61267a565b6001600160a01b03811661218f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610c73565b61083a81612a3d565b6121a061267a565b6001600160a01b03918216600090815260046020526040902080546001600160a01b03191691909216179055565b6040516001600160a01b0380851660248301528316604482015260648101829052611e8b9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614003565b600080876001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561227a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229e9190615602565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015612300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123249190615602565b6001600160a01b031663e6a439058a846040518363ffffffff1660e01b8152600401612351929190615667565b602060405180830381865afa15801561236e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123929190615602565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016123c291906153e5565b602060405180830381865afa1580156123df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612403919061561f565b6040516305c2fbcf60e31b8152600481018a90529091506001600160a01b038a1690632e17de7890602401600060405180830381600087803b15801561244857600080fd5b505af115801561245c573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b038d1692506370a08231915061248c9030906004016153e5565b602060405180830381865afa1580156124a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cd919061561f565b935061255c8a82846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161250091906153e5565b602060405180830381865afa15801561251d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612541919061561f565b61254b919061564e565b6001600160a01b0385169190613330565b896001600160a01b031663f682399682846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161259891906153e5565b602060405180830381865afa1580156125b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d9919061561f565b6125e3919061564e565b6040516001600160e01b031960e084901b1681526004810191909152602481018a90526044810189905260648101889052608401600060405180830381600087803b15801561263157600080fd5b505af1158015612645573d6000803e3d6000fd5b505050505050509695505050505050565b6126758363a9059cbb60e01b8484604051602401612202929190615681565b505050565b6000546001600160a01b031633146109015760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c73565b600080808460028111156126ea576126ea615512565b036128185760405163c661065760e01b8152600060048201526001600160a01b0384169063c6610657906024016020604051808303816000875af1158015612736573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061275a9190615602565b60405163c661065760e01b8152600160048201529092506001600160a01b0384169063c6610657906024016020604051808303816000875af11580156127a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127c89190615602565b6001600160a01b038481166000908152600360209081526040808320878516845290915280822080546001600160801b0319908116909155928416825290208054909116600117905590506128e1565b826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612856573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287a9190615602565b9150826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128de9190615602565b90505b6000604051806060016040528086600281111561290057612900615512565b81526001600160a01b0380871660208084019190915260006040938401819052878316815260028083528482209388168252929091529190912082518154939450849391929091839160ff1990911690600190849081111561296457612964615512565b02179055506020828101518254610100600160a81b0319166101006001600160a01b0392831602178355604093840151600193840180546001600160a01b0319169183169190911790558581166000908152600280845285822092891682529190925292902083518154859492939192849260ff19909216919084908111156129ef576129ef615512565b021790555060208201518154610100600160a81b0319166101006001600160a01b0392831602178255604090920151600190910180546001600160a01b031916919092161790555050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006001600160a01b038516612acc57612aa6836140d8565b92507f000000000000000000000000000000000000000000000000000000000000000094505b6001600160a01b03848116600090815260046020526040812054909182911615612b125750506001600160a01b0380851660009081526004602052604090205416936001905b6001600160a01b038088166000908152600260208181526040808420948b16845293905282822083516060810190945280549293929091839160ff1690811115612b5e57612b5e615512565b6002811115612b6f57612b6f615512565b815281546001600160a01b03610100909104811660208084019190915260019093015481166040909201919091529082015191925016612c4f576040805160028082526060820183526000926020830190803683370190505090508881600081518110612bde57612bde61569a565b60200260200101906001600160a01b031690816001600160a01b0316815250508781600181518110612c1257612c1261569a565b6001600160a01b03928316602091820292909201015289811690891614612c4557612c3e81888861427e565b9450612c49565b8694505b506131b2565b60408101516001600160a01b03161515600082516002811115612c7457612c74615512565b03612d4357612d3c82602001516003600085602001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c6001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a9004600f0b6003600086602001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c6001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a9004600f0b8a8a61449a565b94506131b0565b600182516002811115612d5857612d58615512565b03612f6657600082602001516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612da1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc59190615602565b9050600082612dd5576002612dd8565b60035b60ff166001600160401b03811115612df257612df2615247565b604051908082528060200260200182016040528015612e1b578160200160208202803683370190505b5090508a81600081518110612e3257612e3261569a565b60200260200101906001600160a01b031690816001600160a01b0316815250508215612ee2578a6001600160a01b0316826001600160a01b031614612e775781612ee4565b83602001516001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612eb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612edd9190615602565b612ee4565b895b81600181518110612ef757612ef761569a565b60200260200101906001600160a01b031690816001600160a01b0316815250508215612f52578981600281518110612f3157612f3161569a565b60200260200101906001600160a01b031690816001600160a01b0316815250505b612f5d818a8a61427e565b965050506131b0565b801561313b57600082602001516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd49190615602565b90506131338a84602001516001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa15801561301c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130409190615831565b8c6001600160a01b0316846001600160a01b03161461305f57836130c5565b85602001516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c59190615602565b86604001516001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015613107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312b9190615831565b8d8d8d614527565b9550506131b0565b6131ad8983602001516001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015613181573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a59190615831565b8a8a8a614747565b94505b505b826131bf57505050613328565b6040516370a0823160e01b81526000906001600160a01b038416906370a08231906131ee9030906004016153e5565b602060405180830381865afa15801561320b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061322f919061561f565b90506132456001600160a01b0389168487613330565b60405163b08d033360e01b81526001600160a01b0384169063b08d033390613276908b908990600090600401615810565b600060405180830381600087803b15801561329057600080fd5b505af11580156132a4573d6000803e3d6000fd5b50506040516370a0823160e01b81528392506001600160a01b03861691506370a08231906132d69030906004016153e5565b602060405180830381865afa1580156132f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613317919061561f565b613321919061564e565b9450505050505b949350505050565b604051636eb1769f60e11b81526000906001600160a01b0385169063dd62ed3e906133619030908790600401615667565b602060405180830381865afa15801561337e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a2919061561f565b9050611e8b8463095ea7b360e01b856133bb8686615856565b604051602401612202929190615681565b6040516370a0823160e01b81526000906001600160a01b038416906370a08231906133fb9030906004016153e5565b602060405180830381865afa158015613418573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343c919061561f565b905081811115611e8b57611e8b84613454848461564e565b6001600160a01b0386169190612656565b606080600085516001600160401b0381111561348357613483615247565b6040519080825280602002602001820160405280156134ac578160200160208202803683370190505b509050600086516001600160401b038111156134ca576134ca615247565b6040519080825280602002602001820160405280156134f3578160200160208202803683370190505b509050600087878151811061350a5761350a61569a565b6020026020010151600001516001600160a01b03166370a082318b6040518263ffffffff1660e01b815260040161354191906153e5565b602060405180830381865afa15801561355e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613582919061561f565b905060008a6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156135c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135e8919061561f565b1561360b57816135fc600160601b896157b4565b61360691906157cb565b613611565b600160601b5b90508960005b8a518110156136ac576136688d8c8c815181106136365761363661569a565b6020026020010151600001518b8e85815181106136555761365561569a565b6020026020010151600001518787614c78565b88848151811061367a5761367a61569a565b602002602001018885815181106136935761369361569a565b6020908102919091010191909152529150600101613617565b50939b929a509198505050505050505050565b600080866001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016136ee91906153e5565b602060405180830381865afa15801561370b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061372f919061561f565b90506137456001600160a01b0387168887613330565b60405163b08d033360e01b81526001600160a01b0388169063b08d03339061377590899089908990600401615810565b600060405180830381600087803b15801561378f57600080fd5b505af11580156137a3573d6000803e3d6000fd5b50505050600081886001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016137d691906153e5565b602060405180830381865afa1580156137f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613817919061561f565b613821919061564e565b90506001600160a01b0384163014613847576138476001600160a01b0389168583612656565b979650505050505050565b6000866001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613892573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138b69190615602565b9050600086886001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016138e791906153e5565b602060405180830381865afa158015613904573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613928919061561f565b613932919061564e565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161396291906153e5565b602060405180830381865afa15801561397f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139a3919061561f565b90506000896001600160a01b03166394cc699e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a099190615602565b9050613a186000858a8a612a8d565b5060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a9d9190615602565b6001600160a01b031663e6a439058c876040518363ffffffff1660e01b8152600401613aca929190615667565b602060405180830381865afa158015613ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0b9190615602565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613b3b91906153e5565b602060405180830381865afa158015613b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7c919061561f565b9050613c0b8c85886001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613baf91906153e5565b602060405180830381865afa158015613bcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bf0919061561f565b613bfa919061564e565b6001600160a01b0389169190613330565b8b6001600160a01b031663a9e9c8bc8c86896001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613c4891906153e5565b602060405180830381865afa158015613c65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c89919061561f565b613c93919061564e565b6040516001600160e01b031960e085901b16815260048101929092526024820152604481018b9052606481018a9052608401600060405180830381600087803b158015613cdf57600080fd5b505af1158015613cf3573d6000803e3d6000fd5b50505050613d288382846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161250091906153e5565b826001600160a01b031663adc9772e8e83856001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613d6591906153e5565b602060405180830381865afa158015613d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613da6919061561f565b613db0919061564e565b6040518363ffffffff1660e01b8152600401613dcd929190615681565b600060405180830381600087803b158015613de757600080fd5b505af1158015613dfb573d6000803e3d6000fd5b50506040516370a0823160e01b81528792506001600160a01b038f1691506370a0823190613e2d9030906004016153e5565b602060405180830381865afa158015613e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6e919061561f565b1115613f0157613f018d868e6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613ea591906153e5565b602060405180830381865afa158015613ec2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ee6919061561f565b613ef0919061564e565b6001600160a01b038f169190612656565b6040516370a0823160e01b815284906001600160a01b038816906370a0823190613f2f9030906004016153e5565b602060405180830381865afa158015613f4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f70919061561f565b1115612106576121068d85886001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613fa791906153e5565b602060405180830381865afa158015613fc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe8919061561f565b613ff2919061564e565b6001600160a01b0389169190612656565b6000614058826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166150909092919063ffffffff16565b90508051600014806140795750808060200190518101906140799190615869565b6126755760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c73565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161412791906153e5565b602060405180830381865afa158015614144573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614168919061561f565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b1580156141c557600080fd5b505af11580156141d9573d6000803e3d6000fd5b50506040516370a0823160e01b81528493506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692506370a08231915061422c9030906004016153e5565b602060405180830381865afa158015614249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061426d919061561f565b614277919061564e565b9392505050565b60008084516003146142aa578460018151811061429d5761429d61569a565b60200260200101516142c6565b846002815181106142bd576142bd61569a565b60200260200101515b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016142f691906153e5565b602060405180830381865afa158015614313573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614337919061561f565b90506143917f000000000000000000000000000000000000000000000000000000000000000086886000815181106143715761437161569a565b60200260200101516001600160a01b03166133309092919063ffffffff16565b604051635c11d79560e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635c11d795906143e590889088908b90309042906004016158cb565b600060405180830381600087803b1580156143ff57600080fd5b505af1158015614413573d6000803e3d6000fd5b50506040516370a0823160e01b81528392506001600160a01b03851691506370a08231906144459030906004016153e5565b602060405180830381865afa158015614462573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614486919061561f565b614490919061564e565b9695505050505050565b60405163ddc1f59d60e01b8152600f85810b600483015284900b602482015260448101839052606481018290523060848201526000906001600160a01b0387169063ddc1f59d9060a4016020604051808303816000875af1158015614503573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614490919061561f565b600080846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161455691906153e5565b602060405180830381865afa158015614573573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614597919061561f565b90506145c16001600160a01b038a16732626664c2603336e57b271c5c0b26f421741e48186613330565b6040516bffffffffffffffffffffffff1960608b811b821660208401526001600160e81b031960e88c811b821660348601528b831b841660378601528a901b16604b84015287901b16604e82015260009060620160408051601f1981840301815260a08301825280835230602084015242838301526060830188905260808301879052905163c04b8d5960e01b8152909250732626664c2603336e57b271c5c0b26f421741e4819163c04b8d599161467c9190600401615957565b6020604051808303816000875af115801561469b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146bf919061561f565b506040516370a0823160e01b815282906001600160a01b038816906370a08231906146ee9030906004016153e5565b602060405180830381865afa15801561470b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061472f919061561f565b614739919061564e565b9a9950505050505050505050565b600081600003614a155760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634556bd20732626664c2603336e57b271c5c0b26f421741e4816001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156147d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147f89190615602565b6040516001600160e01b031960e084901b1681526001600160a01b039182166004820152818b166024820152908816604482015262ffffff89166064820152608401602060405180830381865afa158015614857573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061487b9190615602565b90506000856001600160a01b0316886001600160a01b03161061489e57856148a0565b875b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d4bf13347f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316637fb4f79d866040518263ffffffff1660e01b815260040161491f91906153e5565b602060405180830381865afa15801561493c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149609190615602565b6040518263ffffffff1660e01b815260040161497c91906153e5565b602060405180830381865afa158015614999573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149bd919061561f565b9050816001600160a01b0316896001600160a01b0316146149f657806149e7600160601b886157b4565b6149f191906157cb565b614a0f565b600160601b614a0587836157b4565b614a0f91906157cb565b94505050505b6040516370a0823160e01b81526000906001600160a01b038616906370a0823190614a449030906004016153e5565b602060405180830381865afa158015614a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a85919061561f565b9050614aaf6001600160a01b038816732626664c2603336e57b271c5c0b26f421741e48186613330565b732626664c2603336e57b271c5c0b26f421741e4816001600160a01b03166304e45aaf6040518060e001604052808a6001600160a01b03168152602001886001600160a01b031681526020018962ffffff168152602001306001600160a01b031681526020018781526020016103e86001546103e8614b2e919061564e565b614b3890896157b4565b614b4291906157cb565b815260006020918201526040805160e085901b6001600160e01b031916815283516001600160a01b03908116600483015292840151831660248201529083015162ffffff1660448201526060830151821660648201526080830151608482015260a083015160a482015260c0909201511660c482015260e4016020604051808303816000875af1158015614bda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bfe919061561f565b506040516370a0823160e01b815281906001600160a01b038716906370a0823190614c2d9030906004016153e5565b602060405180830381865afa158015614c4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c6e919061561f565b613847919061564e565b6040516370a0823160e01b81526000908190819047906001600160a01b038816906370a0823190614cad9030906004016153e5565b602060405180830381865afa158015614cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614cee919061561f565b925060008a6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614d30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d54919061561f565b15614de557600160601b87896001600160a01b03166370a082318e6040518263ffffffff1660e01b8152600401614d8b91906153e5565b602060405180830381865afa158015614da8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614dcc919061561f565b614dd691906157b4565b614de091906157cb565b614e56565b60405163e4b5495760e01b81526001600160a01b038c169063e4b5495790614e15908d908d908d906004016157ed565b602060405180830381865afa158015614e32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e56919061561f565b60408051600280825260608201835292935060009290916020830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015614eda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614efe9190615602565b81600081518110614f1157614f1161569a565b60200260200101906001600160a01b031690816001600160a01b0316815250508881600181518110614f4557614f4561569a565b6001600160a01b03928316602091820292909201015260405163fb3bdb4160e01b81527f00000000000000000000000000000000000000000000000000000000000000009091169063fb3bdb41908990614fa99086908690309042906004016159af565b60006040518083038185885af1158015614fc7573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052614ff091908101906159e4565b50614ffb478461564e565b615005908861564e565b955084896001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161503491906153e5565b602060405180830381865afa158015615051573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615075919061561f565b61507f919061564e565b935050505096509650969350505050565b6060613328848460008585600080866001600160a01b031685876040516150b79190615a69565b60006040518083038185875af1925050503d80600081146150f4576040519150601f19603f3d011682016040523d82523d6000602084013e6150f9565b606091505b5091509150613847878383876060831561517457825160000361516d576001600160a01b0385163b61516d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c73565b5081613328565b61332883838151156151895781518083602001fd5b8060405162461bcd60e51b8152600401610c739190615a85565b6001600160a01b038116811461083a57600080fd5b600080600080600060a086880312156151d057600080fd5b85356151db816151a3565b97602087013597506040870135966060810135965060800135945092505050565b80356003811061520b57600080fd5b919050565b6000806040838503121561522357600080fd5b61522c836151fc565b9150602083013561523c816151a3565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b038111828210171561527f5761527f615247565b60405290565b604051601f8201601f191681016001600160401b03811182821017156152ad576152ad615247565b604052919050565b600080600083850360a08112156152cb57600080fd5b84356152d6816151a3565b935060208501356152e6816151a3565b92506060603f19820112156152fa57600080fd5b50604051606081018181106001600160401b038211171561531d5761531d615247565b806040525061532e604086016151fc565b8152606085013561533e816151a3565b60208201526080850135615351816151a3565b604082015292959194509192509050565b6000806040838503121561537557600080fd5b823561522c816151a3565b600080600080600080600060e0888a03121561539b57600080fd5b87356153a6816151a3565b96506020880135955060408801356153bd816151a3565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b6001600160a01b0391909116815260200190565b60006001600160401b0382111561541257615412615247565b5060051b60200190565b6000602080838503121561542f57600080fd5b82356001600160401b0381111561544557600080fd5b8301601f8101851361545657600080fd5b8035615469615464826153f9565b615285565b81815260059190911b8201830190838101908783111561548857600080fd5b928401925b828410156138475783356154a0816151a3565b8252928401929084019061548d565b6000602082840312156154c157600080fd5b8135614277816151a3565b600080600080608085870312156154e257600080fd5b84356154ed816151a3565b935060208501356154fd816151a3565b93969395505050506040820135916060013590565b634e487b7160e01b600052602160045260246000fd5b606081016003851061554a57634e487b7160e01b600052602160045260246000fd5b9381526001600160a01b039283166020820152911660409091015290565b801515811461083a57600080fd5b600080600080600080600080610100898b03121561559357600080fd5b883561559e816151a3565b97506020890135965060408901359550606089013594506080890135935060a0890135925060c0890135915060e08901356155d881615568565b809150509295985092959890939650565b6000602082840312156155fb57600080fd5b5035919050565b60006020828403121561561457600080fd5b8151614277816151a3565b60006020828403121561563157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561566157615661615638565b92915050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156156c257600080fd5b81516002811061427757600080fd5b600060208083850312156156e457600080fd5b82516001600160401b038111156156fa57600080fd5b8301601f8101851361570b57600080fd5b8051615719615464826153f9565b81815260a0918202830184019184820191908884111561573857600080fd5b938501935b838510156157a85780858a0312156157555760008081fd5b61575d61525d565b8551615768816151a3565b815285870151878201526040808701519082015260608087015161578b816151a3565b90820152608086810151908201528352938401939185019161573d565b50979650505050505050565b808202811582820484141761566157615661615638565b6000826157e857634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b039390931683526020830191909152604082015260600190565b60006020828403121561584357600080fd5b815162ffffff8116811461427757600080fd5b8082018082111561566157615661615638565b60006020828403121561587b57600080fd5b815161427781615568565b60008151808452602080850194506020840160005b838110156158c05781516001600160a01b03168752958201959082019060010161589b565b509495945050505050565b85815284602082015260a0604082015260006158ea60a0830186615886565b6001600160a01b0394909416606083015250608001529392505050565b60005b8381101561592257818101518382015260200161590a565b50506000910152565b60008151808452615943816020860160208601615907565b601f01601f19169290920160200192915050565b602081526000825160a0602084015261597360c084018261592b565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b8481526080602082015260006159c86080830186615886565b6001600160a01b03949094166040830152506060015292915050565b600060208083850312156159f757600080fd5b82516001600160401b03811115615a0d57600080fd5b8301601f81018513615a1e57600080fd5b8051615a2c615464826153f9565b81815260059190911b82018301908381019087831115615a4b57600080fd5b928401925b8284101561384757835182529284019290840190615a50565b60008251615a7b818460208701615907565b9190910192915050565b602081526000614277602083018461592b56fea2646970667358221220d2529528d6b2c45960f2c77150e689440a8c359d9dc06b25ad049a71e7da2ac964736f6c6343000818003300000000000000000000000098994a9a7a2570367554589189dc9772241650f6000000000000000000000000e603f046ee5141a6f3bb8549660417e83062b688
Deployed Bytecode
0x6080604052600436106100e25760003560e01c8063a1879d9011610085578063a1879d9014610207578063ccec371614610227578063d71f11fb14610247578063e2a3bd6914610267578063e42f53431461029d578063e679daf514610302578063f0fa55a914610315578063f2fde38b14610335578063fc173e3d1461035557600080fd5b80631fd8ecd9146100ee57806320800a001461011057806338e781111461012557806353eedc6714610145578063715018a614610165578063816846c81461017a57806384614e1a146101cd5780638da5cb5b146101e057600080fd5b366100e957005b600080fd5b3480156100fa57600080fd5b5061010e6101093660046151b8565b610375565b005b34801561011c57600080fd5b5061010e6107d2565b34801561013157600080fd5b5061010e610140366004615210565b61083d565b34801561015157600080fd5b5061010e6101603660046152b5565b610853565b34801561017157600080fd5b5061010e6108ef565b34801561018657600080fd5b506101b5610195366004615362565b6003602090815260009283526040808420909152908252902054600f0b81565b604051600f9190910b81526020015b60405180910390f35b61010e6101db366004615380565b610903565b3480156101ec57600080fd5b506000546001600160a01b03165b6040516101c491906153e5565b34801561021357600080fd5b5061010e61022236600461541c565b6113db565b34801561023357600080fd5b5061010e6102423660046154af565b611470565b34801561025357600080fd5b5061010e6102623660046154cc565b611585565b34801561027357600080fd5b506101fa6102823660046154af565b6004602052600090815260409020546001600160a01b031681565b3480156102a957600080fd5b506102f36102b8366004615362565b60026020908152600092835260408084209091529082529020805460019091015460ff8216916001600160a01b036101009091048116911683565b6040516101c493929190615528565b61010e610310366004615576565b611e91565b34801561032157600080fd5b5061010e6103303660046155e9565b612115565b34801561034157600080fd5b5061010e6103503660046154af565b612122565b34801561036157600080fd5b5061010e610370366004615362565b612198565b6000856001600160a01b03166394cc699e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103d99190615602565b90506000866001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561041b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061043f9190615602565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161046f91906153e5565b602060405180830381865afa15801561048c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b0919061561f565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016104e091906153e5565b602060405180830381865afa1580156104fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610521919061561f565b90506105386001600160a01b03851633308b6121ce565b60006105bf8a8685886001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161056c91906153e5565b602060405180830381865afa158015610589573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ad919061561f565b6105b7919061564e565b8b8b8b612239565b9050808a6001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016105ee91906153e5565b602060405180830381865afa15801561060b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062f919061561f565b11156106c3576106c3336040516370a0823160e01b815283906001600160a01b038e16906370a08231906106679030906004016153e5565b602060405180830381865afa158015610684573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106a8919061561f565b6106b2919061564e565b6001600160a01b038d169190612656565b6040516370a0823160e01b815282906001600160a01b038616906370a08231906106f19030906004016153e5565b602060405180830381865afa15801561070e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610732919061561f565b11156107c6576107c6336040516370a0823160e01b815284906001600160a01b038816906370a082319061076a9030906004016153e5565b602060405180830381865afa158015610787573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ab919061561f565b6107b5919061564e565b6001600160a01b0387169190612656565b50505050505050505050565b6107da61267a565b600080546040516001600160a01b039091169047908381818185875af1925050503d8060008114610827576040519150601f19603f3d011682016040523d82523d6000602084013e61082c565b606091505b505090508061083a57600080fd5b50565b61084561267a565b61084f82826126d4565b5050565b61085b61267a565b6001600160a01b0380841660009081526002602081815260408084209487168452939052919020825181548493839160ff19169060019084908111156108a3576108a3615512565b021790555060208201518154610100600160a81b0319166101006001600160a01b0392831602178255604090920151600190910180546001600160a01b03191691909216179055505050565b6108f761267a565b6109016000612a3d565b565b60007f00000000000000000000000098994a9a7a2570367554589189dc9772241650f66001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015610963573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109879190615602565b6001600160a01b031663e6a43905898a6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f89190615602565b6040518363ffffffff1660e01b8152600401610a15929190615667565b602060405180830381865afa158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a569190615602565b90506000886001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610a8691906153e5565b602060405180830381865afa158015610aa3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ac7919061561f565b90506000896001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2d9190615602565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610b5891906153e5565b602060405180830381865afa158015610b75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b99919061561f565b90506000610ba7344761564e565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610bd791906153e5565b602060405180830381865afa158015610bf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c18919061561f565b9050610c2f6001600160a01b038d1633308e6121ce565b6001600160a01b038a16610c845760003411610c7c5760405162461bcd60e51b815260206004820152600760248201526609c8a8a888aa8960cb1b60448201526064015b60405180910390fd5b349850610c99565b610c996001600160a01b038b1633308c6121ce565b8b6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cfb9190615602565b6001600160a01b03168a6001600160a01b031614610d8257610d808a8d6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d799190615602565b8b8b612a8d565b505b610ed18c848e6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de99190615602565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610e1491906153e5565b602060405180830381865afa158015610e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e55919061561f565b610e5f919061564e565b8e6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec19190615602565b6001600160a01b03169190613330565b6040516370a0823160e01b81526001600160a01b038d169063a9e9c8bc90869083906370a0823190610f079030906004016153e5565b602060405180830381865afa158015610f24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f48919061561f565b610f52919061564e565b858f6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb59190615602565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401610fe091906153e5565b602060405180830381865afa158015610ffd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611021919061561f565b61102b919061564e565b6040516001600160e01b031960e085901b16815260048101929092526024820152604481018a905260648101899052608401600060405180830381600087803b15801561107757600080fd5b505af115801561108b573d6000803e3d6000fd5b5050505061117e8c6001600160a01b03166394cc699e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f49190615602565b6040516370a0823160e01b815283906001600160a01b038916906370a08231906111229030906004016153e5565b602060405180830381865afa15801561113f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611163919061561f565b61116d919061564e565b6001600160a01b0388169190613330565b8b6001600160a01b03166394cc699e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e09190615602565b6001600160a01b031663adc9772e336040516370a0823160e01b815284906001600160a01b038a16906370a082319061121d9030906004016153e5565b602060405180830381865afa15801561123a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125e919061561f565b611268919061564e565b6040518363ffffffff1660e01b8152600401611285929190615681565b600060405180830381600087803b15801561129f57600080fd5b505af11580156112b3573d6000803e3d6000fd5b5050505081471115611356576000336112cc844761564e565b604051600081818185875af1925050503d8060008114611308576040519150601f19603f3d011682016040523d82523d6000602084013e61130d565b606091505b5050905080801561131e5750824710155b6113545760405162461bcd60e51b81526020600482015260076024820152660a89e9e9aaa86960cb1b6044820152606401610c73565b505b611361338d866133cc565b6113cd338d6001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c79190615602565b856133cc565b505050505050505050505050565b60005b815181101561084f578181815181106113f9576113f961569a565b60200260200101516001600160a01b031663d279c1916114163390565b6040518263ffffffff1660e01b815260040161143291906153e5565b600060405180830381600087803b15801561144c57600080fd5b505af1158015611460573d6000803e3d6000fd5b5050600190920191506113de9050565b61147861267a565b6040516370a0823160e01b81526000906001600160a01b038316906370a08231906114a79030906004016153e5565b602060405180830381865afa1580156114c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e8919061561f565b116114f257600080fd5b61083a6115076000546001600160a01b031690565b6040516370a0823160e01b81526001600160a01b038416906370a08231906115339030906004016153e5565b602060405180830381865afa158015611550573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611574919061561f565b6001600160a01b0384169190612656565b6000846001600160a01b03166353f504476040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e991906156b0565b60018111156115fa576115fa615512565b03611c50576000846001600160a01b0316632acada4d6040518163ffffffff1660e01b8152600401600060405180830381865afa15801561163f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261166791908101906156d1565b9050600081516001600160401b0381111561168457611684615247565b6040519080825280602002602001820160405280156116ad578160200160208202803683370190505b5090506000856001600160a01b03166370a08231886040518263ffffffff1660e01b81526004016116de91906153e5565b602060405180830381865afa1580156116fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171f919061561f565b90506000876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611761573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611785919061561f565b156117a85781611799600160601b886157b4565b6117a391906157cb565b6117ae565b600160601b5b905060005b8451811015611a86576000896001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611820919061561f565b156118ce57600160601b8387848151811061183d5761183d61569a565b6020026020010151600001516001600160a01b03166370a082318d6040518263ffffffff1660e01b815260040161187491906153e5565b602060405180830381865afa158015611891573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b5919061561f565b6118bf91906157b4565b6118c991906157cb565b61195c565b896001600160a01b031663e4b549578a8a8986815181106118f1576118f161569a565b6020026020010151600001516040518463ffffffff1660e01b815260040161191b939291906157ed565b602060405180830381865afa158015611938573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195c919061561f565b90508582815181106119705761197061569a565b6020026020010151600001516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016119a791906153e5565b602060405180830381865afa1580156119c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e8919061561f565b8583815181106119fa576119fa61569a565b6020908102919091010152611a42333083898681518110611a1d57611a1d61569a565b6020026020010151600001516001600160a01b03166121ce909392919063ffffffff16565b611a7d8a82888581518110611a5957611a5961569a565b6020026020010151600001516001600160a01b03166133309092919063ffffffff16565b506001016117b3565b506040516370a0823160e01b81526000906001600160a01b038a16906370a0823190611ab69030906004016153e5565b602060405180830381865afa158015611ad3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af7919061561f565b60405163b08d033360e01b81529091506001600160a01b038a169063b08d033390611b2a908b908b908b90600401615810565b600060405180830381600087803b158015611b4457600080fd5b505af1158015611b58573d6000803e3d6000fd5b50505050611bf0611b663390565b6040516370a0823160e01b815283906001600160a01b038d16906370a0823190611b949030906004016153e5565b602060405180830381865afa158015611bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd5919061561f565b611bdf919061564e565b6001600160a01b038c169190612656565b60005b8551811015611c4557611c3d33878381518110611c1257611c1261569a565b602002602001015160000151878481518110611c3057611c3061569a565b60200260200101516133cc565b600101611bf3565b505050505050611e8b565b6001846001600160a01b03166353f504476040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb491906156b0565b6001811115611cc557611cc5615512565b14611cf75760405162461bcd60e51b8152602060048201526002602482015261555760f01b6044820152606401610c73565b611d0c6001600160a01b0384163330856121ce565b611d206001600160a01b0384168584613330565b6040516370a0823160e01b81526000906001600160a01b038616906370a0823190611d4f9030906004016153e5565b602060405180830381865afa158015611d6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d90919061561f565b60405163b08d033360e01b81529091506001600160a01b0386169063b08d033390611dc390879087908790600401615810565b600060405180830381600087803b158015611ddd57600080fd5b505af1158015611df1573d6000803e3d6000fd5b50505050611e89611dff3390565b6040516370a0823160e01b815283906001600160a01b038916906370a0823190611e2d9030906004016153e5565b602060405180830381865afa158015611e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6e919061561f565b611e78919061564e565b6001600160a01b0388169190612656565b505b50505050565b60003411611eca5760405162461bcd60e51b81526020600482015260066024820152654e415449564560d01b6044820152606401610c73565b6000611ed6344761564e565b90506000896001600160a01b0316632acada4d6040518163ffffffff1660e01b8152600401600060405180830381865afa158015611f18573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611f4091908101906156d1565b9050600080611f678c86611f545734611f5f565b611f5f6002346157cb565b858e8e613465565b9150915060005b8351811015611fb657808c14611fae57611fae8d838381518110611f9457611f9461569a565b6020026020010151868481518110611a5957611a5961569a565b600101611f6e565b5060006120078d858e81518110611fcf57611fcf61569a565b602002602001015160000151848f81518110611fed57611fed61569a565b60200260200101518d8a61200157336136bf565b306136bf565b9050851561202857612028338e836120206002346157cb565b8d8d8d613852565b60005b8451811015612070576120683386838151811061204a5761204a61569a565b602002602001015160000151868481518110611c3057611c3061569a565b60010161202b565b508447111561210657600033612086874761564e565b604051600081818185875af1925050503d80600081146120c2576040519150601f19603f3d011682016040523d82523d6000602084013e6120c7565b606091505b50509050806121045760405162461bcd60e51b815260206004820152600960248201526811551214915195539160ba1b6044820152606401610c73565b505b50505050505050505050505050565b61211d61267a565b600155565b61212a61267a565b6001600160a01b03811661218f5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610c73565b61083a81612a3d565b6121a061267a565b6001600160a01b03918216600090815260046020526040902080546001600160a01b03191691909216179055565b6040516001600160a01b0380851660248301528316604482015260648101829052611e8b9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614003565b600080876001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561227a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229e9190615602565b905060007f00000000000000000000000098994a9a7a2570367554589189dc9772241650f66001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015612300573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123249190615602565b6001600160a01b031663e6a439058a846040518363ffffffff1660e01b8152600401612351929190615667565b602060405180830381865afa15801561236e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123929190615602565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016123c291906153e5565b602060405180830381865afa1580156123df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612403919061561f565b6040516305c2fbcf60e31b8152600481018a90529091506001600160a01b038a1690632e17de7890602401600060405180830381600087803b15801561244857600080fd5b505af115801561245c573d6000803e3d6000fd5b50506040516370a0823160e01b81526001600160a01b038d1692506370a08231915061248c9030906004016153e5565b602060405180830381865afa1580156124a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124cd919061561f565b935061255c8a82846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161250091906153e5565b602060405180830381865afa15801561251d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612541919061561f565b61254b919061564e565b6001600160a01b0385169190613330565b896001600160a01b031663f682399682846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161259891906153e5565b602060405180830381865afa1580156125b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d9919061561f565b6125e3919061564e565b6040516001600160e01b031960e084901b1681526004810191909152602481018a90526044810189905260648101889052608401600060405180830381600087803b15801561263157600080fd5b505af1158015612645573d6000803e3d6000fd5b505050505050509695505050505050565b6126758363a9059cbb60e01b8484604051602401612202929190615681565b505050565b6000546001600160a01b031633146109015760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c73565b600080808460028111156126ea576126ea615512565b036128185760405163c661065760e01b8152600060048201526001600160a01b0384169063c6610657906024016020604051808303816000875af1158015612736573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061275a9190615602565b60405163c661065760e01b8152600160048201529092506001600160a01b0384169063c6610657906024016020604051808303816000875af11580156127a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127c89190615602565b6001600160a01b038481166000908152600360209081526040808320878516845290915280822080546001600160801b0319908116909155928416825290208054909116600117905590506128e1565b826001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612856573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287a9190615602565b9150826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128de9190615602565b90505b6000604051806060016040528086600281111561290057612900615512565b81526001600160a01b0380871660208084019190915260006040938401819052878316815260028083528482209388168252929091529190912082518154939450849391929091839160ff1990911690600190849081111561296457612964615512565b02179055506020828101518254610100600160a81b0319166101006001600160a01b0392831602178355604093840151600193840180546001600160a01b0319169183169190911790558581166000908152600280845285822092891682529190925292902083518154859492939192849260ff19909216919084908111156129ef576129ef615512565b021790555060208201518154610100600160a81b0319166101006001600160a01b0392831602178255604090920151600190910180546001600160a01b031916919092161790555050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006001600160a01b038516612acc57612aa6836140d8565b92507f000000000000000000000000430000000000000000000000000000000000000494505b6001600160a01b03848116600090815260046020526040812054909182911615612b125750506001600160a01b0380851660009081526004602052604090205416936001905b6001600160a01b038088166000908152600260208181526040808420948b16845293905282822083516060810190945280549293929091839160ff1690811115612b5e57612b5e615512565b6002811115612b6f57612b6f615512565b815281546001600160a01b03610100909104811660208084019190915260019093015481166040909201919091529082015191925016612c4f576040805160028082526060820183526000926020830190803683370190505090508881600081518110612bde57612bde61569a565b60200260200101906001600160a01b031690816001600160a01b0316815250508781600181518110612c1257612c1261569a565b6001600160a01b03928316602091820292909201015289811690891614612c4557612c3e81888861427e565b9450612c49565b8694505b506131b2565b60408101516001600160a01b03161515600082516002811115612c7457612c74615512565b03612d4357612d3c82602001516003600085602001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c6001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a9004600f0b6003600086602001516001600160a01b03166001600160a01b0316815260200190815260200160002060008c6001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a9004600f0b8a8a61449a565b94506131b0565b600182516002811115612d5857612d58615512565b03612f6657600082602001516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612da1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc59190615602565b9050600082612dd5576002612dd8565b60035b60ff166001600160401b03811115612df257612df2615247565b604051908082528060200260200182016040528015612e1b578160200160208202803683370190505b5090508a81600081518110612e3257612e3261569a565b60200260200101906001600160a01b031690816001600160a01b0316815250508215612ee2578a6001600160a01b0316826001600160a01b031614612e775781612ee4565b83602001516001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612eb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612edd9190615602565b612ee4565b895b81600181518110612ef757612ef761569a565b60200260200101906001600160a01b031690816001600160a01b0316815250508215612f52578981600281518110612f3157612f3161569a565b60200260200101906001600160a01b031690816001600160a01b0316815250505b612f5d818a8a61427e565b965050506131b0565b801561313b57600082602001516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fd49190615602565b90506131338a84602001516001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa15801561301c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130409190615831565b8c6001600160a01b0316846001600160a01b03161461305f57836130c5565b85602001516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130c59190615602565b86604001516001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015613107573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312b9190615831565b8d8d8d614527565b9550506131b0565b6131ad8983602001516001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015613181573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131a59190615831565b8a8a8a614747565b94505b505b826131bf57505050613328565b6040516370a0823160e01b81526000906001600160a01b038416906370a08231906131ee9030906004016153e5565b602060405180830381865afa15801561320b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061322f919061561f565b90506132456001600160a01b0389168487613330565b60405163b08d033360e01b81526001600160a01b0384169063b08d033390613276908b908990600090600401615810565b600060405180830381600087803b15801561329057600080fd5b505af11580156132a4573d6000803e3d6000fd5b50506040516370a0823160e01b81528392506001600160a01b03861691506370a08231906132d69030906004016153e5565b602060405180830381865afa1580156132f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613317919061561f565b613321919061564e565b9450505050505b949350505050565b604051636eb1769f60e11b81526000906001600160a01b0385169063dd62ed3e906133619030908790600401615667565b602060405180830381865afa15801561337e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133a2919061561f565b9050611e8b8463095ea7b360e01b856133bb8686615856565b604051602401612202929190615681565b6040516370a0823160e01b81526000906001600160a01b038416906370a08231906133fb9030906004016153e5565b602060405180830381865afa158015613418573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343c919061561f565b905081811115611e8b57611e8b84613454848461564e565b6001600160a01b0386169190612656565b606080600085516001600160401b0381111561348357613483615247565b6040519080825280602002602001820160405280156134ac578160200160208202803683370190505b509050600086516001600160401b038111156134ca576134ca615247565b6040519080825280602002602001820160405280156134f3578160200160208202803683370190505b509050600087878151811061350a5761350a61569a565b6020026020010151600001516001600160a01b03166370a082318b6040518263ffffffff1660e01b815260040161354191906153e5565b602060405180830381865afa15801561355e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613582919061561f565b905060008a6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156135c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135e8919061561f565b1561360b57816135fc600160601b896157b4565b61360691906157cb565b613611565b600160601b5b90508960005b8a518110156136ac576136688d8c8c815181106136365761363661569a565b6020026020010151600001518b8e85815181106136555761365561569a565b6020026020010151600001518787614c78565b88848151811061367a5761367a61569a565b602002602001018885815181106136935761369361569a565b6020908102919091010191909152529150600101613617565b50939b929a509198505050505050505050565b600080866001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016136ee91906153e5565b602060405180830381865afa15801561370b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061372f919061561f565b90506137456001600160a01b0387168887613330565b60405163b08d033360e01b81526001600160a01b0388169063b08d03339061377590899089908990600401615810565b600060405180830381600087803b15801561378f57600080fd5b505af11580156137a3573d6000803e3d6000fd5b50505050600081886001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016137d691906153e5565b602060405180830381865afa1580156137f3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613817919061561f565b613821919061564e565b90506001600160a01b0384163014613847576138476001600160a01b0389168583612656565b979650505050505050565b6000866001600160a01b0316634f4ce61d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613892573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138b69190615602565b9050600086886001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016138e791906153e5565b602060405180830381865afa158015613904573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613928919061561f565b613932919061564e565b90506000826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161396291906153e5565b602060405180830381865afa15801561397f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139a3919061561f565b90506000896001600160a01b03166394cc699e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a099190615602565b9050613a186000858a8a612a8d565b5060007f00000000000000000000000098994a9a7a2570367554589189dc9772241650f66001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a9d9190615602565b6001600160a01b031663e6a439058c876040518363ffffffff1660e01b8152600401613aca929190615667565b602060405180830381865afa158015613ae7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b0b9190615602565b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613b3b91906153e5565b602060405180830381865afa158015613b58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b7c919061561f565b9050613c0b8c85886001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613baf91906153e5565b602060405180830381865afa158015613bcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bf0919061561f565b613bfa919061564e565b6001600160a01b0389169190613330565b8b6001600160a01b031663a9e9c8bc8c86896001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613c4891906153e5565b602060405180830381865afa158015613c65573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c89919061561f565b613c93919061564e565b6040516001600160e01b031960e085901b16815260048101929092526024820152604481018b9052606481018a9052608401600060405180830381600087803b158015613cdf57600080fd5b505af1158015613cf3573d6000803e3d6000fd5b50505050613d288382846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161250091906153e5565b826001600160a01b031663adc9772e8e83856001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613d6591906153e5565b602060405180830381865afa158015613d82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613da6919061561f565b613db0919061564e565b6040518363ffffffff1660e01b8152600401613dcd929190615681565b600060405180830381600087803b158015613de757600080fd5b505af1158015613dfb573d6000803e3d6000fd5b50506040516370a0823160e01b81528792506001600160a01b038f1691506370a0823190613e2d9030906004016153e5565b602060405180830381865afa158015613e4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6e919061561f565b1115613f0157613f018d868e6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613ea591906153e5565b602060405180830381865afa158015613ec2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ee6919061561f565b613ef0919061564e565b6001600160a01b038f169190612656565b6040516370a0823160e01b815284906001600160a01b038816906370a0823190613f2f9030906004016153e5565b602060405180830381865afa158015613f4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f70919061561f565b1115612106576121068d85886001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613fa791906153e5565b602060405180830381865afa158015613fc4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe8919061561f565b613ff2919061564e565b6001600160a01b0389169190612656565b6000614058826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166150909092919063ffffffff16565b90508051600014806140795750808060200190518101906140799190615869565b6126755760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c73565b6000807f00000000000000000000000043000000000000000000000000000000000000046001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161412791906153e5565b602060405180830381865afa158015614144573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614168919061561f565b90507f00000000000000000000000043000000000000000000000000000000000000046001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b1580156141c557600080fd5b505af11580156141d9573d6000803e3d6000fd5b50506040516370a0823160e01b81528493506001600160a01b037f00000000000000000000000043000000000000000000000000000000000000041692506370a08231915061422c9030906004016153e5565b602060405180830381865afa158015614249573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061426d919061561f565b614277919061564e565b9392505050565b60008084516003146142aa578460018151811061429d5761429d61569a565b60200260200101516142c6565b846002815181106142bd576142bd61569a565b60200260200101515b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016142f691906153e5565b602060405180830381865afa158015614313573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614337919061561f565b90506143917f00000000000000000000000098994a9a7a2570367554589189dc9772241650f686886000815181106143715761437161569a565b60200260200101516001600160a01b03166133309092919063ffffffff16565b604051635c11d79560e01b81526001600160a01b037f00000000000000000000000098994a9a7a2570367554589189dc9772241650f61690635c11d795906143e590889088908b90309042906004016158cb565b600060405180830381600087803b1580156143ff57600080fd5b505af1158015614413573d6000803e3d6000fd5b50506040516370a0823160e01b81528392506001600160a01b03851691506370a08231906144459030906004016153e5565b602060405180830381865afa158015614462573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614486919061561f565b614490919061564e565b9695505050505050565b60405163ddc1f59d60e01b8152600f85810b600483015284900b602482015260448101839052606481018290523060848201526000906001600160a01b0387169063ddc1f59d9060a4016020604051808303816000875af1158015614503573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614490919061561f565b600080846001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161455691906153e5565b602060405180830381865afa158015614573573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614597919061561f565b90506145c16001600160a01b038a16732626664c2603336e57b271c5c0b26f421741e48186613330565b6040516bffffffffffffffffffffffff1960608b811b821660208401526001600160e81b031960e88c811b821660348601528b831b841660378601528a901b16604b84015287901b16604e82015260009060620160408051601f1981840301815260a08301825280835230602084015242838301526060830188905260808301879052905163c04b8d5960e01b8152909250732626664c2603336e57b271c5c0b26f421741e4819163c04b8d599161467c9190600401615957565b6020604051808303816000875af115801561469b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146bf919061561f565b506040516370a0823160e01b815282906001600160a01b038816906370a08231906146ee9030906004016153e5565b602060405180830381865afa15801561470b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061472f919061561f565b614739919061564e565b9a9950505050505050505050565b600081600003614a155760007f000000000000000000000000e603f046ee5141a6f3bb8549660417e83062b6886001600160a01b0316634556bd20732626664c2603336e57b271c5c0b26f421741e4816001600160a01b031663c45a01556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156147d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147f89190615602565b6040516001600160e01b031960e084901b1681526001600160a01b039182166004820152818b166024820152908816604482015262ffffff89166064820152608401602060405180830381865afa158015614857573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061487b9190615602565b90506000856001600160a01b0316886001600160a01b03161061489e57856148a0565b875b905060007f000000000000000000000000e603f046ee5141a6f3bb8549660417e83062b6886001600160a01b031663d4bf13347f000000000000000000000000e603f046ee5141a6f3bb8549660417e83062b6886001600160a01b0316637fb4f79d866040518263ffffffff1660e01b815260040161491f91906153e5565b602060405180830381865afa15801561493c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149609190615602565b6040518263ffffffff1660e01b815260040161497c91906153e5565b602060405180830381865afa158015614999573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149bd919061561f565b9050816001600160a01b0316896001600160a01b0316146149f657806149e7600160601b886157b4565b6149f191906157cb565b614a0f565b600160601b614a0587836157b4565b614a0f91906157cb565b94505050505b6040516370a0823160e01b81526000906001600160a01b038616906370a0823190614a449030906004016153e5565b602060405180830381865afa158015614a61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a85919061561f565b9050614aaf6001600160a01b038816732626664c2603336e57b271c5c0b26f421741e48186613330565b732626664c2603336e57b271c5c0b26f421741e4816001600160a01b03166304e45aaf6040518060e001604052808a6001600160a01b03168152602001886001600160a01b031681526020018962ffffff168152602001306001600160a01b031681526020018781526020016103e86001546103e8614b2e919061564e565b614b3890896157b4565b614b4291906157cb565b815260006020918201526040805160e085901b6001600160e01b031916815283516001600160a01b03908116600483015292840151831660248201529083015162ffffff1660448201526060830151821660648201526080830151608482015260a083015160a482015260c0909201511660c482015260e4016020604051808303816000875af1158015614bda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bfe919061561f565b506040516370a0823160e01b815281906001600160a01b038716906370a0823190614c2d9030906004016153e5565b602060405180830381865afa158015614c4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c6e919061561f565b613847919061564e565b6040516370a0823160e01b81526000908190819047906001600160a01b038816906370a0823190614cad9030906004016153e5565b602060405180830381865afa158015614cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614cee919061561f565b925060008a6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614d30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614d54919061561f565b15614de557600160601b87896001600160a01b03166370a082318e6040518263ffffffff1660e01b8152600401614d8b91906153e5565b602060405180830381865afa158015614da8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614dcc919061561f565b614dd691906157b4565b614de091906157cb565b614e56565b60405163e4b5495760e01b81526001600160a01b038c169063e4b5495790614e15908d908d908d906004016157ed565b602060405180830381865afa158015614e32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e56919061561f565b60408051600280825260608201835292935060009290916020830190803683370190505090507f00000000000000000000000098994a9a7a2570367554589189dc9772241650f66001600160a01b031663ad5c46486040518163ffffffff1660e01b8152600401602060405180830381865afa158015614eda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614efe9190615602565b81600081518110614f1157614f1161569a565b60200260200101906001600160a01b031690816001600160a01b0316815250508881600181518110614f4557614f4561569a565b6001600160a01b03928316602091820292909201015260405163fb3bdb4160e01b81527f00000000000000000000000098994a9a7a2570367554589189dc9772241650f69091169063fb3bdb41908990614fa99086908690309042906004016159af565b60006040518083038185885af1158015614fc7573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052614ff091908101906159e4565b50614ffb478461564e565b615005908861564e565b955084896001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161503491906153e5565b602060405180830381865afa158015615051573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615075919061561f565b61507f919061564e565b935050505096509650969350505050565b6060613328848460008585600080866001600160a01b031685876040516150b79190615a69565b60006040518083038185875af1925050503d80600081146150f4576040519150601f19603f3d011682016040523d82523d6000602084013e6150f9565b606091505b5091509150613847878383876060831561517457825160000361516d576001600160a01b0385163b61516d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c73565b5081613328565b61332883838151156151895781518083602001fd5b8060405162461bcd60e51b8152600401610c739190615a85565b6001600160a01b038116811461083a57600080fd5b600080600080600060a086880312156151d057600080fd5b85356151db816151a3565b97602087013597506040870135966060810135965060800135945092505050565b80356003811061520b57600080fd5b919050565b6000806040838503121561522357600080fd5b61522c836151fc565b9150602083013561523c816151a3565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b038111828210171561527f5761527f615247565b60405290565b604051601f8201601f191681016001600160401b03811182821017156152ad576152ad615247565b604052919050565b600080600083850360a08112156152cb57600080fd5b84356152d6816151a3565b935060208501356152e6816151a3565b92506060603f19820112156152fa57600080fd5b50604051606081018181106001600160401b038211171561531d5761531d615247565b806040525061532e604086016151fc565b8152606085013561533e816151a3565b60208201526080850135615351816151a3565b604082015292959194509192509050565b6000806040838503121561537557600080fd5b823561522c816151a3565b600080600080600080600060e0888a03121561539b57600080fd5b87356153a6816151a3565b96506020880135955060408801356153bd816151a3565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b6001600160a01b0391909116815260200190565b60006001600160401b0382111561541257615412615247565b5060051b60200190565b6000602080838503121561542f57600080fd5b82356001600160401b0381111561544557600080fd5b8301601f8101851361545657600080fd5b8035615469615464826153f9565b615285565b81815260059190911b8201830190838101908783111561548857600080fd5b928401925b828410156138475783356154a0816151a3565b8252928401929084019061548d565b6000602082840312156154c157600080fd5b8135614277816151a3565b600080600080608085870312156154e257600080fd5b84356154ed816151a3565b935060208501356154fd816151a3565b93969395505050506040820135916060013590565b634e487b7160e01b600052602160045260246000fd5b606081016003851061554a57634e487b7160e01b600052602160045260246000fd5b9381526001600160a01b039283166020820152911660409091015290565b801515811461083a57600080fd5b600080600080600080600080610100898b03121561559357600080fd5b883561559e816151a3565b97506020890135965060408901359550606089013594506080890135935060a0890135925060c0890135915060e08901356155d881615568565b809150509295985092959890939650565b6000602082840312156155fb57600080fd5b5035919050565b60006020828403121561561457600080fd5b8151614277816151a3565b60006020828403121561563157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561566157615661615638565b92915050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156156c257600080fd5b81516002811061427757600080fd5b600060208083850312156156e457600080fd5b82516001600160401b038111156156fa57600080fd5b8301601f8101851361570b57600080fd5b8051615719615464826153f9565b81815260a0918202830184019184820191908884111561573857600080fd5b938501935b838510156157a85780858a0312156157555760008081fd5b61575d61525d565b8551615768816151a3565b815285870151878201526040808701519082015260608087015161578b816151a3565b90820152608086810151908201528352938401939185019161573d565b50979650505050505050565b808202811582820484141761566157615661615638565b6000826157e857634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b0393841681526020810192909252909116604082015260600190565b6001600160a01b039390931683526020830191909152604082015260600190565b60006020828403121561584357600080fd5b815162ffffff8116811461427757600080fd5b8082018082111561566157615661615638565b60006020828403121561587b57600080fd5b815161427781615568565b60008151808452602080850194506020840160005b838110156158c05781516001600160a01b03168752958201959082019060010161589b565b509495945050505050565b85815284602082015260a0604082015260006158ea60a0830186615886565b6001600160a01b0394909416606083015250608001529392505050565b60005b8381101561592257818101518382015260200161590a565b50506000910152565b60008151808452615943816020860160208601615907565b601f01601f19169290920160200192915050565b602081526000825160a0602084015261597360c084018261592b565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b8481526080602082015260006159c86080830186615886565b6001600160a01b03949094166040830152506060015292915050565b600060208083850312156159f757600080fd5b82516001600160401b03811115615a0d57600080fd5b8301601f81018513615a1e57600080fd5b8051615a2c615464826153f9565b81815260059190911b82018301908381019087831115615a4b57600080fd5b928401925b8284101561384757835182529284019290840190615a50565b60008251615a7b818460208701615907565b9190910192915050565b602081526000614277602083018461592b56fea2646970667358221220d2529528d6b2c45960f2c77150e689440a8c359d9dc06b25ad049a71e7da2ac964736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000098994a9a7a2570367554589189dc9772241650f6000000000000000000000000e603f046ee5141a6f3bb8549660417e83062b688
-----Decoded View---------------
Arg [0] : _v2Router (address): 0x98994a9A7a2570367554589189dC9772241650f6
Arg [1] : _v3TwapUtilities (address): 0xE603F046ee5141a6f3bb8549660417E83062b688
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000098994a9a7a2570367554589189dc9772241650f6
Arg [1] : 000000000000000000000000e603f046ee5141a6f3bb8549660417e83062b688
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.