Source Code
Latest 25 from a total of 24,627 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Swap | 59616163 | 21 days ago | IN | 0 S | 0.01911624 | ||||
| Swap | 59255529 | 26 days ago | IN | 0 S | 0.2248593 | ||||
| Swap | 59255452 | 26 days ago | IN | 0 S | 0.18138188 | ||||
| Swap | 59255405 | 26 days ago | IN | 0 S | 0.05117398 | ||||
| Swap | 59255349 | 26 days ago | IN | 0 S | 0.09444379 | ||||
| Swap | 59255280 | 26 days ago | IN | 0 S | 0.05348787 | ||||
| Swap | 59255190 | 26 days ago | IN | 0 S | 0.07365165 | ||||
| Swap | 59255118 | 26 days ago | IN | 0 S | 0.07284073 | ||||
| Swap | 59224191 | 26 days ago | IN | 0 S | 0.08963042 | ||||
| Swap | 59224175 | 26 days ago | IN | 0 S | 0.04075038 | ||||
| Swap | 59224157 | 26 days ago | IN | 0 S | 0.07769597 | ||||
| Swap | 54026286 | 80 days ago | IN | 10 S | 0.01766077 | ||||
| Swap | 53643241 | 82 days ago | IN | 0 S | 0.121346 | ||||
| Swap | 53642836 | 82 days ago | IN | 0 S | 0.10803531 | ||||
| Swap | 53642302 | 82 days ago | IN | 0 S | 0.07582349 | ||||
| Swap | 53642157 | 82 days ago | IN | 0 S | 0.06199596 | ||||
| Swap | 53640123 | 82 days ago | IN | 0 S | 0.08343346 | ||||
| Swap | 53640026 | 82 days ago | IN | 0 S | 0.06451296 | ||||
| Swap | 53238138 | 84 days ago | IN | 0 S | 0.05693721 | ||||
| Swap | 53175257 | 84 days ago | IN | 0 S | 0.04227288 | ||||
| Swap | 51997969 | 91 days ago | IN | 79 S | 0.04586303 | ||||
| Swap | 51928838 | 91 days ago | IN | 48 S | 0.03034986 | ||||
| Swap | 51913115 | 91 days ago | IN | 82 S | 0.0535875 | ||||
| Swap | 51785476 | 93 days ago | IN | 0 S | 0.05781688 | ||||
| Swap | 51540405 | 95 days ago | IN | 0 S | 0.04002768 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 59616163 | 21 days ago | 2.3032326 S | ||||
| 59616163 | 21 days ago | 2.3032326 S | ||||
| 54026286 | 80 days ago | 10 S | ||||
| 53175257 | 84 days ago | 89.81093867 S | ||||
| 53175257 | 84 days ago | 89.81093867 S | ||||
| 51997969 | 91 days ago | 79 S | ||||
| 51928838 | 91 days ago | 48 S | ||||
| 51913115 | 91 days ago | 82 S | ||||
| 51785476 | 93 days ago | 1,175.7689979 S | ||||
| 51785476 | 93 days ago | 1,175.7689979 S | ||||
| 51229851 | 98 days ago | 59 S | ||||
| 50348944 | 105 days ago | 396 S | ||||
| 50065923 | 107 days ago | 565.79098766 S | ||||
| 50065923 | 107 days ago | 565.79098766 S | ||||
| 50002678 | 107 days ago | 35 S | ||||
| 50002662 | 107 days ago | 16 S | ||||
| 49981249 | 107 days ago | 926.95712923 S | ||||
| 49981249 | 107 days ago | 926.95712923 S | ||||
| 49851194 | 109 days ago | 2.80648501 S | ||||
| 49851194 | 109 days ago | 2.80648501 S | ||||
| 49800560 | 109 days ago | 499 S | ||||
| 49800393 | 109 days ago | 17 S | ||||
| 49800164 | 109 days ago | 13 S | ||||
| 49800117 | 109 days ago | 16.5 S | ||||
| 49776363 | 109 days ago | 3.75653434 S |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ZapIn
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeMath} from "@openzeppelin/contracts/utils/math/SafeMath.sol";
import {IZapIn} from "./interfaces/external/IZapIn.sol";
import {IWETH} from "./interfaces/external/IWETH.sol";
import {ISafeHaven} from "./interfaces/external/ISafeHaven.sol";
import {IShadowV2Router02} from "./interfaces/external/IShadowV2Router02.sol";
import {IShadowV2Factory} from "./interfaces/external/IShadowV2Factory.sol";
import {IUniswapV2Pair} from "./interfaces/external/IUniswapV2Pair.sol";
import {IStaking} from "./interfaces/external/IStaking.sol";
import {Babylonian} from "./libs/Babylonian.sol";
contract ZapIn is Ownable, IZapIn {
using SafeMath for uint;
using SafeERC20 for IERC20;
uint256 constant deadline =
0xf000000000000000000000000000000000000000000000000000000000000000;
IWETH public immutable WETH;
IERC20 public immutable USDC;
IShadowV2Router02 public immutable ROUTER;
IShadowV2Factory public immutable FACTORY;
IUniswapV2Pair public immutable PAIR_TO_USDC; // ss/usdc
IUniswapV2Pair public immutable PAIR_TO_SONIC; // ss/sonic
IStaking public immutable STAKING_USDC;
IStaking public immutable STAKING_SONIC;
ISafeHaven public immutable SAFE_HAVEN_SONIC;
ISafeHaven public immutable SAFE_HAVEN_USDC;
address public immutable TREASURY_SONIC;
address public immutable TREASURY_USDC;
address public TO_TOKEN_ADDRESS;
address public FROM_TOKEN_ADDRESS;
address public FROM_USDC_ADDRESS;
bool public WETH_IS_TOKEN0;
bool public USDC_IS_TOKEN0;
uint public slippage = 900; //mean 900 = 10% slippage
bool public stopped;
PairDetails[] public pairsDetails;
mapping(address => PairDetails) public pairDetails;
mapping(address => bool) public approvedTargets;
modifier stopInEmergency() {
require(!stopped, "Paused");
_;
}
constructor(
address _router,
address _usdc,
address _pairToSonic,
address _pairToUsdc,
address _safeHavenSonic,
address _safeHavenUsdc,
address _treasurySonic,
address _treasuryUsdc,
address _stakingSonic,
address _stakingUsdc
) {
ROUTER = IShadowV2Router02(_router);
WETH = IWETH(ROUTER.WETH());
FACTORY = IShadowV2Factory(ROUTER.factory());
PAIR_TO_SONIC = IUniswapV2Pair(_pairToSonic);
PAIR_TO_USDC = IUniswapV2Pair(_pairToUsdc);
STAKING_SONIC = IStaking(_stakingSonic);
STAKING_USDC = IStaking(_stakingUsdc);
SAFE_HAVEN_SONIC = ISafeHaven(_safeHavenSonic);
SAFE_HAVEN_USDC = ISafeHaven(_safeHavenUsdc);
USDC = IERC20(_usdc);
TREASURY_SONIC = _treasurySonic;
TREASURY_USDC = _treasuryUsdc;
if (PAIR_TO_SONIC.token0() == address(WETH)) {
TO_TOKEN_ADDRESS = PAIR_TO_SONIC.token1();
FROM_TOKEN_ADDRESS = PAIR_TO_SONIC.token0();
WETH_IS_TOKEN0 = true;
} else {
TO_TOKEN_ADDRESS = PAIR_TO_SONIC.token0();
FROM_TOKEN_ADDRESS = PAIR_TO_SONIC.token1();
}
if (PAIR_TO_USDC.token0() == address(USDC)) {
FROM_USDC_ADDRESS = PAIR_TO_USDC.token0();
USDC_IS_TOKEN0 = true;
} else {
FROM_USDC_ADDRESS = PAIR_TO_USDC.token1();
}
approvedTargets[0xc325856e5585823aaC0D1Fd46c35c608D95E65A9] = true; //magpie
approvedTargets[0x6352a56caadC4F1E25CD6c75970Fa768A3304e64] = true; //openocean
}
receive() external payable {}
function swap(
address from,
address to,
uint amount,
bytes calldata data,
address target
) external payable {
uint toInvest = _receivePayment(from, amount);
bool exitInWrapper;
if (to == address(WETH)) {
exitInWrapper = true;
}
if (from == address(0)) {
from = address(WETH);
} else if (to == address(0)) {
to = address(WETH);
}
_swapWithTarget(from, to, toInvest, target, data);
uint balance;
if (to == address(WETH)) {
uint WETHBalance = IERC20(address(WETH)).balanceOf(address(this));
if (exitInWrapper) {
balance = IERC20(address(WETH)).balanceOf(address(this));
if (balance > 0)
IERC20(address(WETH)).safeTransfer(msg.sender, balance);
} else {
if (WETHBalance > 0) {
WETH.withdraw(WETHBalance);
(bool success, ) = msg.sender.call{value: WETHBalance}("");
require(success, "ETH transfer failed");
}
}
}
balance = IERC20(from).balanceOf(address(this));
if (balance > 0) IERC20(from).safeTransfer(msg.sender, balance);
balance = IERC20(to).balanceOf(address(this));
if (balance > 0) IERC20(to).safeTransfer(msg.sender, balance);
}
function singleBond(
uint amount,
address purchaseToken,
address tokenA,
address tokenB,
address swapTargetTokenA,
address swapTargetTokenB,
bytes calldata swapDataTokenA,
bytes calldata swapDataTokenB,
bool isAdditionalSwap
) external payable stopInEmergency returns (uint fragmentsOut) {
IUniswapV2Pair _pair = _getPair(tokenA, tokenB);
address bondTo = pairDetails[address(_pair)].treasury;
_receivePayment(purchaseToken, amount);
if (purchaseToken == address(0)) {
purchaseToken = address(WETH);
}
if (tokenA == address(0)) {
tokenA = address(WETH);
}
if (tokenB == address(0)) {
tokenB = address(WETH);
}
uint amountA = amount / 2;
uint amountB = amount / 2;
if (_pair.token0() != tokenA) {
(tokenA, tokenB) = (tokenB, tokenA);
(amountA, amountB) = (amountB, amountA);
}
if (purchaseToken != tokenA) {
amountA = _swapWithTarget(
purchaseToken,
tokenA,
amountA,
swapTargetTokenA,
swapDataTokenA
);
}
if (purchaseToken != tokenB) {
amountB = _swapWithTarget(
purchaseToken,
tokenB,
amountB,
swapTargetTokenB,
swapDataTokenB
);
}
if (isAdditionalSwap) {
(uint112 reserve0, uint112 reserve1, ) = _pair.getReserves();
(uint remainingTokenA, uint remainingTokenB) = _getRemainingAmounts(
_pair,
amountA,
amountB,
reserve0,
reserve1
);
if (remainingTokenA > remainingTokenB) {
(uint256 amountSpent, uint256 amountBought) = _swapIntermediate(
reserve0,
remainingTokenA,
tokenA,
tokenB
);
amountA -= amountSpent;
amountB += amountBought;
} else if (remainingTokenB > remainingTokenA) {
(uint256 amountSpent, uint256 amountBought) = _swapIntermediate(
reserve1,
remainingTokenB,
tokenB,
tokenA
);
amountA += amountBought;
amountB -= amountSpent;
}
}
IERC20(tokenA).approve(bondTo, amountA);
IERC20(tokenB).approve(bondTo, amountB);
ISafeHaven safeHaven = ISafeHaven(
pairDetails[address(_pair)].safeHaven
);
fragmentsOut = safeHaven.deposit(
msg.sender,
amountA,
amountB,
(amountA * slippage) / 1000,
(amountB * slippage) / 1000,
deadline
);
uint balance = IERC20(tokenA).balanceOf(address(this));
if (balance > 0) IERC20(tokenA).safeTransfer(msg.sender, balance);
balance = IERC20(tokenB).balanceOf(address(this));
if (balance > 0) IERC20(tokenB).safeTransfer(msg.sender, balance);
}
function duoBond(
address tokenA,
address tokenB,
uint amountA,
uint amountB
) external payable stopInEmergency returns (uint fragmentsOut) {
IUniswapV2Pair _pair = _getPair(tokenA, tokenB);
address bondTo = pairDetails[address(_pair)].treasury;
_receivePayment(tokenA, amountA);
_receivePayment(tokenB, amountB);
if (tokenA == address(0)) {
tokenA = address(WETH);
}
if (tokenB == address(0)) {
tokenB = address(WETH);
}
if (_pair.token0() != tokenA) {
(tokenA, tokenB) = (tokenB, tokenA);
(amountA, amountB) = (amountB, amountA);
}
IERC20(tokenA).approve(bondTo, amountA);
IERC20(tokenB).approve(bondTo, amountB);
ISafeHaven safeHaven = ISafeHaven(
pairDetails[address(_pair)].safeHaven
);
fragmentsOut = safeHaven.deposit(
msg.sender,
amountA,
amountB,
(amountA * slippage) / 1000,
(amountB * slippage) / 1000,
deadline
);
uint balance = IERC20(tokenA).balanceOf(address(this));
if (balance > 0) IERC20(tokenA).safeTransfer(msg.sender, balance);
balance = IERC20(tokenB).balanceOf(address(this));
if (balance > 0) IERC20(tokenB).safeTransfer(msg.sender, balance);
}
function singleAddStake(
address _fromTokenContractAddress,
uint256 _amount,
uint256 _amountAmin,
uint256 _amountBmin,
address _swapTarget,
bytes calldata swapData,
bool isStablePool
) external payable stopInEmergency returns (uint) {
IUniswapV2Pair _pair = isStablePool ? PAIR_TO_USDC : PAIR_TO_SONIC;
address tokenA = isStablePool ? address(USDC) : address(WETH);
address tokenB = TO_TOKEN_ADDRESS;
bool tokenAIsToken0 = isStablePool ? USDC_IS_TOKEN0 : WETH_IS_TOKEN0;
uint toInvest = _receivePayment(_fromTokenContractAddress, _amount);
if (_fromTokenContractAddress == address(0)) {
_fromTokenContractAddress = address(WETH);
}
if (_fromTokenContractAddress != tokenA) {
toInvest = _swapWithTarget(
_fromTokenContractAddress,
tokenA,
toInvest,
_swapTarget,
swapData
);
}
(
uint256 token0Bought,
uint256 token1Bought
) = _swapIntermediateForStake(toInvest, _pair, tokenAIsToken0, tokenA);
require(
token0Bought >= _amountAmin && token1Bought >= _amountBmin,
"EST3"
);
IERC20(tokenA).approve(
address(ROUTER),
tokenAIsToken0 ? token0Bought : token1Bought
);
IERC20(tokenB).approve(
address(ROUTER),
tokenAIsToken0 ? token1Bought : token0Bought
);
ROUTER.addLiquidity(
tokenA,
tokenB,
false, // stable=false for Uniswap-style pools
tokenAIsToken0 ? token0Bought : token1Bought,
tokenAIsToken0 ? token1Bought : token0Bought,
((tokenAIsToken0 ? token0Bought : token1Bought) * slippage) / 1000,
((tokenAIsToken0 ? token1Bought : token0Bought) * slippage) / 1000,
address(this),
block.timestamp
);
IStaking stakeTo = isStablePool ? STAKING_USDC : STAKING_SONIC;
uint liquidityAdded = _pair.balanceOf(address(this));
_pair.approve(address(stakeTo), liquidityAdded);
stakeTo.deposit(0, liquidityAdded, msg.sender);
uint balance = IERC20(address(tokenA)).balanceOf(address(this));
if (balance > 0)
IERC20(address(tokenA)).safeTransfer(msg.sender, balance);
balance = IERC20(address(tokenB)).balanceOf(address(this));
if (balance > 0)
IERC20(address(tokenB)).safeTransfer(msg.sender, balance);
return liquidityAdded;
}
function duoAddStake(
address tokenA,
address tokenB,
uint amountA,
uint amountB,
uint minAmountA,
uint minAmountB,
bool isStablePool
) external payable stopInEmergency {
IUniswapV2Pair _pair = isStablePool ? PAIR_TO_USDC : PAIR_TO_SONIC;
IStaking stakeTo = isStablePool ? STAKING_USDC : STAKING_SONIC;
uint toInvestA = _receivePayment(tokenA, amountA);
uint toInvestB = _receivePayment(tokenB, amountB);
if (tokenA == address(0)) {
tokenA = address(WETH);
}
if (tokenB == address(0)) {
tokenB = address(WETH);
}
IERC20(tokenA).approve(address(ROUTER), amountA);
IERC20(tokenB).approve(address(ROUTER), amountB);
ROUTER.addLiquidity(
tokenA,
tokenB,
false,
toInvestA,
toInvestB,
minAmountA,
minAmountB,
address(this),
block.timestamp
);
_pair.approve(address(stakeTo), _pair.balanceOf(address(this)));
stakeTo.deposit(0, _pair.balanceOf(address(this)), msg.sender);
uint balance = IERC20(tokenA).balanceOf(address(this));
if (balance > 0) IERC20(tokenA).safeTransfer(msg.sender, balance);
balance = IERC20(tokenB).balanceOf(address(this));
if (balance > 0) IERC20(tokenB).safeTransfer(msg.sender, balance);
}
function setApprovedTargets(
address[] calldata targets,
bool[] calldata isApproved
) external onlyOwner {
_setApprovedTargets(targets, isApproved);
}
function setPairDetails(
address[] calldata pairs,
PairDetails[] calldata _pairDetails
) external onlyOwner {
_setPairDetails(pairs, _pairDetails);
}
function removePairDetails(address _pair) external onlyOwner {
_removePairDetails(_pair);
}
// - to Pause the contract
function toggleContractActive() public onlyOwner {
stopped = !stopped;
}
function changeSlippage(uint _newSlippage) external onlyOwner {
slippage = _newSlippage;
}
function withdrawTokens(address _token) external onlyOwner returns (bool) {
IERC20(_token).safeTransfer(
owner(),
IERC20(_token).balanceOf(address(this))
);
return true;
}
function withdraWETH() external onlyOwner {
if (address(this).balance > 0) {
(bool success, ) = owner().call{value: address(this).balance}(
new bytes(0)
);
require(success, "STE");
}
}
function quoteSingleBond(
uint amountTokenA,
uint amountTokenB,
address tokenA,
address tokenB,
bool isAdditionalSwap
)
external
view
returns (
uint liquidity,
uint updatedAmountTokenA,
uint updatedAmountTokenB
)
{
IUniswapV2Pair _pair = _getPair(tokenA, tokenB);
if (_pair.token0() != tokenA) {
(amountTokenA, amountTokenB) = (amountTokenB, amountTokenA);
(tokenA, tokenB) = (tokenB, tokenA);
}
(uint reserve0, uint reserve1, ) = _pair.getReserves();
uint totalSupply = _pair.totalSupply();
uint liquidityFromTokenA = (amountTokenA * totalSupply) / reserve0;
uint liquidityFromTokenB = (amountTokenB * totalSupply) / reserve1;
liquidity = Math.min(liquidityFromTokenA, liquidityFromTokenB);
updatedAmountTokenA = (liquidity * reserve0) / totalSupply;
updatedAmountTokenB = (liquidity * reserve1) / totalSupply;
if (isAdditionalSwap) {
uint remainingTokenA = amountTokenA - updatedAmountTokenA;
uint remainingTokenB = amountTokenB - updatedAmountTokenB;
if (remainingTokenA > remainingTokenB) {
// ZapIn token0 → token1
(
uint extraLiquidity,
uint extraTokenA,
uint extraTokenB
) = _computeExtraLiquidity(
_pair.token0(),
remainingTokenA,
reserve0,
reserve1,
reserve0,
_pair,
true
);
liquidity += extraLiquidity;
updatedAmountTokenA += extraTokenA;
updatedAmountTokenB += extraTokenB;
} else if (remainingTokenB > remainingTokenA) {
// ZapIn tokenB → tokenA
(
uint extraLiquidity,
uint extraTokenA,
uint extraTokenB
) = _computeExtraLiquidity(
_pair.token1(),
remainingTokenB,
reserve0,
reserve1,
reserve1,
_pair,
false
);
liquidity += extraLiquidity;
updatedAmountTokenA += extraTokenA;
updatedAmountTokenB += extraTokenB;
}
}
}
function quoteSingleStake(
address tokenIn,
uint amountIn,
bool isNativePair
)
public
view
returns (
uint liquidity,
uint amountToken0, //token0 always amount weth || usdc
uint amountToken1
)
{
IUniswapV2Pair _pair = isNativePair ? PAIR_TO_SONIC : PAIR_TO_USDC;
(uint reserve0, uint reserve1, ) = _pair.getReserves();
address token0 = _pair.token0();
address token1 = _pair.token1();
bool isToken0In = tokenIn == token0;
require(isToken0In || tokenIn == token1, "invalid token");
// address tokenOut = isToken0In ? token1 : token0;
uint reserveIn = isToken0In ? reserve0 : reserve1;
(liquidity, amountToken0, amountToken1) = _computeExtraLiquidity(
tokenIn,
amountIn,
reserve0,
reserve1,
reserveIn,
_pair,
isToken0In
);
}
function quoteDuoStaking(
address tokenIn,
uint amountIn,
bool isNativePair
) external view returns (uint, uint) {
IUniswapV2Pair _pair = isNativePair ? PAIR_TO_SONIC : PAIR_TO_USDC;
(uint112 reserve0, uint112 reserve1, ) = _pair.getReserves();
require(
tokenIn == _pair.token0() || tokenIn == _pair.token1(),
"Invalid tokenIn"
);
bool isToken0In = tokenIn == _pair.token0();
address tokenOut = isToken0In ? _pair.token1() : _pair.token0();
uint reserveIn = isToken0In ? reserve0 : reserve1;
uint reserveOut = isToken0In ? reserve1 : reserve0;
uint scaledAmountIn = amountIn *
(10 ** (18 - IERC20Metadata(tokenIn).decimals()));
uint scaledReserveIn = reserveIn *
(10 ** (18 - IERC20Metadata(tokenIn).decimals()));
uint scaledReserveOut = reserveOut *
(10 ** (18 - IERC20Metadata(tokenOut).decimals()));
return
_getFinalQuote(
scaledAmountIn,
scaledReserveOut,
scaledReserveIn,
tokenOut,
_pair,
reserve0,
reserve1
);
}
function quoteDuoBond(
address tokenIn,
address tokenOut,
uint amountIn
) external view returns (uint, uint) {
IUniswapV2Pair _pair = _getPair(tokenIn, tokenOut);
(uint112 reserve0, uint112 reserve1, ) = _pair.getReserves();
require(
tokenIn == _pair.token0() || tokenIn == _pair.token1(),
"Invalid tokenIn"
);
bool isToken0In = tokenIn == _pair.token0();
uint reserveIn = isToken0In ? reserve0 : reserve1;
uint reserveOut = isToken0In ? reserve1 : reserve0;
uint scaledAmountIn = amountIn *
(10 ** (18 - IERC20Metadata(tokenIn).decimals()));
uint scaledReserveIn = reserveIn *
(10 ** (18 - IERC20Metadata(tokenIn).decimals()));
uint scaledReserveOut = reserveOut *
(10 ** (18 - IERC20Metadata(tokenOut).decimals()));
return
_getFinalQuote(
scaledAmountIn,
scaledReserveOut,
scaledReserveIn,
tokenOut,
_pair,
reserve0,
reserve1
);
}
function getLiquidityAmountsOut(
address tokenA,
address tokenB,
uint256 liquidity
) external view returns (uint256 amountA, uint256 amountB) {
IUniswapV2Pair _pair = _getPair(tokenA, tokenB);
uint256 totalSupply = _pair.totalSupply();
(uint112 reserve0, uint112 reserve1, ) = _pair.getReserves();
require(totalSupply > 0, "No liquidity");
amountA = (liquidity * reserve0) / totalSupply;
amountB = (liquidity * reserve1) / totalSupply;
}
function getAllPairsDetails() external view returns (PairDetails[] memory) {
return pairsDetails;
}
function _swapIntermediate(
uint112 reserveIn,
uint256 amountIn,
address tokenIn,
address tokenOut
) private returns (uint256 amountSpent, uint256 amountBought) {
amountSpent = _calculateSwapInAmount(reserveIn, amountIn);
if (amountSpent != 0) {
amountBought = _swapV2(amountSpent, tokenIn, tokenOut);
}
}
function _swapIntermediateForStake(
uint256 _amount,
IUniswapV2Pair _pair,
bool _isWethOrUsdcToken0,
address _fromToken
) internal returns (uint256 token0Bought, uint256 token1Bought) {
(uint256 res0, uint256 res1, ) = _pair.getReserves();
if (_isWethOrUsdcToken0) {
uint256 amountToSwap = _calculateSwapInAmount(res0, _amount);
//if no reserve or a new pair is created
if (amountToSwap <= 0) amountToSwap = _amount / 2;
token1Bought = _swapV2(amountToSwap, _fromToken, _pair.token1());
token0Bought = token1Bought != 0 ? _amount - amountToSwap : 0;
} else {
uint256 amountToSwap = _calculateSwapInAmount(res1, _amount);
//if no reserve or a new pair is created
if (amountToSwap <= 0) amountToSwap = _amount / 2;
token0Bought = _swapV2(amountToSwap, _fromToken, _pair.token0());
token1Bought = token0Bought != 0 ? _amount - amountToSwap : 0;
}
}
function _swapV2(
uint256 _amountToTrade,
address _tokenFrom,
address _tokenTo
) private returns (uint256) {
IShadowV2Router02.route[] memory route = new IShadowV2Router02.route[](
1
);
route[0].from = _tokenFrom;
route[0].to = _tokenTo;
route[0].stable = false;
IERC20(_tokenFrom).approve(address(ROUTER), type(uint256).max);
uint amountOut;
try
ROUTER.swapExactTokensForTokens(
_amountToTrade,
1,
route,
address(this),
deadline
)
returns (uint[] memory amountsOut) {
amountOut = amountsOut[1];
} catch {
amountOut = 0;
}
return amountOut;
}
function _swapWithTarget(
address _fromTokenAddress,
address _toTokenAddress,
uint256 _amount,
address _swapTarget,
bytes calldata swapData
) internal returns (uint256 amountBought) {
IERC20(_fromTokenAddress).approve(_swapTarget, _amount);
IERC20 token = IERC20(_toTokenAddress);
uint256 initialBalance = token.balanceOf(address(this));
require(approvedTargets[_swapTarget], "Target not Authorized");
(bool success, ) = _swapTarget.call(swapData);
require(success, "Error Swapping Tokens 1");
IERC20(_fromTokenAddress).approve(_swapTarget, 0);
amountBought = token.balanceOf(address(this)) - initialBalance;
require(amountBought > 0, "Error Swapping Tokens 2");
}
function _receivePayment(
address token,
uint256 amount
) internal returns (uint256) {
if (token == address(0)) {
require(msg.value > 0, "No eth sent");
WETH.deposit{value: msg.value}();
return msg.value;
}
require(amount > 0, "Invalid token amount");
//transfer token
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
return amount;
}
function _setApprovedTargets(
address[] calldata targets,
bool[] calldata isApproved
) private {
uint256 length = targets.length;
require(length == isApproved.length, "Invalid Input length");
for (uint256 i = 0; i < length; ) {
approvedTargets[targets[i]] = isApproved[i];
unchecked {
i++;
}
}
}
function _setPairDetails(
address[] memory pairs,
PairDetails[] memory _pairDetails
) private {
uint256 length = pairs.length;
require(length == _pairDetails.length, "Invalid Input length");
for (uint256 i = 0; i < length; ) {
pairDetails[pairs[i]] = _pairDetails[i];
pairsDetails.push(_pairDetails[i]);
unchecked {
i++;
}
}
}
function _removePairDetails(address _pair) private {
uint256 length = pairsDetails.length;
for (uint256 i = 0; i < length; ) {
if (pairsDetails[i].pair == _pair) {
pairsDetails[i] = pairsDetails[length - 1];
pairsDetails.pop();
}
unchecked {
i++;
}
}
delete pairDetails[_pair];
}
function _calculateSwapInAmount(
uint256 reserveIn,
uint256 userIn
) private pure returns (uint256) {
return
(Babylonian.sqrt(
reserveIn * ((userIn * 3988000) + (reserveIn * 3988009))
) - (reserveIn * 1997)) / 1994;
}
function _getFinalQuote(
uint _scaledAmountIn,
uint _scaledReserveOut,
uint _scaledReserveIn,
address _tokenOut,
IUniswapV2Pair _pair,
uint reserve0,
uint reserve1
) internal view returns (uint, uint) {
uint amountOut = (_scaledAmountIn * _scaledReserveOut) /
_scaledReserveIn;
amountOut =
amountOut /
(10 ** (18 - IERC20Metadata(_tokenOut).decimals()));
uint totalSupply = _applyFeeLogic(
_pair,
reserve0,
reserve1,
_pair.totalSupply()
);
uint scaledLiquidity = Math.min(
(_scaledAmountIn * totalSupply) / _scaledReserveIn,
(amountOut *
(10 ** (18 - IERC20Metadata(_tokenOut).decimals())) *
totalSupply) / _scaledReserveOut
);
return (amountOut, scaledLiquidity);
}
function _getRemainingAmounts(
IUniswapV2Pair _pair,
uint token0Bought,
uint token1Bought,
uint112 reserve0,
uint112 reserve1
) private view returns (uint remainingToken0, uint remainingToken1) {
uint totalSupply = _pair.totalSupply();
uint liquidityFromToken0 = (token0Bought * totalSupply) / reserve0;
uint liquidityFromToken1 = (token1Bought * totalSupply) / reserve1;
uint liquidity = Math.min(liquidityFromToken0, liquidityFromToken1);
uint usedToken0 = (liquidity * reserve0) / totalSupply;
uint usedToken1 = (liquidity * reserve1) / totalSupply;
remainingToken0 = token0Bought - usedToken0;
remainingToken1 = token1Bought - usedToken1;
}
function _computeExtraLiquidity(
address tokenIn,
uint amountIn,
uint reserve0,
uint reserve1,
uint reserveIn,
IUniswapV2Pair _pair,
bool isToken0In
)
private
view
returns (uint liquidity, uint amountToken0, uint amountToken1)
{
uint amountSwap = _calculateSwapInAmount(reserveIn, amountIn);
uint amountOut = _pair.getAmountOut(amountSwap, tokenIn);
uint amountAdded = amountIn - amountSwap;
amountToken0 = isToken0In ? amountAdded : amountOut;
amountToken1 = isToken0In ? amountOut : amountAdded;
liquidity = Math.min(
(amountToken0 * _pair.totalSupply()) / reserve0,
(amountToken1 * _pair.totalSupply()) / reserve1
);
}
function _applyFeeLogic(
IUniswapV2Pair _pair,
uint reserve0,
uint reserve1,
uint totalSupply
) private view returns (uint updatedTotalSupply) {
updatedTotalSupply = totalSupply;
uint kLast = _pair.kLast();
if (kLast != 0) {
uint rootK = Math.sqrt(uint(reserve0) * uint(reserve1));
uint rootKLast = Math.sqrt(kLast);
if (rootK > rootKLast) {
uint diffK = rootK - rootKLast;
uint feeSplit = 10000; // 100% protocol fee
uint dueToProtocol = (diffK * feeSplit) / 10000;
uint dueToLp = rootKLast + diffK - dueToProtocol;
uint feeLiquidity = (updatedTotalSupply * dueToProtocol) /
dueToLp;
if (feeLiquidity > 0) {
updatedTotalSupply += feeLiquidity;
}
}
}
}
function _getPair(
address tokenA,
address tokenB
) internal view returns (IUniswapV2Pair _pair) {
if (tokenA == address(0)) {
tokenA = address(WETH);
}
if (tokenB == address(0)) {
tokenB = address(WETH);
}
_pair = IUniswapV2Pair(FACTORY.getPair(tokenA, tokenB, false));
address pair = pairDetails[address(_pair)].pair;
require(pair != address(0), "Invalid Pair");
}
}// 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 v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (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.
*/
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].
*/
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 v4.4.1 (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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}//SPDX-License-Identifier: UNLICENSE
pragma solidity >=0.5.0;
interface ISafeHaven {
function processExpiredBonds() external;
function deposit(
address _to,
uint amountDesiredA,
uint amountDesiredB,
uint amountAMin,
uint amountBMin,
uint deadline
) external returns(uint);
}//SPDX-License-Identifier: UNLICENSE
pragma solidity >=0.5.0;
interface IShadowV2Factory {
event PairCreated(
address indexed token0,
address indexed token1,
address pair,
uint
);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function migrator() external view returns (address);
function getPair(
address tokenA,
address tokenB,
bool stable
) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(
address tokenA,
address tokenB,
bool stable
) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
function setMigrator(address) external;
}//SPDX-License-Identifier: UNLICENSE
pragma solidity >=0.5.0;
interface IShadowV2Router01 {
struct route {
address from;
address to;
bool stable;
}
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
bool stable,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
bool stable,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
)
external
payable
returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
bool stable,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
bool stable,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
route[] calldata routes,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
route[] calldata routes,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(
uint amountOutMin,
route[] calldata routes,
address to,
uint deadline
) external payable returns (uint[] memory amounts);
function swapTokensForExactETH(
uint amountOut,
uint amountInMax,
route[] calldata routes,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactTokensForETH(
uint amountIn,
uint amountOutMin,
route[] calldata routes,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapETHForExactTokens(
uint amountOut,
route[] calldata routes,
address to,
uint deadline
) external payable returns (uint[] memory amounts);
function quote(
uint amountA,
uint reserveA,
uint reserveB
) external pure returns (uint amountB);
// function getAmountOut(
// uint amountIn,
// uint reserveIn,
// uint reserveOut
// ) external pure returns (uint amountOut);
function getAmountOut(
uint256 amountIn,
address tokenIn,
address tokenOut
) external view returns (uint256 amount, bool stable);
function getAmountIn(
uint amountOut,
uint reserveIn,
uint reserveOut
) external pure returns (uint amountIn);
function getAmountsOut(
uint amountIn,
route[] calldata routes
) external view returns (uint[] memory amounts);
function getAmountsIn(
uint amountOut,
route[] calldata routes
) external view returns (uint[] memory amounts);
}
interface IShadowV2Router02 is IShadowV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
route[] calldata routes,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
route[] calldata routes,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
route[] calldata routes,
address to,
uint deadline
) external;
}//SPDX-License-Identifier: UNLICENSE
pragma solidity >=0.5.0;
interface IStaking {
function updateRewardPerInterval(uint256 _rewardPerInterval) external;
function deposit(uint256 _pid, uint256 _amount, address _account) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapV2Pair {
struct Observation {
uint256 timestamp;
uint256 reserve0Cumulative;
uint256 reserve1Cumulative;
}
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function fee() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(
address owner,
address spender
) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(
address from,
address to,
uint value
) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(
address owner,
address spender,
uint value,
uint deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(
address indexed sender,
uint amount0,
uint amount1,
address indexed to
);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(
uint amount0Out,
uint amount1Out,
address to,
bytes calldata data
) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
function currentCumulativePrices()
external
view
returns (
uint256 reserve0Cumulative,
uint256 reserve1Cumulative,
uint256 blockTimestamp
);
function lastObservation() external view returns (Observation memory);
/// SHADOW V2 ONLY
function getAmountOut(
uint amountIn,
address tokenIn
) external view returns (uint amountOut);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IWETH {
function balanceOf(address) external view returns (uint);
function deposit() external payable;
function withdraw(uint256 _amount) external;
function approve(address to, uint256 _amount) external;
}//SPDX-License-Identifier: UNLICENSE
pragma solidity >=0.5.0;
interface IZapIn {
struct SingleAddStakeParams {
address purchaseToken;
address tokenA;
address tokenB;
uint256 amount; // amount of token from we want to get into LP
uint256 amountAmin;
uint256 amountBmin;
address swapTargetTokenA;
address swapTargetTokenB;
bytes swapDataTokenA;
bytes swapDataTokenB;
}
struct PairDetails {
address safeHaven;
address treasury;
address pair;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
library Babylonian {
function sqrt(uint256 x) internal pure returns (uint256) {
if (x == 0) return 0;
uint256 xx = x;
uint256 r = 1;
if (xx >= 0x100000000000000000000000000000000) {
xx >>= 128;
r <<= 64;
}
if (xx >= 0x10000000000000000) {
xx >>= 64;
r <<= 32;
}
if (xx >= 0x100000000) {
xx >>= 32;
r <<= 16;
}
if (xx >= 0x10000) {
xx >>= 16;
r <<= 8;
}
if (xx >= 0x100) {
xx >>= 8;
r <<= 4;
}
if (xx >= 0x10) {
xx >>= 4;
r <<= 2;
}
if (xx >= 0x8) {
r <<= 1;
}
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
uint256 r1 = x / r;
return (r < r1 ? r : r1);
}
}{
"optimizer": {
"enabled": true,
"runs": 100
},
"viaIR": true,
"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":"_router","type":"address"},{"internalType":"address","name":"_usdc","type":"address"},{"internalType":"address","name":"_pairToSonic","type":"address"},{"internalType":"address","name":"_pairToUsdc","type":"address"},{"internalType":"address","name":"_safeHavenSonic","type":"address"},{"internalType":"address","name":"_safeHavenUsdc","type":"address"},{"internalType":"address","name":"_treasurySonic","type":"address"},{"internalType":"address","name":"_treasuryUsdc","type":"address"},{"internalType":"address","name":"_stakingSonic","type":"address"},{"internalType":"address","name":"_stakingUsdc","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":[],"name":"FACTORY","outputs":[{"internalType":"contract IShadowV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FROM_TOKEN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FROM_USDC_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAIR_TO_SONIC","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAIR_TO_USDC","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROUTER","outputs":[{"internalType":"contract IShadowV2Router02","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SAFE_HAVEN_SONIC","outputs":[{"internalType":"contract ISafeHaven","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SAFE_HAVEN_USDC","outputs":[{"internalType":"contract ISafeHaven","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_SONIC","outputs":[{"internalType":"contract IStaking","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_USDC","outputs":[{"internalType":"contract IStaking","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TO_TOKEN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TREASURY_SONIC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TREASURY_USDC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC_IS_TOKEN0","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH_IS_TOKEN0","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedTargets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newSlippage","type":"uint256"}],"name":"changeSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"minAmountA","type":"uint256"},{"internalType":"uint256","name":"minAmountB","type":"uint256"},{"internalType":"bool","name":"isStablePool","type":"bool"}],"name":"duoAddStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"name":"duoBond","outputs":[{"internalType":"uint256","name":"fragmentsOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAllPairsDetails","outputs":[{"components":[{"internalType":"address","name":"safeHaven","type":"address"},{"internalType":"address","name":"treasury","type":"address"},{"internalType":"address","name":"pair","type":"address"}],"internalType":"struct IZapIn.PairDetails[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"getLiquidityAmountsOut","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"pairDetails","outputs":[{"internalType":"address","name":"safeHaven","type":"address"},{"internalType":"address","name":"treasury","type":"address"},{"internalType":"address","name":"pair","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pairsDetails","outputs":[{"internalType":"address","name":"safeHaven","type":"address"},{"internalType":"address","name":"treasury","type":"address"},{"internalType":"address","name":"pair","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"quoteDuoBond","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bool","name":"isNativePair","type":"bool"}],"name":"quoteDuoStaking","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountTokenA","type":"uint256"},{"internalType":"uint256","name":"amountTokenB","type":"uint256"},{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"isAdditionalSwap","type":"bool"}],"name":"quoteSingleBond","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"updatedAmountTokenA","type":"uint256"},{"internalType":"uint256","name":"updatedAmountTokenB","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"bool","name":"isNativePair","type":"bool"}],"name":"quoteSingleStake","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountToken0","type":"uint256"},{"internalType":"uint256","name":"amountToken1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pair","type":"address"}],"name":"removePairDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bool[]","name":"isApproved","type":"bool[]"}],"name":"setApprovedTargets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"pairs","type":"address[]"},{"components":[{"internalType":"address","name":"safeHaven","type":"address"},{"internalType":"address","name":"treasury","type":"address"},{"internalType":"address","name":"pair","type":"address"}],"internalType":"struct IZapIn.PairDetails[]","name":"_pairDetails","type":"tuple[]"}],"name":"setPairDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_fromTokenContractAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_amountAmin","type":"uint256"},{"internalType":"uint256","name":"_amountBmin","type":"uint256"},{"internalType":"address","name":"_swapTarget","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"},{"internalType":"bool","name":"isStablePool","type":"bool"}],"name":"singleAddStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"purchaseToken","type":"address"},{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"address","name":"swapTargetTokenA","type":"address"},{"internalType":"address","name":"swapTargetTokenB","type":"address"},{"internalType":"bytes","name":"swapDataTokenA","type":"bytes"},{"internalType":"bytes","name":"swapDataTokenB","type":"bytes"},{"internalType":"bool","name":"isAdditionalSwap","type":"bool"}],"name":"singleBond","outputs":[{"internalType":"uint256","name":"fragmentsOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"slippage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"target","type":"address"}],"name":"swap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"toggleContractActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraWETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"withdrawTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
61020080604052346200059457610140816200586080380380916200002582856200091d565b83398101031262000594576200003b8162000955565b906200004a6020820162000955565b90620000596040820162000955565b92620000686060830162000955565b92620000776080840162000955565b6200008560a0850162000955565b906200009460c0860162000955565b93620000a360e0870162000955565b95620000c2610120620000ba610100840162000955565b920162000955565b5f8054336001600160a01b03198216811783556040519395602093859360049385939290916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a361038483556001600160a01b031660c08190526315ab88c960e31b82525afa908115620005a1575f91620008db575b506001600160a01b0390811660805260c05160405163c45a015560e01b81529160209183916004918391165afa908115620005a1575f9162000882575b506001600160a01b0390811660e0529889166101208190529789166101005288166101605287166101405286166101805285166101a05290931660a0526101c0929092526101e091909152604051630dfe168160e01b815290602090829060049082905afa908115620005a1575f9162000840575b506080516001600160a01b0391821691160362000712576101205160405163d21220a760e01b815290602090829060049082906001600160a01b03165afa908115620005a1575f91620006d0575b50600180546001600160a01b0319166001600160a01b0392831617905561012051604051630dfe168160e01b81529160209183916004918391165afa908115620005a1575f916200068e575b50600280546001600160a01b0319166001600160a01b03929092169190911790556003805460ff60a01b1916600160a01b1790555b61010051604051630dfe168160e01b815290602090829060049082906001600160a01b03165afa908115620005a1575f916200064c575b5060a0516001600160a01b03918216911603620005ac5761010051604051630dfe168160e01b815290602090829060049082906001600160a01b03165afa908115620005a1575f916200055b575b5060038054600161ff0160a01b0319166001600160a01b0390921691909117600160a81b1790555b60086020527fcdc0045d0c85c04319db18131b80cbf7a91d1c2c18bd319ce33b2d123b3651d78054600160ff199182168117909255736352a56caadc4f1e25cd6c75970fa768a3304e645f527fda9f66dcbe51b40ee750bda58e559ea672af32b3b690011eff2ef2822fa74ffb80549091169091179055604051614ef590816200096b8239608051818181610972015281816112c9015281816112fa0152818161132b015281816113740152818161201801528181612057015281816134620152818161348c01528181613979015281816139aa0152818161471001528181614d3a0152614d61015260a05181818161181d015261193e015260c051818181611a9001528181611b0101528181611baa01528181612bf201528181613593015281816135f90152818161367b01526141e6015260e051818181612c370152614c9701526101005181818161166f015281816119150152818161280a01528181612fc001526134f601526101205181818161141a015281816116a90152818161208701528181612ca90152613a0201526101405181818161064201528181611be7015261351e015261016051818181611e2901528181612bad01526139db015261018051816108dd01526101a0518161053d01526101c0518161186201526101e051816127c50152f35b90506020813d60201162000598575b8162000579602093836200091d565b8101031262000594576200058d9062000955565b5f6200034a565b5f80fd5b3d91506200056a565b6040513d5f823e3d90fd5b6101005160405163d21220a760e01b815290602090829060049082906001600160a01b03165afa908115620005a1575f916200060a575b50600380546001600160a01b0319166001600160a01b039290921691909117905562000372565b90506020813d60201162000643575b8162000628602093836200091d565b8101031262000594576200063c9062000955565b5f620005e3565b3d915062000619565b90506020813d60201162000685575b816200066a602093836200091d565b8101031262000594576200067e9062000955565b5f620002fc565b3d91506200065b565b90506020813d602011620006c7575b81620006ac602093836200091d565b810103126200059457620006c09062000955565b5f62000290565b3d91506200069d565b90506020813d60201162000709575b81620006ee602093836200091d565b810103126200059457620007029062000955565b5f62000244565b3d9150620006df565b61012051604051630dfe168160e01b815290602090829060049082906001600160a01b03165afa908115620005a1575f91620007fe575b50600180546001600160a01b0319166001600160a01b039283161790556101205160405163d21220a760e01b81529160209183916004918391165afa908115620005a1575f91620007bc575b50600280546001600160a01b0319166001600160a01b0392909216919091179055620002c5565b90506020813d602011620007f5575b81620007da602093836200091d565b810103126200059457620007ee9062000955565b5f62000795565b3d9150620007cb565b90506020813d60201162000837575b816200081c602093836200091d565b810103126200059457620008309062000955565b5f62000749565b3d91506200080d565b90506020813d60201162000879575b816200085e602093836200091d565b810103126200059457620008729062000955565b5f620001f6565b3d91506200084f565b989796959493929190506020893d602011620008d2575b81620008a8602093836200091d565b810103126200059457600499620008c160209a62000955565b919293949596979899509962000181565b3d915062000899565b90506020813d60201162000914575b81620008f9602093836200091d565b8101031262000594576200090d9062000955565b5f62000144565b3d9150620008ea565b601f909101601f19168101906001600160401b038211908210176200094157604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620005945756fe6080604052600436101561001a575b3615610018575f80fd5b005b5f803560e01c8062c61fbf146134b45780630730adbb1461317157806309b6730114613148578063103841c61461303a5780631385d24c1461300b57806324381a5314612fe55780632585d64614612c8f5780632ca8847f14612c665780632dd3100014612c2157806332fe7b2614612bdc5780633d05cbd314612b975780633e032a3b14612b795780633f78817014612a15578063457ea756146128da57806349df728c14612839578063527a53ad146127f4578063551950c8146127af578063603f1afb1461270957806364cc89be1461217757806371065a9314612105578063715018a6146120ac5780637224f322146118b457806375f12b211461189157806376cbff3b1461184c57806389a30271146118075780638da5cb5b146117e05780639735a634146117175780639779d1a6146116d857806399116aba14611693578063993a3719146114015780639c05a4cb146113a3578063ad5c46481461135e578063bc0ca6a514610caa578063bec872b014610c87578063bf8094621461090c578063d1090dc2146108c7578063de9a71291461089e578063e0a6dfa014610697578063e512073814610671578063f066de4b1461062c578063f2fde38b1461056c578063f355355b146105275763fb21cd01146101fd575061000e565b346105245761020b36613aeb565b92906102178184614c50565b604051630240bc6b60e21b8152946001600160a01b038083169492939291606088600481895afa9283156103d757809881946104ed575b5060405196630dfe168160e01b8089526020998a8a600481865afa998a1561042257908b9291859b6104ca575b5086169986168a148015610473575b61029390614082565b60046040518094819382525afa908115610468579382918996958295949161043b575b50168514928315610434578a935b1561042d5784925b6040518b8160048163313ce56760e01b9b8c82525afa9081156104225760049261030a6103058f9461031094899161040b575b506140d9565b6140ea565b90613fbc565b9a604051928380928b82525afa9081156104005761033c6103058d9361034c9387916103e357506140d9565b6001600160701b03968716613fbc565b9660046040518094819382528b165afa9182156103d75761039e999795938561038d61030560409f9c9a98968f96849761039497926103aa575b50506140d9565b9116613fbc565b921696169461489b565b90918351928352820152f35b6103c99250803d106103d0575b6103c18183613c4d565b8101906140c0565b8f80610386565b503d6103b7565b604051903d90823e3d90fd5b6103fa9150853d87116103d0576103c18183613c4d565b5f6102ff565b6040513d85823e3d90fd5b6103fa9150863d88116103d0576103c18183613c4d565b6040513d86823e3d90fd5b8a926102cc565b84936102c4565b61045b91508b3d8d11610461575b6104538183613c4d565b810190613f25565b5f6102b6565b503d610449565b6040513d84823e3d90fd5b5060405163d21220a760e01b81529091508a81600481865afa90811561042257868c93926102939287916104ad575b50168b14905061028a565b6104c49150853d8711610461576104538183613c4d565b5f6104a2565b87919b506104e58291853d8711610461576104538183613c4d565b9b915061027b565b90935061051291985060603d811161051d575b61050a8183613c4d565b810190613f58565b50979097925f61024e565b503d610500565b80fd5b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461052457602036600319011261052457610586613a27565b61058e613bad565b6001600160a01b039081169081156105d8575f548260018060a01b03198216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034610524578060031936011261052457602060ff60035460a01c166040519015158152f35b5034610524576040366003190112610524576001600160401b0360043581811161089a576106c9903690600401613b4d565b90916024928335828111610896573660238201121561089657806004013592831161089657606090858285028201019036821161089257610708613bad565b6107118661406b565b9361071f6040519586613c4d565b8685526020968786019060051b82019136831161088e578890915b838310610876575050505061074e8561406b565b9461075c6040519687613c4d565b855286018585015b828210610824575050505080519261077e8351851461479f565b855b84811061078b578680f35b6107bc610798828661413b565b516001600160a01b036107ab848761413b565b5116895260078452604089206147f2565b6107c6818561413b565b51906006918254600160401b811015610811576107ea906001948582019055613b7d565b6107fe57906107f8916147f2565b01610780565b634e487b7160e01b8a5260048a9052888afd5b634e487b7160e01b8a526041600452888afd5b83823603126108725786849160405161083c81613c17565b61084585613a95565b8152610852838601613a95565b8382015261086260408601613a95565b6040820152815201910190610764565b8880fd5b819061088184613a95565b815201910190889061073a565b8a80fd5b8780fd5b8580fd5b8280fd5b50346105245780600319360112610524576001546040516001600160a01b039091168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5060a036600319011261052457610921613a27565b610929613a3d565b906064356001600160401b038111610c8357610949903690600401613b20565b90610952613a7f565b938392819061096360443587614667565b93889760018060a01b039788807f000000000000000000000000000000000000000000000000000000000000000016961690868214610c7a575b899594939291908616610c5e5750856109be949596979850975b85896143bd565b501693818514610abf575b50506040516370a0823160e01b808252306004830152602093909216908381602481855afa908115610ab4578691610a87575b5080610a75575b50506040519081523060048201528181602481865afa918215610422578492610a43575b505080610a32578280f35b610a3d913390613cc7565b5f808280f35b90809250813d8311610a6e575b610a5a8183613c4d565b81010312610a6a57515f80610a27565b5f80fd5b503d610a50565b610a80913390613cc7565b5f80610a03565b90508381813d8311610aad575b610a9e8183613c4d565b81010312610a6a57515f6109fc565b503d610a94565b6040513d88823e3d90fd5b604051866370a0823160e01b918281523060048201526020938482602481895afa918215610400578392610c2c575b5015610b755750506040519081523060048201528181602481865afa918215610b6a578792610b3c575b505080610b2a575b50505b5f806109c9565b610b35913390613cc7565b5f80610b20565b90809250813d8311610b63575b610b538183613c4d565b81010312610a6a57515f80610b18565b503d610b49565b6040513d89823e3d90fd5b80925093909293610b8a575b50505050610b23565b803b1561089a57828091602460405180948193632e1a7d4d60e01b83528760048401525af1908115610400578391610c14575b50808092335af1610bcc613c6e565b5015610bda57848180610b81565b6064906040519062461bcd60e51b825260048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152fd5b610c1d90613c04565b610c2857815f610bbd565b5080fd5b925090508382813d8111610c57575b610c458183613c4d565b81010312610a6a57889151905f610aee565b503d610c3b565b9694959615610c72575b6109be93946109b7565b869350610c68565b60019a5061099d565b8380fd5b503461052457602036600319011261052457610ca1613bad565b60043560045580f35b5061012036600319011261052457610cc0613a3d565b90610cc9613a53565b91610cd2613a69565b91610cdb613a7f565b60a4356001600160a01b0381169003610a6a576001600160401b039360c435858111610c8357610d0f903690600401613b20565b96909560e43590811161135a57610d2a903690600401613b20565b906101043515156101043503610a6a57610d4960ff6005541615613ed2565b868399859860018060a01b03610d5f8888614c50565b1696878a52600760205260018060a01b03600160408c200154169660043592610d888482614667565b506001600160a01b031615611329575b6001600160a01b0316156112f8575b6001600160a01b0316156112c7575b60011c998a97604051630dfe168160e01b81526020816004818c5afa9081156112bc578b9161129d575b506001600160a01b03808f16911603611292575b6001600160a01b038d81169085160361127d575b5050506001600160a01b0388811690821603611265575b505050610104356110b1575b60405163095ea7b360e01b8082529060208180610e4c8b8760048401613cac565b0381896001600160a01b038e165af18015610ab45791859391602093611094575b50610e846040519485938493845260048401613cac565b0381876001600160a01b038a165af1801561042257906020939291611067575b5083526007825260018060a01b0360408420541660045491846103e8610ed681610ece878c613fbc565b049584613fbc565b604051636cfa229360e01b8152998a9687958694610efa9404923360048701613fcf565b03925af192831561105a578193611026575b506040516370a0823160e01b80825230600483015294906020816024816001600160a01b0386165afa908115610400578391610ff4575b5080610fd9575b50506040519384523060048501526020846024816001600160a01b0386165afa9081156103d75790610fa6575b6020935080610f8b575b5050604051908152f35b610f9f9133906001600160a01b0316613cc7565b5f80610f81565b506020833d602011610fd1575b81610fc060209383613c4d565b81010312610a6a5760209251610f77565b3d9150610fb3565b610fed9133906001600160a01b0316613cc7565b5f80610f4a565b90506020813d60201161101e575b8161100f60209383613c4d565b81010312610a6a57515f610f43565b3d9150611002565b9092506020813d602011611052575b8161104260209383613c4d565b81010312610a6a5751915f610f0c565b3d9150611035565b50604051903d90823e3d90fd5b61108690843d861161108d575b61107e8183613c4d565b810190613d03565b505f610ea4565b503d611074565b6110aa90843d861161108d5761107e8183613c4d565b505f610e6d565b9194604051630240bc6b60e21b8152606081600481865afa90811561125a5785908692611238575b506040516318160ddd60e01b815291602083600481885afa928315610b6a57908a9392918893611201575b5061110f8386613fbc565b6001600160701b03838116949091819081908e9061112e908990613f07565b9261113891613fbc565b938516938461114691613f07565b8083105f14946111746111819561116f61117a9661116f956111889a6111f957509b5b8c613fbc565b613f07565b98613fbc565b9487613faf565b938b613faf565b90818411156111b8575050876111b294936111ac936111a6936140fb565b92613faf565b96613f8e565b91610e2b565b9150918299969499116111ce575b505050610e2b565b6111f093959892886111ea936111e3936140fb565b9092613f8e565b96613faf565b91865f806111c6565b90509b611169565b935091506020833d602011611230575b8161121e60209383613c4d565b81010312610a6a57899251915f611104565b3d9150611211565b9050611252915060603d811161051d5761050a8183613c4d565b50905f6110d9565b6040513d87823e3d90fd5b61127493958860a435926143bd565b915f8080610e1f565b839b8d611289956143bd565b975f8080610e08565b999b998b9850610df4565b6112b6915060203d602011610461576104538183613c4d565b5f610de0565b6040513d8d823e3d90fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169950610db6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169c50610da7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169450610d98565b8480fd5b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461052457602036600319011261052457600435600654811015610c28576113cb90613b7d565b5080546001820154600290920154604080516001600160a01b0393841681529383166020850152911690820152606090f35b0390f35b50346105245761141036613ab8565b9092901561166d577f00000000000000000000000000000000000000000000000000000000000000005b604051630240bc6b60e21b8152936001600160a01b0390828216606087600481845afa91821561125a5785978693611646575b5060405195630dfe168160e01b928388526020988989600481855afa988915610400578399611623575b508616978616881480156115d1575b6114af90614082565b6040518481528981600481855afa908115610400578a91889185916115b4575b5016891494851561156e575060405163d21220a760e01b815291829060049082905afa90811561046857908291899695949391611551575b50955b8315610434578a931561042d5784926040518b8160048163313ce56760e01b9b8c82525afa9081156104225760049261030a6103058f9461031094899161040b57506140d9565b61156891508a3d8c11610461576104538183613c4d565b5f611507565b60046040518094819382525afa90811561046857908291899695949391611597575b509561150a565b6115ae91508a3d8c11610461576104538183613c4d565b5f611590565b6115cb9150833d8511610461576104538183613c4d565b5f6114cf565b5060405163d21220a760e01b81528981600481855afa908115610400576114af9188918591611606575b5016891490506114a6565b61161d91508c8d3d10610461576104538183613c4d565b5f6115fb565b8791995061163e82918c8d3d10610461576104538183613c4d565b999150611497565b90925061166291975060603d811161051d5761050a8183613c4d565b50969096915f61146d565b7f000000000000000000000000000000000000000000000000000000000000000061143a565b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245760203660031901126105245760209060ff906040906001600160a01b03611703613a27565b168152600884522054166040519015158152f35b5034610524576040366003190112610524576001600160401b0360043581811161089a57611749903690600401613b4d565b91602435908111610c8357611762903690600401613b4d565b61176d939193613bad565b61177881831461479f565b845b828110611785578580f35b6117908183876147e2565b35908115158092036117dc576117a78185876147e2565b356001600160a01b03811692908390036108925760019288526008602052604088209060ff801983541691161790550161177a565b8680fd5b5034610524578060031936011261052457546040516001600160a01b039091168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034610524578060031936011261052457602060ff600554166040519015158152f35b5060e0366003190112610524576118c9613a27565b906118d2613a7f565b60a4356001600160401b03811161089a576118f1903690600401613b20565b9290936118fc613aa9565b9061190c60ff6005541615613ed2565b808215612085577f0000000000000000000000000000000000000000000000000000000000000000955b8315612055577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316975b6001546001600160a01b0316968515612045578960ff60035460a81c16945b61199360243588614667565b966001600160a01b031615612015575b6001600160a01b0382811690821603611ffe575b5050604051630240bc6b60e21b81529250606091508290506004816001600160a01b038b165afa801561125a57839086928791611fd8575b508315611f5b5750611a09916001600160701b0316614832565b918215611f4f575b60405163d21220a760e01b81526020816004816001600160a01b038c165afa908115610ab45790611a4b918791611f31575b50898561414f565b928315611f2957611a5b91613faf565b915b60443583101580611f1d575b15611ef2578115611ee757611ac16020845b60405163095ea7b360e01b81529283918291907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660048401613cac565b0381896001600160a01b038e165af18015610ab457611ec8575b508115611ebd5760405163095ea7b360e01b815260208180611b2a856001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660048401613cac565b0381898b5af18015610ab457906060939291611e9e575b508115611e9457611ba5845b8315611e8a57611b82835b8515611e845782905b600454938492611b756103e8968792613fbc565b049715611e7d5750613fbc565b04948a6040519687958695635a47ddc360e01b875242948d309560048a01614020565b0381867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1801561040057611e4e575b5015611e27577f0000000000000000000000000000000000000000000000000000000000000000935b6040516370a0823160e01b808252306004830152959094906020866024816001600160a01b0386165afa958615610422578496611df3575b5060405163095ea7b360e01b81526001600160a01b0391909116916020908290818781611c718c8960048401613cac565b03926001600160a01b03165af1801561042257611dd4575b50803b1561089a57828091606460405180948193638dbdbe6d60e01b83528160048401528a60248401523360448401525af1801561040057908391611dc0575b50506040518581523060048201526020816024816001600160a01b0386165afa908115610400578391611d8e575b5080611d73575b5050604051938452306004850152602084602481855afa9081156103d75790611d40575b6020935080611d35575050604051908152f35b610f9f913390613cc7565b506020833d602011611d6b575b81611d5a60209383613c4d565b81010312610a6a5760209251611d22565b3d9150611d4d565b611d879133906001600160a01b0316613cc7565b5f80611cfe565b90506020813d602011611db8575b81611da960209383613c4d565b81010312610a6a57515f611cf7565b3d9150611d9c565b611dc990613c04565b610c2857815f611cc9565b611dec9060203d60201161108d5761107e8183613c4d565b505f611c89565b9095506020813d602011611e1f575b81611e0f60209383613c4d565b81010312610a6a5751945f611c40565b3d9150611e02565b7f000000000000000000000000000000000000000000000000000000000000000093611c08565b611e6f9060603d606011611e76575b611e678183613c4d565b810190614005565b5050611bdf565b503d611e5d565b9050613fbc565b80611b61565b611b828193611b58565b611ba58194611b4d565b611eb69060203d60201161108d5761107e8183613c4d565b505f611b41565b611b2a602084611a7b565b611ee09060203d60201161108d5761107e8183613c4d565b505f611adb565b611ac1602082611a7b565b606460405162461bcd60e51b81526020600482015260046024820152634553543360e01b6044820152fd5b50606435811015611a69565b505083611a5b565b611f49915060203d8111610461576104538183613c4d565b5f611a43565b80925060011c91611a11565b611f6e92506001600160701b0316614832565b918215611fcc575b604051630dfe168160e01b81526020816004816001600160a01b038c165afa908115610ab45790611faf918791611f315750898561414f565b928315611fc457611fbf91613faf565b611a5d565b505083611a5d565b80925060011c91611f76565b9050611ff491925060603d60601161051d5761050a8183613c4d565b509190915f6119ef565b9061200a9596916143bd565b905f808089816119b7565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166119a3565b8960ff60035460a01c1694611987565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031697611968565b7f000000000000000000000000000000000000000000000000000000000000000095611936565b50346105245780600319360112610524576120c5613bad565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5034610524576020366003190112610524576001600160a01b03906040908261212c613a27565b168152600760205220906113fd81835416916002816001860154169401541660405193849384916040919493606084019560018060a01b039283809216865216602085015216910152565b50346105245760a03660031901126105245760243590600435612198613a53565b916121a1613a69565b93608435928315158403610a6a576121c68195839760018060a01b0392839183614c50565b169360405193630dfe168160e01b9485815260209384826004818b5afa9182156126ae579086918a936126e8575b5081169116036126dd575b5050604051630240bc6b60e21b815293606085600481845afa948515610ab457869087966126b9575b5060018060701b03809116951692604051996318160ddd60e01b95868c52848c600481875afa9a8b156126ae57899b61267e575b8b809d5061227c8861116f6122758d61116f8688613fbc565b9387613fbc565b808210156126765750905b6122a4612299839e61116f8d86613fbc565b9e61116f8a85613fbc565b9b6122cd575b8d8d6113fd8e604051938493846040919493926060820195825260208201520152565b8b6122e18f9d9f9e9b9c9d6122e793613faf565b94613faf565b808411156124ae5750506040519081528481600481875afa998a156103d7579961248f575b506123178189614832565b91604051996378a051ad60e11b8b528360048c01521660248a01528389604481865afa988915612421575f9961245e575b509061235391613faf565b95604051908582528382600481865afa80156124215784925f9161242c575b509061116f612381928a613fbc565b9460046040518094819382525afa918215612421575f926123f0575b505085936123d2936123bd6123d8979461116f6123cc956113fd9b613fbc565b808210156123e8575090613f8e565b95613f8e565b94613f8e565b905f8080808080808080806122aa565b905090613f8e565b81819392933d831161241a575b6124078183613c4d565b81010312610524575051836123d261239d565b503d6123fd565b6040513d5f823e3d90fd5b919282813d8311612457575b6124428183613c4d565b8101031261052457505183919061116f612372565b503d612438565b90988482813d8311612488575b6124758183613c4d565b8101031261052457505197612353612348565b503d61246b565b6124a7919950843d8611610461576104538183613c4d565b975f61230c565b8092509c9a989b9c9796959493929097116124d6575b5050505050505050506113fd906123d8565b9091929394959697989a995060405163d21220a760e01b81528481600481875afa9889156103d75798612657575b5061250f8186614832565b91604051986378a051ad60e11b8a528360048b01521660248901528388604481865afa978815612421575f98612626575b509061254b91613faf565b96604051908582528382600481865afa80156124215784925f916125f4575b509061116f612579928a613fbc565b9460046040518094819382525afa918215612421575f926125c3575b505085936123d2936123bd6125b5979461116f6123cc956113fd9b613fbc565b905f808080808080806124c4565b81819392933d83116125ed575b6125da8183613c4d565b81010312610524575051836123d2612595565b503d6125d0565b919282813d831161261f575b61260a8183613c4d565b8101031261052457505183919061116f61256a565b503d612600565b90978482813d8311612650575b61263d8183613c4d565b810103126105245750519661254b612540565b503d612633565b61266f919850843d8611610461576104538183613c4d565b965f612504565b905090612287565b9a509a8481813d83116126a7575b6126968183613c4d565b81010312610a6a5751998b9061225c565b503d61268c565b6040513d8b823e3d90fd5b90506126d491955060603d811161051d5761050a8183613c4d565b5094905f612228565b985096505f806121ff565b8291935061270290873d8911610461576104538183613c4d565b92906121f4565b5034610524578060031936011261052457612722613bad565b4761272a5780f35b805460405147916001600160a01b031690602081016001600160401b0381118282101761279b578493849384809484604052525af1612767613c6e565b50156127705780f35b60405162461bcd60e51b815260206004820152600360248201526253544560e81b6044820152606490fd5b634e487b7160e01b5f52604160045260245ffd5b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034610524576020908160031936011261052457612855613a27565b9061285e613bad565b80546040516370a0823160e01b8152306004820152926001600160a01b0391821691168484602481845afa9283156103d757926128a9575b6128a09350613cc7565b60405160018152f35b91508383813d83116128d3575b6128c08183613c4d565b81010312610a6a576128a0925191612896565b503d6128b6565b5034610524576128fe6128ec36613aeb565b926001600160a01b0392909190614c50565b1690604051906318160ddd60e01b82526020938483600481875afa92831561105a5781936129e3575b50606060049460405195868092630240bc6b60e21b82525afa93841561105a5781946129bf575b50821561298b579161116f61298092604096946129788461116f60018060701b0380941685613fbc565b961690613fbc565b908351928352820152f35b60405162461bcd60e51b815260048101869052600c60248201526b4e6f206c697175696469747960a01b6044820152606490fd5b90506129da91935060603d811161051d5761050a8183613c4d565b5092905f61294e565b9392508484813d8311612a0e575b6129fb8183613c4d565b81010312610a6a57925191926060612927565b503d6129f1565b503461052457602036600319011261052457612a2f613a27565b612a37613bad565b600680546001600160a01b03928316929190845b818110612a70578585815260076020525f600260408320828155826001820155015580f35b612a7981613b7d565b509085856002809401541614612a94575b6001915001612a4b565b5f19838101848111612b6557612aa990613b7d565b50612ab383613b7d565b612b5157818103612b14575b505084548015612b005701612ad381613b7d565b612aed57600193815f809355828682015501558455612a8a565b634e487b7160e01b5f525f60045260245ffd5b634e487b7160e01b89526031600452602489fd5b878580828554169360018060a01b031994858254161781556001848183019188015416868254161790550193015416908254161790555f80612abf565b634e487b7160e01b8a5260048a905260248afd5b634e487b7160e01b89526011600452602489fd5b50346105245780600319360112610524576020600454604051908152f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245780600319360112610524576002546040516001600160a01b039091168152602090f35b503461052457612c9e36613ab8565b9192909115612fbe577f0000000000000000000000000000000000000000000000000000000000000000915b604051630240bc6b60e21b81526001600160a01b03938416939092606084600481885afa93841561105a5781908295612f9a575b50604051630dfe168160e01b81526001600160701b0391821695909116936020939192909184846004818b5afa938415610468578294612f7b575b5060405163d21220a760e01b815298858a6004818c5afa998a1561040057839a612f58575b5081809116941684149081998215612f4c575b505015612f1757508615612f0d57612d898186614832565b90604051926378a051ad60e11b8452826004850152602484015283836044818a5afa928315612421575f93612edc575b5090612dc491613faf565b8615612ed55780965b15612ecd5750935b6040516318160ddd60e01b808252948382600481865afa80156124215784925f91612e9b575b509061116f612e0a928a613fbc565b9460046040518094819382525afa918215612421575f92612e6a575b50506113fd929161116f612e3a9286613fbc565b80821015612e625750915b604051938493846040919493926060820195825260208201520152565b905091612e45565b81819392933d8311612e94575b612e818183613c4d565b810103126105245750518161116f612e26565b503d612e77565b919282813d8311612ec6575b612eb18183613c4d565b8101031261052457505183919061116f612dfb565b503d612ea7565b905093612dd5565b8196612dcd565b90928482813d8311612f06575b612ef38183613c4d565b8101031261052457505191612dc4612db9565b503d612ee9565b612d898185614832565b60405162461bcd60e51b815260048101859052600d60248201526c34b73b30b634b2103a37b5b2b760991b6044820152606490fd5b16841490505f80612d71565b82919a50612f738291883d8a11610461576104538183613c4d565b9a9150612d5e565b612f93919450853d8711610461576104538183613c4d565b925f612d39565b9050612fb591945060603d811161051d5761050a8183613c4d565b5093905f612cfe565b7f000000000000000000000000000000000000000000000000000000000000000091612cca565b5034610524578060031936011261052457602060ff60035460a81c166040519015158152f35b5034610524578060031936011261052457613024613bad565b60055460ff80821615169060ff19161760055580f35b50346105245780600319360112610524576006546130578161406b565b906130656040519283613c4d565b8082526006835260209182810191847ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f845b8383106130fd57505050506040519280840191818552518092526040840192945b8281106130c55784840385f35b855180516001600160a01b039081168652818401518116868501526040918201511690850152948101946060909301926001016130b8565b60038760019260409a9997989a5161311481613c17565b848060a01b038087541682528086880154168483015260028701541660408201528152019201920191909694939596613097565b50346105245780600319360112610524576003546040516001600160a01b039091168152602090f35b50608036600319011261052457613186613a27565b61318e613a3d565b91606435906131a260ff6005541615613ed2565b6044359284926001600160a01b038183826131bd8883614c50565b16918287528360209a60078c528180600160408c20015416986131e08d82614667565b506131eb8584614667565b50161561348a575b1615613460575b604051630dfe168160e01b81528a81600481875afa90811561342c578891613443575b5084808416911603613437575b508216936040519663095ea7b360e01b978881528a818061324f8d8760048401613cac565b03818b8b5af1801561342c578b92879492879261340f575b5016986132806040519485938493845260048401613cac565b0381898b5af18015610ab4579089949392916133f2575b5085526007835260408520541660045491856103e86132ba81610ece878d613fbc565b604051636cfa229360e01b81529a8b96879586946132de9404923360048701613fcf565b03925af19384156104685782946133c3575b506040516370a0823160e01b80825230600483015291908681602481855afa908115610422578491613396575b5080613384575b50506040519081523060048201528481602481865afa9182156103d75791613357575b5080611d35575050604051908152f35b90508381813d831161337d575b61336e8183613c4d565b81010312610a6a57515f613347565b503d613364565b61338f913390613cc7565b5f80613324565b90508681813d83116133bc575b6133ad8183613c4d565b81010312610a6a57515f61331d565b503d6133a3565b9093508481813d83116133eb575b6133db8183613c4d565b81010312610a6a5751925f6132f0565b503d6133d1565b61340890853d871161108d5761107e8183613c4d565b505f613297565b61342590853d871161108d5761107e8183613c4d565b505f613267565b6040513d8a823e3d90fd5b9790969093508261322a565b61345a91508b3d8d11610461576104538183613c4d565b5f61321d565b7f0000000000000000000000000000000000000000000000000000000000000000841697506131fa565b7f0000000000000000000000000000000000000000000000000000000000000000821693506131f3565b5060e0366003190112610524576134c9613a27565b6134d1613a3d565b6134d9613aa9565b6134e860ff6005541615613ed2565b8383918394815f14613a00577f0000000000000000000000000000000000000000000000000000000000000000915b156139d9577f0000000000000000000000000000000000000000000000000000000000000000945b60443561354c8184614667565b9161355960643582614667565b936001600160a01b0316156139a8575b6001600160a01b031615613977575b60405163095ea7b360e01b815290602090829081906135c4907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660048401613cac565b0381886001600160a01b038b165af1801561125a57613958575b5060405163095ea7b360e01b8152916020838061362a6064357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660048401613cac565b0381886001600160a01b038d165af191821561125a5761367693606093613939575b50604051635a47ddc360e01b815293849283924291309160a43591608435918f8e60048a01614020565b0381867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af180156104005761391b575b506040516370a0823160e01b8082523060048301529490916001600160a01b039182169116602083602481845afa9283156104225784936138e6575b50602061370e936040518095819263095ea7b360e01b83528660048401613cac565b038187855af1908115610422576024936020926138c9575b50604051938480928982523060048301525afa918215610400578392613895575b50803b1561089a57606483926040519485938492638dbdbe6d60e01b845282600485015260248401523360448401525af1801561125a57613882575b506040518281523060048201526020816024816001600160a01b0386165afa90811561125a578591613850575b5080613835575b50506040519081523060048201526020816024816001600160a01b0386165afa908115610400578391613803575b50806137ef578280f35b610a3d9133906001600160a01b0316613cc7565b90506020813d60201161382d575b8161381e60209383613c4d565b81010312610a6a57515f6137e5565b3d9150613811565b6138499133906001600160a01b0316613cc7565b5f806137b7565b90506020813d60201161387a575b8161386b60209383613c4d565b81010312610a6a57515f6137b0565b3d915061385e565b61388e90949194613c04565b925f613783565b9091506020813d6020116138c1575b816138b160209383613c4d565b8101031261089a5751905f613747565b3d91506138a4565b6138df90833d851161108d5761107e8183613c4d565b505f613726565b92506020833d602011613913575b8161390160209383613c4d565b81010312610c835791519160206136ec565b3d91506138f4565b6139329060603d8111611e7657611e678183613c4d565b50506136b0565b6139519060203d60201161108d5761107e8183613c4d565b505f61364c565b6139709060203d60201161108d5761107e8183613c4d565b505f6135de565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169750613578565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169650613569565b7f00000000000000000000000000000000000000000000000000000000000000009461353f565b7f000000000000000000000000000000000000000000000000000000000000000091613517565b600435906001600160a01b0382168203610a6a57565b602435906001600160a01b0382168203610a6a57565b604435906001600160a01b0382168203610a6a57565b606435906001600160a01b0382168203610a6a57565b608435906001600160a01b0382168203610a6a57565b35906001600160a01b0382168203610a6a57565b60c435908115158203610a6a57565b6060906003190112610a6a576004356001600160a01b0381168103610a6a5790602435906044358015158103610a6a5790565b6060906003190112610a6a576001600160a01b03906004358281168103610a6a57916024359081168103610a6a579060443590565b9181601f84011215610a6a578235916001600160401b038311610a6a5760208381860195010111610a6a57565b9181601f84011215610a6a578235916001600160401b038311610a6a576020808501948460051b010111610a6a57565b600654811015613b995760065f52600360205f20910201905f90565b634e487b7160e01b5f52603260045260245ffd5b5f546001600160a01b03163303613bc057565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160401b03811161279b57604052565b606081019081106001600160401b0382111761279b57604052565b604081019081106001600160401b0382111761279b57604052565b90601f801991011681019081106001600160401b0382111761279b57604052565b3d15613ca7573d906001600160401b03821161279b5760405191613c9c601f8201601f191660200184613c4d565b82523d5f602084013e565b606090565b6001600160a01b039091168152602081019190915260400190565b613cfc613d019392613cee60405194859263a9059cbb60e01b602085015260248401613cac565b03601f198101845283613c4d565b613d1b565b565b90816020910312610a6a57518015158103610a6a5790565b604051613d78916001600160a01b0316613d3482613c32565b5f806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af1613d72613c6e565b91613e00565b805190828215928315613de8575b50505015613d915750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b613df89350820181019101613d03565b5f8281613d86565b91929015613e625750815115613e14575090565b3b15613e1d5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015613e755750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401525f935b828510613eb9575050604492505f838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350613e97565b15613ed957565b60405162461bcd60e51b815260206004820152600660248201526514185d5cd95960d21b6044820152606490fd5b8115613f11570490565b634e487b7160e01b5f52601260045260245ffd5b90816020910312610a6a57516001600160a01b0381168103610a6a5790565b51906001600160701b0382168203610a6a57565b90816060910312610a6a57613f6c81613f44565b916040613f7b60208401613f44565b92015163ffffffff81168103610a6a5790565b91908201809211613f9b57565b634e487b7160e01b5f52601160045260245ffd5b91908203918211613f9b57565b81810292918115918404141715613f9b57565b9391959492909560c085019660018060a01b03168552602085015260408401526060830152608082015260a0600f60fc1b910152565b90816060910312610a6a578051916040602083015192015190565b9490989796929361010096929461012087019a60018060a01b03968780921689521660208801525f60408801526060870152608086015260a085015260c08401521660e08201520152565b6001600160401b03811161279b5760051b60200190565b1561408957565b60405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b2103a37b5b2b724b760891b6044820152606490fd5b90816020910312610a6a575160ff81168103610a6a5790565b60ff166012039060ff8211613f9b57565b60ff16604d8111613f9b57600a0a90565b91935f9390929091614115916001600160701b0316614832565b938461411f575050565b61412b9293508461414f565b90565b805115613b995760200190565b8051821015613b995760209160051b010190565b91929060409182519161416183613c32565b6001948584525f5b60208082101561419a5786516020929161418282613c17565b5f82525f818301525f89830152828801015201614169565b5050929590939491956141ac8161412e565b516001600160a01b039586169081905260209290919086846141cd8461412e565b5101911690525f876141de8361412e565b5101525f83877f0000000000000000000000000000000000000000000000000000000000000000169360448a518094819363095ea7b360e01b8352886004840152811960248401525af180156143b357614396575b5090935f9485928851978893631e82ecdb60e31b855260a4850190600486015287602486015260a0604486015282518091528660c4860193019186905b89898484106143615750505050505083838092306064830152600f60fc1b608483015203925af193849184956142d1575b50506142af57505050505f90565b825111156142bd5750015190565b634e487b7160e01b81526032600452602490fd5b909194503d8085843e6142e48184613c4d565b820191818184031261135a578051906001600160401b03821161089657019180601f8401121561135a5782516143198161406b565b9361432689519586613c4d565b818552838086019260051b8201019283116117dc578301905b8282106143525750505050925f806142a1565b8151815290830190830161433f565b8551805184168852808201518416888301528f015115158f8801528c99508d9850606090960195949094019390910190614270565b6143ac90843d861161108d5761107e8183613c4d565b505f614233565b88513d5f823e3d90fd5b9295949091939560018060a01b038094169060409788519263095ea7b360e01b90818552602096856143f460049b878d8401613cac565b039588815f98818a875af1801561465d57908a9291614640575b5016938b51966370a0823160e01b94858952308c8a015260249a8a8a8d818b5afa998a1561463557908f9695949392918a9b6145f7575b508316808a5260088c529589205460ff16156145bc5791818f8a9485948592519384928337810182815203925af161447b613c6e565b501561457f5760448892878c938f5196879586948552840152818d8401525af180156145755790869291614558575b50868a51809481938252308b8301525afa91821561454d57809261451b575b5050906144d591613faf565b9485156144e25750505050565b5162461bcd60e51b8152928301526017908201527622b93937b91029bbb0b83834b733902a37b5b2b739901960491b6044820152606490fd5b9091508382813d8311614546575b6145338183613c4d565b810103126105245750516144d55f6144c9565b503d614529565b8851903d90823e3d90fd5b61456e90833d851161108d5761107e8183613c4d565b505f6144aa565b8a513d86823e3d90fd5b508a5162461bcd60e51b8152808a018890526017818a0152764572726f72205377617070696e6720546f6b656e73203160481b6044820152606490fd5b508d5162461bcd60e51b8152808d018b90526015818d01527415185c99d95d081b9bdd08105d5d1a1bdc9a5e9959605a1b6044820152606490fd5b8c80929c5081939495969798503d831161462e575b6146168183613c4d565b810103126108725751988e95949392919060ff614445565b503d61460c565b508e513d8a823e3d90fd5b614656908a3d8c1161108d5761107e8183613c4d565b505f61440e565b8d513d89823e3d90fd5b6001600160a01b03908116908115614705575081156146c9576040516323b872dd60e01b60208201523360248201523060448201526064808201849052815260a08101916001600160401b0383118284101761279b5761412b92604052613d1b565b60405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a59081d1bdad95b88185b5bdd5b9d60621b6044820152606490fd5b915050341561476c577f000000000000000000000000000000000000000000000000000000000000000016803b15610a6a575f60049160405192838092630d0e30db60e41b825234905af180156124215761475f57503490565b61476890613c04565b3490565b60405162461bcd60e51b815260206004820152600b60248201526a139bc8195d1a081cd95b9d60aa1b6044820152606490fd5b156147a657565b60405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c84092dce0eae840d8cadccee8d60631b6044820152606490fd5b9190811015613b995760051b0190565b60018060a01b0360406002828551169360018060a01b03199485825416178155600181018460208801511686825416179055019301511690825416179055565b90623cda2090818102918183041490151715613f9b57623cda299081830283159284820414831715613f9b5761486e6148749161487993613f8e565b84613fbc565b614d89565b906107cd808402938404141715613f9b576107ca9161489791613faf565b0490565b90939695929491946148b18661116f8785613fbc565b6040805163313ce56760e01b8082529891956001600160a01b039485169560209593949093919286816004818b5afa908115614acf5761030561490593926148ff925f91614b0957506140d9565b90613f07565b9b16968651916318160ddd60e01b835285836004818c5afa9283156143b3575f93614ad9575b509060049186849a8a5194858092637464fc3d60e01b82525afa928315614acf579187969593918b95935f93614a92575b50826149ed575b50505050614975929161116f91613fbc565b96600485518095819382525afa9283156149e457506149ab61030561116f946149b69796946149b1945f926149c75750506140d9565b88613fbc565b613fbc565b808210156149c2575090565b905090565b6149dd9250803d106103d0576103c18183613c4d565b5f80610386565b513d5f823e3d90fd5b6149fd614a0892614a0292613fbc565b614b20565b91614b20565b90818111614a17575b80614963565b8193959650614a27929450613faf565b61271080820290828204811483151715613f9b57614a5f93614a53614a589261116f9404948592613f8e565b613faf565b9184613fbc565b9081614a72575b91818594938993614a11565b614975929750614a8785949261116f92613f8e565b979250819350614a66565b80939294965088919597983d8311614ac8575b614aaf8183613c4d565b810103126105245750918993918796959351915f61495c565b503d614aa5565b89513d5f823e3d90fd5b90928682813d8311614b02575b614af08183613c4d565b8101031261052457505191600461492b565b503d614ae6565b6103fa91508a3d8c116103d0576103c18183613c4d565b8015614c4b576149b6815f908360801c80614c3f575b508060401c80614c32575b508060201c80614c25575b508060101c80614c18575b508060081c80614c0b575b508060041c80614bfe575b508060021c80614bf1575b50600191828092811c614bea575b1c1b614b928185613f07565b01811c614b9f8185613f07565b01811c614bac8185613f07565b01811c614bb98185613f07565b01811c614bc68185613f07565b01811c614bd38185613f07565b01811c614be08185613f07565b01901c8092613f07565b0181614b86565b600291509101905f614b78565b600491509101905f614b6d565b600891509101905f614b62565b601091509101905f614b57565b602091509101905f614b4c565b604091509101905f614b41565b9150506080905f614b36565b505f90565b6001600160a01b039291839081831615614d5f575b81811615614d36575b6040516306801cc360e41b815292821660048401521660248201525f60448201526020816064817f000000000000000000000000000000000000000000000000000000000000000087165afa80156124215783915f91614d18575b501691825f526007602052600260405f2001541615614ce457565b60405162461bcd60e51b815260206004820152600c60248201526b24b73b30b634b2102830b4b960a11b6044820152606490fd5b614d30915060203d8111610461576104538183613c4d565b5f614cc9565b50807f000000000000000000000000000000000000000000000000000000000000000016614c6e565b7f000000000000000000000000000000000000000000000000000000000000000082169250614c65565b8015614c4b57600181600160801b811015614ead575b614e4f614e42614e35614e28614e1b614e0e6149b6976008614e5c98600160401b811015614ea0575b640100000000811015614e93575b62010000811015614e87575b610100811015614e7b575b6010811015614e6e575b1015614e66575b614e08818b613f07565b90613f8e565b60011c614e08818a613f07565b60011c614e088189613f07565b60011c614e088188613f07565b60011c614e088187613f07565b60011c614e088186613f07565b60011c614e088185613f07565b60011c8092613f07565b60011b614dfe565b60041c9160021b91614df7565b811c9160041b91614ded565b60101c91811b91614de2565b60201c9160101b91614dd6565b60401c9160201b91614dc8565b50600160401b9050608082901c614d9f56fea264697066735822122066d7c52dc80b5e77105af9c88936ed937c2d48f87079a1e44f47c5b88fa65a1864736f6c634300081400330000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc00000000000000000000000029219dd400f2bf60e5a23d13be72b486d40388940000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf00000000000000000000000019d04a9bd2aeee1d1b9e86a05afeadb4c9c6e395000000000000000000000000c7f449eb12f20d66e33631ad5176993ccacb6acf00000000000000000000000012c0d2e69c309ba71d8ca55f61ce4395c01d15d10000000000000000000000007993620e9f66cb7cef1ffb755aa8ad8df4a10207000000000000000000000000f93d924b54955e113965e51641f360163709029700000000000000000000000031a5a7add82b1091821be91dececc13974c76e36
Deployed Bytecode
0x6080604052600436101561001a575b3615610018575f80fd5b005b5f803560e01c8062c61fbf146134b45780630730adbb1461317157806309b6730114613148578063103841c61461303a5780631385d24c1461300b57806324381a5314612fe55780632585d64614612c8f5780632ca8847f14612c665780632dd3100014612c2157806332fe7b2614612bdc5780633d05cbd314612b975780633e032a3b14612b795780633f78817014612a15578063457ea756146128da57806349df728c14612839578063527a53ad146127f4578063551950c8146127af578063603f1afb1461270957806364cc89be1461217757806371065a9314612105578063715018a6146120ac5780637224f322146118b457806375f12b211461189157806376cbff3b1461184c57806389a30271146118075780638da5cb5b146117e05780639735a634146117175780639779d1a6146116d857806399116aba14611693578063993a3719146114015780639c05a4cb146113a3578063ad5c46481461135e578063bc0ca6a514610caa578063bec872b014610c87578063bf8094621461090c578063d1090dc2146108c7578063de9a71291461089e578063e0a6dfa014610697578063e512073814610671578063f066de4b1461062c578063f2fde38b1461056c578063f355355b146105275763fb21cd01146101fd575061000e565b346105245761020b36613aeb565b92906102178184614c50565b604051630240bc6b60e21b8152946001600160a01b038083169492939291606088600481895afa9283156103d757809881946104ed575b5060405196630dfe168160e01b8089526020998a8a600481865afa998a1561042257908b9291859b6104ca575b5086169986168a148015610473575b61029390614082565b60046040518094819382525afa908115610468579382918996958295949161043b575b50168514928315610434578a935b1561042d5784925b6040518b8160048163313ce56760e01b9b8c82525afa9081156104225760049261030a6103058f9461031094899161040b575b506140d9565b6140ea565b90613fbc565b9a604051928380928b82525afa9081156104005761033c6103058d9361034c9387916103e357506140d9565b6001600160701b03968716613fbc565b9660046040518094819382528b165afa9182156103d75761039e999795938561038d61030560409f9c9a98968f96849761039497926103aa575b50506140d9565b9116613fbc565b921696169461489b565b90918351928352820152f35b6103c99250803d106103d0575b6103c18183613c4d565b8101906140c0565b8f80610386565b503d6103b7565b604051903d90823e3d90fd5b6103fa9150853d87116103d0576103c18183613c4d565b5f6102ff565b6040513d85823e3d90fd5b6103fa9150863d88116103d0576103c18183613c4d565b6040513d86823e3d90fd5b8a926102cc565b84936102c4565b61045b91508b3d8d11610461575b6104538183613c4d565b810190613f25565b5f6102b6565b503d610449565b6040513d84823e3d90fd5b5060405163d21220a760e01b81529091508a81600481865afa90811561042257868c93926102939287916104ad575b50168b14905061028a565b6104c49150853d8711610461576104538183613c4d565b5f6104a2565b87919b506104e58291853d8711610461576104538183613c4d565b9b915061027b565b90935061051291985060603d811161051d575b61050a8183613c4d565b810190613f58565b50979097925f61024e565b503d610500565b80fd5b50346105245780600319360112610524576040517f000000000000000000000000c7f449eb12f20d66e33631ad5176993ccacb6acf6001600160a01b03168152602090f35b503461052457602036600319011261052457610586613a27565b61058e613bad565b6001600160a01b039081169081156105d8575f548260018060a01b03198216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b50346105245780600319360112610524576040517f00000000000000000000000031a5a7add82b1091821be91dececc13974c76e366001600160a01b03168152602090f35b5034610524578060031936011261052457602060ff60035460a01c166040519015158152f35b5034610524576040366003190112610524576001600160401b0360043581811161089a576106c9903690600401613b4d565b90916024928335828111610896573660238201121561089657806004013592831161089657606090858285028201019036821161089257610708613bad565b6107118661406b565b9361071f6040519586613c4d565b8685526020968786019060051b82019136831161088e578890915b838310610876575050505061074e8561406b565b9461075c6040519687613c4d565b855286018585015b828210610824575050505080519261077e8351851461479f565b855b84811061078b578680f35b6107bc610798828661413b565b516001600160a01b036107ab848761413b565b5116895260078452604089206147f2565b6107c6818561413b565b51906006918254600160401b811015610811576107ea906001948582019055613b7d565b6107fe57906107f8916147f2565b01610780565b634e487b7160e01b8a5260048a9052888afd5b634e487b7160e01b8a526041600452888afd5b83823603126108725786849160405161083c81613c17565b61084585613a95565b8152610852838601613a95565b8382015261086260408601613a95565b6040820152815201910190610764565b8880fd5b819061088184613a95565b815201910190889061073a565b8a80fd5b8780fd5b8580fd5b8280fd5b50346105245780600319360112610524576001546040516001600160a01b039091168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000019d04a9bd2aeee1d1b9e86a05afeadb4c9c6e3956001600160a01b03168152602090f35b5060a036600319011261052457610921613a27565b610929613a3d565b906064356001600160401b038111610c8357610949903690600401613b20565b90610952613a7f565b938392819061096360443587614667565b93889760018060a01b039788807f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3816961690868214610c7a575b899594939291908616610c5e5750856109be949596979850975b85896143bd565b501693818514610abf575b50506040516370a0823160e01b808252306004830152602093909216908381602481855afa908115610ab4578691610a87575b5080610a75575b50506040519081523060048201528181602481865afa918215610422578492610a43575b505080610a32578280f35b610a3d913390613cc7565b5f808280f35b90809250813d8311610a6e575b610a5a8183613c4d565b81010312610a6a57515f80610a27565b5f80fd5b503d610a50565b610a80913390613cc7565b5f80610a03565b90508381813d8311610aad575b610a9e8183613c4d565b81010312610a6a57515f6109fc565b503d610a94565b6040513d88823e3d90fd5b604051866370a0823160e01b918281523060048201526020938482602481895afa918215610400578392610c2c575b5015610b755750506040519081523060048201528181602481865afa918215610b6a578792610b3c575b505080610b2a575b50505b5f806109c9565b610b35913390613cc7565b5f80610b20565b90809250813d8311610b63575b610b538183613c4d565b81010312610a6a57515f80610b18565b503d610b49565b6040513d89823e3d90fd5b80925093909293610b8a575b50505050610b23565b803b1561089a57828091602460405180948193632e1a7d4d60e01b83528760048401525af1908115610400578391610c14575b50808092335af1610bcc613c6e565b5015610bda57848180610b81565b6064906040519062461bcd60e51b825260048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152fd5b610c1d90613c04565b610c2857815f610bbd565b5080fd5b925090508382813d8111610c57575b610c458183613c4d565b81010312610a6a57889151905f610aee565b503d610c3b565b9694959615610c72575b6109be93946109b7565b869350610c68565b60019a5061099d565b8380fd5b503461052457602036600319011261052457610ca1613bad565b60043560045580f35b5061012036600319011261052457610cc0613a3d565b90610cc9613a53565b91610cd2613a69565b91610cdb613a7f565b60a4356001600160a01b0381169003610a6a576001600160401b039360c435858111610c8357610d0f903690600401613b20565b96909560e43590811161135a57610d2a903690600401613b20565b906101043515156101043503610a6a57610d4960ff6005541615613ed2565b868399859860018060a01b03610d5f8888614c50565b1696878a52600760205260018060a01b03600160408c200154169660043592610d888482614667565b506001600160a01b031615611329575b6001600160a01b0316156112f8575b6001600160a01b0316156112c7575b60011c998a97604051630dfe168160e01b81526020816004818c5afa9081156112bc578b9161129d575b506001600160a01b03808f16911603611292575b6001600160a01b038d81169085160361127d575b5050506001600160a01b0388811690821603611265575b505050610104356110b1575b60405163095ea7b360e01b8082529060208180610e4c8b8760048401613cac565b0381896001600160a01b038e165af18015610ab45791859391602093611094575b50610e846040519485938493845260048401613cac565b0381876001600160a01b038a165af1801561042257906020939291611067575b5083526007825260018060a01b0360408420541660045491846103e8610ed681610ece878c613fbc565b049584613fbc565b604051636cfa229360e01b8152998a9687958694610efa9404923360048701613fcf565b03925af192831561105a578193611026575b506040516370a0823160e01b80825230600483015294906020816024816001600160a01b0386165afa908115610400578391610ff4575b5080610fd9575b50506040519384523060048501526020846024816001600160a01b0386165afa9081156103d75790610fa6575b6020935080610f8b575b5050604051908152f35b610f9f9133906001600160a01b0316613cc7565b5f80610f81565b506020833d602011610fd1575b81610fc060209383613c4d565b81010312610a6a5760209251610f77565b3d9150610fb3565b610fed9133906001600160a01b0316613cc7565b5f80610f4a565b90506020813d60201161101e575b8161100f60209383613c4d565b81010312610a6a57515f610f43565b3d9150611002565b9092506020813d602011611052575b8161104260209383613c4d565b81010312610a6a5751915f610f0c565b3d9150611035565b50604051903d90823e3d90fd5b61108690843d861161108d575b61107e8183613c4d565b810190613d03565b505f610ea4565b503d611074565b6110aa90843d861161108d5761107e8183613c4d565b505f610e6d565b9194604051630240bc6b60e21b8152606081600481865afa90811561125a5785908692611238575b506040516318160ddd60e01b815291602083600481885afa928315610b6a57908a9392918893611201575b5061110f8386613fbc565b6001600160701b03838116949091819081908e9061112e908990613f07565b9261113891613fbc565b938516938461114691613f07565b8083105f14946111746111819561116f61117a9661116f956111889a6111f957509b5b8c613fbc565b613f07565b98613fbc565b9487613faf565b938b613faf565b90818411156111b8575050876111b294936111ac936111a6936140fb565b92613faf565b96613f8e565b91610e2b565b9150918299969499116111ce575b505050610e2b565b6111f093959892886111ea936111e3936140fb565b9092613f8e565b96613faf565b91865f806111c6565b90509b611169565b935091506020833d602011611230575b8161121e60209383613c4d565b81010312610a6a57899251915f611104565b3d9150611211565b9050611252915060603d811161051d5761050a8183613c4d565b50905f6110d9565b6040513d87823e3d90fd5b61127493958860a435926143bd565b915f8080610e1f565b839b8d611289956143bd565b975f8080610e08565b999b998b9850610df4565b6112b6915060203d602011610461576104538183613c4d565b5f610de0565b6040513d8d823e3d90fd5b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03169950610db6565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03169c50610da7565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03169450610d98565b8480fd5b50346105245780600319360112610524576040517f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03168152602090f35b503461052457602036600319011261052457600435600654811015610c28576113cb90613b7d565b5080546001820154600290920154604080516001600160a01b0393841681529383166020850152911690820152606090f35b0390f35b50346105245761141036613ab8565b9092901561166d577f0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b5b604051630240bc6b60e21b8152936001600160a01b0390828216606087600481845afa91821561125a5785978693611646575b5060405195630dfe168160e01b928388526020988989600481855afa988915610400578399611623575b508616978616881480156115d1575b6114af90614082565b6040518481528981600481855afa908115610400578a91889185916115b4575b5016891494851561156e575060405163d21220a760e01b815291829060049082905afa90811561046857908291899695949391611551575b50955b8315610434578a931561042d5784926040518b8160048163313ce56760e01b9b8c82525afa9081156104225760049261030a6103058f9461031094899161040b57506140d9565b61156891508a3d8c11610461576104538183613c4d565b5f611507565b60046040518094819382525afa90811561046857908291899695949391611597575b509561150a565b6115ae91508a3d8c11610461576104538183613c4d565b5f611590565b6115cb9150833d8511610461576104538183613c4d565b5f6114cf565b5060405163d21220a760e01b81528981600481855afa908115610400576114af9188918591611606575b5016891490506114a6565b61161d91508c8d3d10610461576104538183613c4d565b5f6115fb565b8791995061163e82918c8d3d10610461576104538183613c4d565b999150611497565b90925061166291975060603d811161051d5761050a8183613c4d565b50969096915f61146d565b7f0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf61143a565b50346105245780600319360112610524576040517f0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b6001600160a01b03168152602090f35b50346105245760203660031901126105245760209060ff906040906001600160a01b03611703613a27565b168152600884522054166040519015158152f35b5034610524576040366003190112610524576001600160401b0360043581811161089a57611749903690600401613b4d565b91602435908111610c8357611762903690600401613b4d565b61176d939193613bad565b61177881831461479f565b845b828110611785578580f35b6117908183876147e2565b35908115158092036117dc576117a78185876147e2565b356001600160a01b03811692908390036108925760019288526008602052604088209060ff801983541691161790550161177a565b8680fd5b5034610524578060031936011261052457546040516001600160a01b039091168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000029219dd400f2bf60e5a23d13be72b486d40388946001600160a01b03168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000012c0d2e69c309ba71d8ca55f61ce4395c01d15d16001600160a01b03168152602090f35b5034610524578060031936011261052457602060ff600554166040519015158152f35b5060e0366003190112610524576118c9613a27565b906118d2613a7f565b60a4356001600160401b03811161089a576118f1903690600401613b20565b9290936118fc613aa9565b9061190c60ff6005541615613ed2565b808215612085577f0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf955b8315612055577f00000000000000000000000029219dd400f2bf60e5a23d13be72b486d40388946001600160a01b0316975b6001546001600160a01b0316968515612045578960ff60035460a81c16945b61199360243588614667565b966001600160a01b031615612015575b6001600160a01b0382811690821603611ffe575b5050604051630240bc6b60e21b81529250606091508290506004816001600160a01b038b165afa801561125a57839086928791611fd8575b508315611f5b5750611a09916001600160701b0316614832565b918215611f4f575b60405163d21220a760e01b81526020816004816001600160a01b038c165afa908115610ab45790611a4b918791611f31575b50898561414f565b928315611f2957611a5b91613faf565b915b60443583101580611f1d575b15611ef2578115611ee757611ac16020845b60405163095ea7b360e01b81529283918291907f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b031660048401613cac565b0381896001600160a01b038e165af18015610ab457611ec8575b508115611ebd5760405163095ea7b360e01b815260208180611b2a856001600160a01b037f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc1660048401613cac565b0381898b5af18015610ab457906060939291611e9e575b508115611e9457611ba5845b8315611e8a57611b82835b8515611e845782905b600454938492611b756103e8968792613fbc565b049715611e7d5750613fbc565b04948a6040519687958695635a47ddc360e01b875242948d309560048a01614020565b0381867f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b03165af1801561040057611e4e575b5015611e27577f00000000000000000000000031a5a7add82b1091821be91dececc13974c76e36935b6040516370a0823160e01b808252306004830152959094906020866024816001600160a01b0386165afa958615610422578496611df3575b5060405163095ea7b360e01b81526001600160a01b0391909116916020908290818781611c718c8960048401613cac565b03926001600160a01b03165af1801561042257611dd4575b50803b1561089a57828091606460405180948193638dbdbe6d60e01b83528160048401528a60248401523360448401525af1801561040057908391611dc0575b50506040518581523060048201526020816024816001600160a01b0386165afa908115610400578391611d8e575b5080611d73575b5050604051938452306004850152602084602481855afa9081156103d75790611d40575b6020935080611d35575050604051908152f35b610f9f913390613cc7565b506020833d602011611d6b575b81611d5a60209383613c4d565b81010312610a6a5760209251611d22565b3d9150611d4d565b611d879133906001600160a01b0316613cc7565b5f80611cfe565b90506020813d602011611db8575b81611da960209383613c4d565b81010312610a6a57515f611cf7565b3d9150611d9c565b611dc990613c04565b610c2857815f611cc9565b611dec9060203d60201161108d5761107e8183613c4d565b505f611c89565b9095506020813d602011611e1f575b81611e0f60209383613c4d565b81010312610a6a5751945f611c40565b3d9150611e02565b7f000000000000000000000000f93d924b54955e113965e51641f360163709029793611c08565b611e6f9060603d606011611e76575b611e678183613c4d565b810190614005565b5050611bdf565b503d611e5d565b9050613fbc565b80611b61565b611b828193611b58565b611ba58194611b4d565b611eb69060203d60201161108d5761107e8183613c4d565b505f611b41565b611b2a602084611a7b565b611ee09060203d60201161108d5761107e8183613c4d565b505f611adb565b611ac1602082611a7b565b606460405162461bcd60e51b81526020600482015260046024820152634553543360e01b6044820152fd5b50606435811015611a69565b505083611a5b565b611f49915060203d8111610461576104538183613c4d565b5f611a43565b80925060011c91611a11565b611f6e92506001600160701b0316614832565b918215611fcc575b604051630dfe168160e01b81526020816004816001600160a01b038c165afa908115610ab45790611faf918791611f315750898561414f565b928315611fc457611fbf91613faf565b611a5d565b505083611a5d565b80925060011c91611f76565b9050611ff491925060603d60601161051d5761050a8183613c4d565b509190915f6119ef565b9061200a9596916143bd565b905f808089816119b7565b507f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03166119a3565b8960ff60035460a01c1694611987565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b031697611968565b7f0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b95611936565b50346105245780600319360112610524576120c5613bad565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5034610524576020366003190112610524576001600160a01b03906040908261212c613a27565b168152600760205220906113fd81835416916002816001860154169401541660405193849384916040919493606084019560018060a01b039283809216865216602085015216910152565b50346105245760a03660031901126105245760243590600435612198613a53565b916121a1613a69565b93608435928315158403610a6a576121c68195839760018060a01b0392839183614c50565b169360405193630dfe168160e01b9485815260209384826004818b5afa9182156126ae579086918a936126e8575b5081169116036126dd575b5050604051630240bc6b60e21b815293606085600481845afa948515610ab457869087966126b9575b5060018060701b03809116951692604051996318160ddd60e01b95868c52848c600481875afa9a8b156126ae57899b61267e575b8b809d5061227c8861116f6122758d61116f8688613fbc565b9387613fbc565b808210156126765750905b6122a4612299839e61116f8d86613fbc565b9e61116f8a85613fbc565b9b6122cd575b8d8d6113fd8e604051938493846040919493926060820195825260208201520152565b8b6122e18f9d9f9e9b9c9d6122e793613faf565b94613faf565b808411156124ae5750506040519081528481600481875afa998a156103d7579961248f575b506123178189614832565b91604051996378a051ad60e11b8b528360048c01521660248a01528389604481865afa988915612421575f9961245e575b509061235391613faf565b95604051908582528382600481865afa80156124215784925f9161242c575b509061116f612381928a613fbc565b9460046040518094819382525afa918215612421575f926123f0575b505085936123d2936123bd6123d8979461116f6123cc956113fd9b613fbc565b808210156123e8575090613f8e565b95613f8e565b94613f8e565b905f8080808080808080806122aa565b905090613f8e565b81819392933d831161241a575b6124078183613c4d565b81010312610524575051836123d261239d565b503d6123fd565b6040513d5f823e3d90fd5b919282813d8311612457575b6124428183613c4d565b8101031261052457505183919061116f612372565b503d612438565b90988482813d8311612488575b6124758183613c4d565b8101031261052457505197612353612348565b503d61246b565b6124a7919950843d8611610461576104538183613c4d565b975f61230c565b8092509c9a989b9c9796959493929097116124d6575b5050505050505050506113fd906123d8565b9091929394959697989a995060405163d21220a760e01b81528481600481875afa9889156103d75798612657575b5061250f8186614832565b91604051986378a051ad60e11b8a528360048b01521660248901528388604481865afa978815612421575f98612626575b509061254b91613faf565b96604051908582528382600481865afa80156124215784925f916125f4575b509061116f612579928a613fbc565b9460046040518094819382525afa918215612421575f926125c3575b505085936123d2936123bd6125b5979461116f6123cc956113fd9b613fbc565b905f808080808080806124c4565b81819392933d83116125ed575b6125da8183613c4d565b81010312610524575051836123d2612595565b503d6125d0565b919282813d831161261f575b61260a8183613c4d565b8101031261052457505183919061116f61256a565b503d612600565b90978482813d8311612650575b61263d8183613c4d565b810103126105245750519661254b612540565b503d612633565b61266f919850843d8611610461576104538183613c4d565b965f612504565b905090612287565b9a509a8481813d83116126a7575b6126968183613c4d565b81010312610a6a5751998b9061225c565b503d61268c565b6040513d8b823e3d90fd5b90506126d491955060603d811161051d5761050a8183613c4d565b5094905f612228565b985096505f806121ff565b8291935061270290873d8911610461576104538183613c4d565b92906121f4565b5034610524578060031936011261052457612722613bad565b4761272a5780f35b805460405147916001600160a01b031690602081016001600160401b0381118282101761279b578493849384809484604052525af1612767613c6e565b50156127705780f35b60405162461bcd60e51b815260206004820152600360248201526253544560e81b6044820152606490fd5b634e487b7160e01b5f52604160045260245ffd5b50346105245780600319360112610524576040517f0000000000000000000000007993620e9f66cb7cef1ffb755aa8ad8df4a102076001600160a01b03168152602090f35b50346105245780600319360112610524576040517f0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf6001600160a01b03168152602090f35b5034610524576020908160031936011261052457612855613a27565b9061285e613bad565b80546040516370a0823160e01b8152306004820152926001600160a01b0391821691168484602481845afa9283156103d757926128a9575b6128a09350613cc7565b60405160018152f35b91508383813d83116128d3575b6128c08183613c4d565b81010312610a6a576128a0925191612896565b503d6128b6565b5034610524576128fe6128ec36613aeb565b926001600160a01b0392909190614c50565b1690604051906318160ddd60e01b82526020938483600481875afa92831561105a5781936129e3575b50606060049460405195868092630240bc6b60e21b82525afa93841561105a5781946129bf575b50821561298b579161116f61298092604096946129788461116f60018060701b0380941685613fbc565b961690613fbc565b908351928352820152f35b60405162461bcd60e51b815260048101869052600c60248201526b4e6f206c697175696469747960a01b6044820152606490fd5b90506129da91935060603d811161051d5761050a8183613c4d565b5092905f61294e565b9392508484813d8311612a0e575b6129fb8183613c4d565b81010312610a6a57925191926060612927565b503d6129f1565b503461052457602036600319011261052457612a2f613a27565b612a37613bad565b600680546001600160a01b03928316929190845b818110612a70578585815260076020525f600260408320828155826001820155015580f35b612a7981613b7d565b509085856002809401541614612a94575b6001915001612a4b565b5f19838101848111612b6557612aa990613b7d565b50612ab383613b7d565b612b5157818103612b14575b505084548015612b005701612ad381613b7d565b612aed57600193815f809355828682015501558455612a8a565b634e487b7160e01b5f525f60045260245ffd5b634e487b7160e01b89526031600452602489fd5b878580828554169360018060a01b031994858254161781556001848183019188015416868254161790550193015416908254161790555f80612abf565b634e487b7160e01b8a5260048a905260248afd5b634e487b7160e01b89526011600452602489fd5b50346105245780600319360112610524576020600454604051908152f35b50346105245780600319360112610524576040517f000000000000000000000000f93d924b54955e113965e51641f36016370902976001600160a01b03168152602090f35b50346105245780600319360112610524576040517f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b03168152602090f35b50346105245780600319360112610524576040517f0000000000000000000000002da25e7446a70d7be65fd4c053948becaa6374c86001600160a01b03168152602090f35b50346105245780600319360112610524576002546040516001600160a01b039091168152602090f35b503461052457612c9e36613ab8565b9192909115612fbe577f0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b915b604051630240bc6b60e21b81526001600160a01b03938416939092606084600481885afa93841561105a5781908295612f9a575b50604051630dfe168160e01b81526001600160701b0391821695909116936020939192909184846004818b5afa938415610468578294612f7b575b5060405163d21220a760e01b815298858a6004818c5afa998a1561040057839a612f58575b5081809116941684149081998215612f4c575b505015612f1757508615612f0d57612d898186614832565b90604051926378a051ad60e11b8452826004850152602484015283836044818a5afa928315612421575f93612edc575b5090612dc491613faf565b8615612ed55780965b15612ecd5750935b6040516318160ddd60e01b808252948382600481865afa80156124215784925f91612e9b575b509061116f612e0a928a613fbc565b9460046040518094819382525afa918215612421575f92612e6a575b50506113fd929161116f612e3a9286613fbc565b80821015612e625750915b604051938493846040919493926060820195825260208201520152565b905091612e45565b81819392933d8311612e94575b612e818183613c4d565b810103126105245750518161116f612e26565b503d612e77565b919282813d8311612ec6575b612eb18183613c4d565b8101031261052457505183919061116f612dfb565b503d612ea7565b905093612dd5565b8196612dcd565b90928482813d8311612f06575b612ef38183613c4d565b8101031261052457505191612dc4612db9565b503d612ee9565b612d898185614832565b60405162461bcd60e51b815260048101859052600d60248201526c34b73b30b634b2103a37b5b2b760991b6044820152606490fd5b16841490505f80612d71565b82919a50612f738291883d8a11610461576104538183613c4d565b9a9150612d5e565b612f93919450853d8711610461576104538183613c4d565b925f612d39565b9050612fb591945060603d811161051d5761050a8183613c4d565b5093905f612cfe565b7f0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf91612cca565b5034610524578060031936011261052457602060ff60035460a81c166040519015158152f35b5034610524578060031936011261052457613024613bad565b60055460ff80821615169060ff19161760055580f35b50346105245780600319360112610524576006546130578161406b565b906130656040519283613c4d565b8082526006835260209182810191847ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f845b8383106130fd57505050506040519280840191818552518092526040840192945b8281106130c55784840385f35b855180516001600160a01b039081168652818401518116868501526040918201511690850152948101946060909301926001016130b8565b60038760019260409a9997989a5161311481613c17565b848060a01b038087541682528086880154168483015260028701541660408201528152019201920191909694939596613097565b50346105245780600319360112610524576003546040516001600160a01b039091168152602090f35b50608036600319011261052457613186613a27565b61318e613a3d565b91606435906131a260ff6005541615613ed2565b6044359284926001600160a01b038183826131bd8883614c50565b16918287528360209a60078c528180600160408c20015416986131e08d82614667565b506131eb8584614667565b50161561348a575b1615613460575b604051630dfe168160e01b81528a81600481875afa90811561342c578891613443575b5084808416911603613437575b508216936040519663095ea7b360e01b978881528a818061324f8d8760048401613cac565b03818b8b5af1801561342c578b92879492879261340f575b5016986132806040519485938493845260048401613cac565b0381898b5af18015610ab4579089949392916133f2575b5085526007835260408520541660045491856103e86132ba81610ece878d613fbc565b604051636cfa229360e01b81529a8b96879586946132de9404923360048701613fcf565b03925af19384156104685782946133c3575b506040516370a0823160e01b80825230600483015291908681602481855afa908115610422578491613396575b5080613384575b50506040519081523060048201528481602481865afa9182156103d75791613357575b5080611d35575050604051908152f35b90508381813d831161337d575b61336e8183613c4d565b81010312610a6a57515f613347565b503d613364565b61338f913390613cc7565b5f80613324565b90508681813d83116133bc575b6133ad8183613c4d565b81010312610a6a57515f61331d565b503d6133a3565b9093508481813d83116133eb575b6133db8183613c4d565b81010312610a6a5751925f6132f0565b503d6133d1565b61340890853d871161108d5761107e8183613c4d565b505f613297565b61342590853d871161108d5761107e8183613c4d565b505f613267565b6040513d8a823e3d90fd5b9790969093508261322a565b61345a91508b3d8d11610461576104538183613c4d565b5f61321d565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38841697506131fa565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38821693506131f3565b5060e0366003190112610524576134c9613a27565b6134d1613a3d565b6134d9613aa9565b6134e860ff6005541615613ed2565b8383918394815f14613a00577f0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf915b156139d9577f00000000000000000000000031a5a7add82b1091821be91dececc13974c76e36945b60443561354c8184614667565b9161355960643582614667565b936001600160a01b0316156139a8575b6001600160a01b031615613977575b60405163095ea7b360e01b815290602090829081906135c4907f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b031660048401613cac565b0381886001600160a01b038b165af1801561125a57613958575b5060405163095ea7b360e01b8152916020838061362a6064357f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b031660048401613cac565b0381886001600160a01b038d165af191821561125a5761367693606093613939575b50604051635a47ddc360e01b815293849283924291309160a43591608435918f8e60048a01614020565b0381867f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b03165af180156104005761391b575b506040516370a0823160e01b8082523060048301529490916001600160a01b039182169116602083602481845afa9283156104225784936138e6575b50602061370e936040518095819263095ea7b360e01b83528660048401613cac565b038187855af1908115610422576024936020926138c9575b50604051938480928982523060048301525afa918215610400578392613895575b50803b1561089a57606483926040519485938492638dbdbe6d60e01b845282600485015260248401523360448401525af1801561125a57613882575b506040518281523060048201526020816024816001600160a01b0386165afa90811561125a578591613850575b5080613835575b50506040519081523060048201526020816024816001600160a01b0386165afa908115610400578391613803575b50806137ef578280f35b610a3d9133906001600160a01b0316613cc7565b90506020813d60201161382d575b8161381e60209383613c4d565b81010312610a6a57515f6137e5565b3d9150613811565b6138499133906001600160a01b0316613cc7565b5f806137b7565b90506020813d60201161387a575b8161386b60209383613c4d565b81010312610a6a57515f6137b0565b3d915061385e565b61388e90949194613c04565b925f613783565b9091506020813d6020116138c1575b816138b160209383613c4d565b8101031261089a5751905f613747565b3d91506138a4565b6138df90833d851161108d5761107e8183613c4d565b505f613726565b92506020833d602011613913575b8161390160209383613c4d565b81010312610c835791519160206136ec565b3d91506138f4565b6139329060603d8111611e7657611e678183613c4d565b50506136b0565b6139519060203d60201161108d5761107e8183613c4d565b505f61364c565b6139709060203d60201161108d5761107e8183613c4d565b505f6135de565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03169750613578565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03169650613569565b7f000000000000000000000000f93d924b54955e113965e51641f36016370902979461353f565b7f0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b91613517565b600435906001600160a01b0382168203610a6a57565b602435906001600160a01b0382168203610a6a57565b604435906001600160a01b0382168203610a6a57565b606435906001600160a01b0382168203610a6a57565b608435906001600160a01b0382168203610a6a57565b35906001600160a01b0382168203610a6a57565b60c435908115158203610a6a57565b6060906003190112610a6a576004356001600160a01b0381168103610a6a5790602435906044358015158103610a6a5790565b6060906003190112610a6a576001600160a01b03906004358281168103610a6a57916024359081168103610a6a579060443590565b9181601f84011215610a6a578235916001600160401b038311610a6a5760208381860195010111610a6a57565b9181601f84011215610a6a578235916001600160401b038311610a6a576020808501948460051b010111610a6a57565b600654811015613b995760065f52600360205f20910201905f90565b634e487b7160e01b5f52603260045260245ffd5b5f546001600160a01b03163303613bc057565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160401b03811161279b57604052565b606081019081106001600160401b0382111761279b57604052565b604081019081106001600160401b0382111761279b57604052565b90601f801991011681019081106001600160401b0382111761279b57604052565b3d15613ca7573d906001600160401b03821161279b5760405191613c9c601f8201601f191660200184613c4d565b82523d5f602084013e565b606090565b6001600160a01b039091168152602081019190915260400190565b613cfc613d019392613cee60405194859263a9059cbb60e01b602085015260248401613cac565b03601f198101845283613c4d565b613d1b565b565b90816020910312610a6a57518015158103610a6a5790565b604051613d78916001600160a01b0316613d3482613c32565b5f806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af1613d72613c6e565b91613e00565b805190828215928315613de8575b50505015613d915750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b613df89350820181019101613d03565b5f8281613d86565b91929015613e625750815115613e14575090565b3b15613e1d5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015613e755750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401525f935b828510613eb9575050604492505f838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350613e97565b15613ed957565b60405162461bcd60e51b815260206004820152600660248201526514185d5cd95960d21b6044820152606490fd5b8115613f11570490565b634e487b7160e01b5f52601260045260245ffd5b90816020910312610a6a57516001600160a01b0381168103610a6a5790565b51906001600160701b0382168203610a6a57565b90816060910312610a6a57613f6c81613f44565b916040613f7b60208401613f44565b92015163ffffffff81168103610a6a5790565b91908201809211613f9b57565b634e487b7160e01b5f52601160045260245ffd5b91908203918211613f9b57565b81810292918115918404141715613f9b57565b9391959492909560c085019660018060a01b03168552602085015260408401526060830152608082015260a0600f60fc1b910152565b90816060910312610a6a578051916040602083015192015190565b9490989796929361010096929461012087019a60018060a01b03968780921689521660208801525f60408801526060870152608086015260a085015260c08401521660e08201520152565b6001600160401b03811161279b5760051b60200190565b1561408957565b60405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b2103a37b5b2b724b760891b6044820152606490fd5b90816020910312610a6a575160ff81168103610a6a5790565b60ff166012039060ff8211613f9b57565b60ff16604d8111613f9b57600a0a90565b91935f9390929091614115916001600160701b0316614832565b938461411f575050565b61412b9293508461414f565b90565b805115613b995760200190565b8051821015613b995760209160051b010190565b91929060409182519161416183613c32565b6001948584525f5b60208082101561419a5786516020929161418282613c17565b5f82525f818301525f89830152828801015201614169565b5050929590939491956141ac8161412e565b516001600160a01b039586169081905260209290919086846141cd8461412e565b5101911690525f876141de8361412e565b5101525f83877f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc169360448a518094819363095ea7b360e01b8352886004840152811960248401525af180156143b357614396575b5090935f9485928851978893631e82ecdb60e31b855260a4850190600486015287602486015260a0604486015282518091528660c4860193019186905b89898484106143615750505050505083838092306064830152600f60fc1b608483015203925af193849184956142d1575b50506142af57505050505f90565b825111156142bd5750015190565b634e487b7160e01b81526032600452602490fd5b909194503d8085843e6142e48184613c4d565b820191818184031261135a578051906001600160401b03821161089657019180601f8401121561135a5782516143198161406b565b9361432689519586613c4d565b818552838086019260051b8201019283116117dc578301905b8282106143525750505050925f806142a1565b8151815290830190830161433f565b8551805184168852808201518416888301528f015115158f8801528c99508d9850606090960195949094019390910190614270565b6143ac90843d861161108d5761107e8183613c4d565b505f614233565b88513d5f823e3d90fd5b9295949091939560018060a01b038094169060409788519263095ea7b360e01b90818552602096856143f460049b878d8401613cac565b039588815f98818a875af1801561465d57908a9291614640575b5016938b51966370a0823160e01b94858952308c8a015260249a8a8a8d818b5afa998a1561463557908f9695949392918a9b6145f7575b508316808a5260088c529589205460ff16156145bc5791818f8a9485948592519384928337810182815203925af161447b613c6e565b501561457f5760448892878c938f5196879586948552840152818d8401525af180156145755790869291614558575b50868a51809481938252308b8301525afa91821561454d57809261451b575b5050906144d591613faf565b9485156144e25750505050565b5162461bcd60e51b8152928301526017908201527622b93937b91029bbb0b83834b733902a37b5b2b739901960491b6044820152606490fd5b9091508382813d8311614546575b6145338183613c4d565b810103126105245750516144d55f6144c9565b503d614529565b8851903d90823e3d90fd5b61456e90833d851161108d5761107e8183613c4d565b505f6144aa565b8a513d86823e3d90fd5b508a5162461bcd60e51b8152808a018890526017818a0152764572726f72205377617070696e6720546f6b656e73203160481b6044820152606490fd5b508d5162461bcd60e51b8152808d018b90526015818d01527415185c99d95d081b9bdd08105d5d1a1bdc9a5e9959605a1b6044820152606490fd5b8c80929c5081939495969798503d831161462e575b6146168183613c4d565b810103126108725751988e95949392919060ff614445565b503d61460c565b508e513d8a823e3d90fd5b614656908a3d8c1161108d5761107e8183613c4d565b505f61440e565b8d513d89823e3d90fd5b6001600160a01b03908116908115614705575081156146c9576040516323b872dd60e01b60208201523360248201523060448201526064808201849052815260a08101916001600160401b0383118284101761279b5761412b92604052613d1b565b60405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a59081d1bdad95b88185b5bdd5b9d60621b6044820152606490fd5b915050341561476c577f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3816803b15610a6a575f60049160405192838092630d0e30db60e41b825234905af180156124215761475f57503490565b61476890613c04565b3490565b60405162461bcd60e51b815260206004820152600b60248201526a139bc8195d1a081cd95b9d60aa1b6044820152606490fd5b156147a657565b60405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c84092dce0eae840d8cadccee8d60631b6044820152606490fd5b9190811015613b995760051b0190565b60018060a01b0360406002828551169360018060a01b03199485825416178155600181018460208801511686825416179055019301511690825416179055565b90623cda2090818102918183041490151715613f9b57623cda299081830283159284820414831715613f9b5761486e6148749161487993613f8e565b84613fbc565b614d89565b906107cd808402938404141715613f9b576107ca9161489791613faf565b0490565b90939695929491946148b18661116f8785613fbc565b6040805163313ce56760e01b8082529891956001600160a01b039485169560209593949093919286816004818b5afa908115614acf5761030561490593926148ff925f91614b0957506140d9565b90613f07565b9b16968651916318160ddd60e01b835285836004818c5afa9283156143b3575f93614ad9575b509060049186849a8a5194858092637464fc3d60e01b82525afa928315614acf579187969593918b95935f93614a92575b50826149ed575b50505050614975929161116f91613fbc565b96600485518095819382525afa9283156149e457506149ab61030561116f946149b69796946149b1945f926149c75750506140d9565b88613fbc565b613fbc565b808210156149c2575090565b905090565b6149dd9250803d106103d0576103c18183613c4d565b5f80610386565b513d5f823e3d90fd5b6149fd614a0892614a0292613fbc565b614b20565b91614b20565b90818111614a17575b80614963565b8193959650614a27929450613faf565b61271080820290828204811483151715613f9b57614a5f93614a53614a589261116f9404948592613f8e565b613faf565b9184613fbc565b9081614a72575b91818594938993614a11565b614975929750614a8785949261116f92613f8e565b979250819350614a66565b80939294965088919597983d8311614ac8575b614aaf8183613c4d565b810103126105245750918993918796959351915f61495c565b503d614aa5565b89513d5f823e3d90fd5b90928682813d8311614b02575b614af08183613c4d565b8101031261052457505191600461492b565b503d614ae6565b6103fa91508a3d8c116103d0576103c18183613c4d565b8015614c4b576149b6815f908360801c80614c3f575b508060401c80614c32575b508060201c80614c25575b508060101c80614c18575b508060081c80614c0b575b508060041c80614bfe575b508060021c80614bf1575b50600191828092811c614bea575b1c1b614b928185613f07565b01811c614b9f8185613f07565b01811c614bac8185613f07565b01811c614bb98185613f07565b01811c614bc68185613f07565b01811c614bd38185613f07565b01811c614be08185613f07565b01901c8092613f07565b0181614b86565b600291509101905f614b78565b600491509101905f614b6d565b600891509101905f614b62565b601091509101905f614b57565b602091509101905f614b4c565b604091509101905f614b41565b9150506080905f614b36565b505f90565b6001600160a01b039291839081831615614d5f575b81811615614d36575b6040516306801cc360e41b815292821660048401521660248201525f60448201526020816064817f0000000000000000000000002da25e7446a70d7be65fd4c053948becaa6374c887165afa80156124215783915f91614d18575b501691825f526007602052600260405f2001541615614ce457565b60405162461bcd60e51b815260206004820152600c60248201526b24b73b30b634b2102830b4b960a11b6044820152606490fd5b614d30915060203d8111610461576104538183613c4d565b5f614cc9565b50807f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3816614c6e565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3882169250614c65565b8015614c4b57600181600160801b811015614ead575b614e4f614e42614e35614e28614e1b614e0e6149b6976008614e5c98600160401b811015614ea0575b640100000000811015614e93575b62010000811015614e87575b610100811015614e7b575b6010811015614e6e575b1015614e66575b614e08818b613f07565b90613f8e565b60011c614e08818a613f07565b60011c614e088189613f07565b60011c614e088188613f07565b60011c614e088187613f07565b60011c614e088186613f07565b60011c614e088185613f07565b60011c8092613f07565b60011b614dfe565b60041c9160021b91614df7565b811c9160041b91614ded565b60101c91811b91614de2565b60201c9160101b91614dd6565b60401c9160201b91614dc8565b50600160401b9050608082901c614d9f56fea264697066735822122066d7c52dc80b5e77105af9c88936ed937c2d48f87079a1e44f47c5b88fa65a1864736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc00000000000000000000000029219dd400f2bf60e5a23d13be72b486d40388940000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf00000000000000000000000019d04a9bd2aeee1d1b9e86a05afeadb4c9c6e395000000000000000000000000c7f449eb12f20d66e33631ad5176993ccacb6acf00000000000000000000000012c0d2e69c309ba71d8ca55f61ce4395c01d15d10000000000000000000000007993620e9f66cb7cef1ffb755aa8ad8df4a10207000000000000000000000000f93d924b54955e113965e51641f360163709029700000000000000000000000031a5a7add82b1091821be91dececc13974c76e36
-----Decoded View---------------
Arg [0] : _router (address): 0x1D368773735ee1E678950B7A97bcA2CafB330CDc
Arg [1] : _usdc (address): 0x29219dd400f2Bf60E5a23d13Be72B486D4038894
Arg [2] : _pairToSonic (address): 0x5b4747849F72bf9D0E673955842FE9CAcd69B18B
Arg [3] : _pairToUsdc (address): 0x1844F04a2E2F0aEF0f72BA3eF9D94aC9B07fa8bf
Arg [4] : _safeHavenSonic (address): 0x19d04a9Bd2AeEE1D1b9e86A05AFeAdB4C9C6E395
Arg [5] : _safeHavenUsdc (address): 0xC7F449EB12f20D66e33631ad5176993CCacb6ACF
Arg [6] : _treasurySonic (address): 0x12c0D2E69C309bA71D8Ca55F61Ce4395c01d15d1
Arg [7] : _treasuryUsdc (address): 0x7993620E9F66cB7cEF1fFB755aa8Ad8df4A10207
Arg [8] : _stakingSonic (address): 0xF93d924b54955E113965E51641F3601637090297
Arg [9] : _stakingUsdc (address): 0x31a5a7adD82b1091821BE91Dececc13974c76e36
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc
Arg [1] : 00000000000000000000000029219dd400f2bf60e5a23d13be72b486d4038894
Arg [2] : 0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b
Arg [3] : 0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf
Arg [4] : 00000000000000000000000019d04a9bd2aeee1d1b9e86a05afeadb4c9c6e395
Arg [5] : 000000000000000000000000c7f449eb12f20d66e33631ad5176993ccacb6acf
Arg [6] : 00000000000000000000000012c0d2e69c309ba71d8ca55f61ce4395c01d15d1
Arg [7] : 0000000000000000000000007993620e9f66cb7cef1ffb755aa8ad8df4a10207
Arg [8] : 000000000000000000000000f93d924b54955e113965e51641f3601637090297
Arg [9] : 00000000000000000000000031a5a7add82b1091821be91dececc13974c76e36
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in S
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.