Source Code
Overview
S Balance
S Value
$0.00Latest 25 from a total of 3,016 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Pair Details | 38059134 | 198 days ago | IN | 0 S | 0.00915035 | ||||
| Single Bond | 37884964 | 199 days ago | IN | 0 S | 0.24168738 | ||||
| Single Bond | 37884518 | 199 days ago | IN | 6 S | 0.09179499 | ||||
| Swap | 37884376 | 199 days ago | IN | 0 S | 0.61830038 | ||||
| Duo Bond | 37883965 | 199 days ago | IN | 0 S | 0.11956631 | ||||
| Single Bond | 37883617 | 199 days ago | IN | 100 S | 0.09937639 | ||||
| Single Bond | 37881540 | 199 days ago | IN | 33 S | 0.19542915 | ||||
| Swap | 37881330 | 199 days ago | IN | 0 S | 0.69230621 | ||||
| Swap | 37881322 | 199 days ago | IN | 0 S | 0.86962411 | ||||
| Duo Add Stake | 37880501 | 199 days ago | IN | 1.16104892 S | 0.0776366 | ||||
| Duo Add Stake | 37880186 | 199 days ago | IN | 0 S | 0.11641898 | ||||
| Swap | 37879588 | 199 days ago | IN | 0 S | 0.6876047 | ||||
| Single Add Stake | 37878180 | 199 days ago | IN | 3,342 S | 0.1264575 | ||||
| Single Add Stake | 37878135 | 199 days ago | IN | 3,342 S | 0.14081568 | ||||
| Duo Add Stake | 37877803 | 199 days ago | IN | 55.24801723 S | 0.07048219 | ||||
| Duo Add Stake | 37877442 | 199 days ago | IN | 24.72368158 S | 0.05741551 | ||||
| Duo Add Stake | 37876577 | 199 days ago | IN | 0 S | 0.05916206 | ||||
| Duo Bond | 37876449 | 199 days ago | IN | 23 S | 0.13866736 | ||||
| Single Add Stake | 37875975 | 199 days ago | IN | 2,300 S | 0.09704801 | ||||
| Duo Bond | 37875473 | 199 days ago | IN | 0 S | 0.05272306 | ||||
| Swap | 37875355 | 199 days ago | IN | 0 S | 0.7463985 | ||||
| Duo Add Stake | 37874611 | 199 days ago | IN | 1,357.80991758 S | 0.07719305 | ||||
| Duo Add Stake | 37874068 | 199 days ago | IN | 0 S | 0.13167808 | ||||
| Single Add Stake | 37873664 | 199 days ago | IN | 10 S | 0.13380416 | ||||
| Duo Add Stake | 37873353 | 199 days ago | IN | 0 S | 0.0385521 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 37884518 | 199 days ago | 6 S | ||||
| 37884376 | 199 days ago | 6.54607496 S | ||||
| 37884376 | 199 days ago | 6.54607496 S | ||||
| 37883617 | 199 days ago | 100 S | ||||
| 37881540 | 199 days ago | 33 S | ||||
| 37881322 | 199 days ago | 33.55747783 S | ||||
| 37881322 | 199 days ago | 33.55747783 S | ||||
| 37880501 | 199 days ago | 1.16104892 S | ||||
| 37878180 | 199 days ago | 3,342 S | ||||
| 37878135 | 199 days ago | 3,342 S | ||||
| 37877803 | 199 days ago | 55.24801723 S | ||||
| 37877442 | 199 days ago | 24.72368158 S | ||||
| 37876449 | 199 days ago | 23 S | ||||
| 37875975 | 199 days ago | 2,300 S | ||||
| 37874611 | 199 days ago | 1,357.80991758 S | ||||
| 37873664 | 199 days ago | 10 S | ||||
| 37873194 | 199 days ago | 14 S | ||||
| 37871888 | 199 days ago | 19 S | ||||
| 37871715 | 199 days ago | 22,500 S | ||||
| 37871620 | 199 days ago | 5.56823264 S | ||||
| 37870435 | 199 days ago | 3,100 S | ||||
| 37870232 | 199 days ago | 5,000 S | ||||
| 37869812 | 199 days ago | 160 S | ||||
| 37869384 | 199 days ago | 511.82127052 S | ||||
| 37869275 | 199 days ago | 509.3609674 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);
uint256 length = pairsDetails.length;
for (uint256 i = 0; i < length; ) {
ISafeHaven safeHaven = ISafeHaven(
pairDetails[pairsDetails[i].pair].safeHaven
);
safeHaven.processExpiredBonds();
unchecked {
i++;
}
}
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
6102008060405234620005945761014081620058de80380380916200002582856200091d565b83398101031262000594576200003b8162000955565b906200004a6020820162000955565b90620000596040820162000955565b92620000686060830162000955565b92620000776080840162000955565b6200008560a0850162000955565b906200009460c0860162000955565b93620000a360e0870162000955565b95620000c2610120620000ba610100840162000955565b920162000955565b5f8054336001600160a01b03198216811783556040519395602093859360049385939290916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a361038483556001600160a01b031660c08190526315ab88c960e31b82525afa908115620005a1575f91620008db575b506001600160a01b0390811660805260c05160405163c45a015560e01b81529160209183916004918391165afa908115620005a1575f9162000882575b506001600160a01b0390811660e0529889166101208190529789166101005288166101605287166101405286166101805285166101a05290931660a0526101c0929092526101e091909152604051630dfe168160e01b815290602090829060049082905afa908115620005a1575f9162000840575b506080516001600160a01b0391821691160362000712576101205160405163d21220a760e01b815290602090829060049082906001600160a01b03165afa908115620005a1575f91620006d0575b50600180546001600160a01b0319166001600160a01b0392831617905561012051604051630dfe168160e01b81529160209183916004918391165afa908115620005a1575f916200068e575b50600280546001600160a01b0319166001600160a01b03929092169190911790556003805460ff60a01b1916600160a01b1790555b61010051604051630dfe168160e01b815290602090829060049082906001600160a01b03165afa908115620005a1575f916200064c575b5060a0516001600160a01b03918216911603620005ac5761010051604051630dfe168160e01b815290602090829060049082906001600160a01b03165afa908115620005a1575f916200055b575b5060038054600161ff0160a01b0319166001600160a01b0390921691909117600160a81b1790555b60086020527fcdc0045d0c85c04319db18131b80cbf7a91d1c2c18bd319ce33b2d123b3651d78054600160ff199182168117909255736352a56caadc4f1e25cd6c75970fa768a3304e645f527fda9f66dcbe51b40ee750bda58e559ea672af32b3b690011eff2ef2822fa74ffb80549091169091179055604051614f7390816200096b82396080518181816109720152818161134701528181611378015281816113a9015281816113f201528181612096015281816120d5015281816134e00152818161350a015281816139f701528181613a280152818161478e01528181614db80152614ddf015260a05181818161189b01526119bc015260c051818181611b0e01528181611b7f01528181611c2801528181612c700152818161361101528181613677015281816136f90152614264015260e051818181612cb50152614d150152610100518181816116ed01528181611993015281816128880152818161303e0152613574015261012051818181611498015281816117270152818161210501528181612d270152613a8001526101405181818161064201528181611c65015261359c015261016051818181611ea701528181612c2b0152613a59015261018051816108dd01526101a0518161053d01526101c051816118e001526101e051816128430152f35b90506020813d60201162000598575b8162000579602093836200091d565b8101031262000594576200058d9062000955565b5f6200034a565b5f80fd5b3d91506200056a565b6040513d5f823e3d90fd5b6101005160405163d21220a760e01b815290602090829060049082906001600160a01b03165afa908115620005a1575f916200060a575b50600380546001600160a01b0319166001600160a01b039290921691909117905562000372565b90506020813d60201162000643575b8162000628602093836200091d565b8101031262000594576200063c9062000955565b5f620005e3565b3d915062000619565b90506020813d60201162000685575b816200066a602093836200091d565b8101031262000594576200067e9062000955565b5f620002fc565b3d91506200065b565b90506020813d602011620006c7575b81620006ac602093836200091d565b810103126200059457620006c09062000955565b5f62000290565b3d91506200069d565b90506020813d60201162000709575b81620006ee602093836200091d565b810103126200059457620007029062000955565b5f62000244565b3d9150620006df565b61012051604051630dfe168160e01b815290602090829060049082906001600160a01b03165afa908115620005a1575f91620007fe575b50600180546001600160a01b0319166001600160a01b039283161790556101205160405163d21220a760e01b81529160209183916004918391165afa908115620005a1575f91620007bc575b50600280546001600160a01b0319166001600160a01b0392909216919091179055620002c5565b90506020813d602011620007f5575b81620007da602093836200091d565b810103126200059457620007ee9062000955565b5f62000795565b3d9150620007cb565b90506020813d60201162000837575b816200081c602093836200091d565b810103126200059457620008309062000955565b5f62000749565b3d91506200080d565b90506020813d60201162000879575b816200085e602093836200091d565b810103126200059457620008729062000955565b5f620001f6565b3d91506200084f565b989796959493929190506020893d602011620008d2575b81620008a8602093836200091d565b810103126200059457600499620008c160209a62000955565b919293949596979899509962000181565b3d915062000899565b90506020813d60201162000914575b81620008f9602093836200091d565b8101031262000594576200090d9062000955565b5f62000144565b3d9150620008ea565b601f909101601f19168101906001600160401b038211908210176200094157604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b0382168203620005945756fe6080604052600436101561001a575b3615610018575f80fd5b005b5f803560e01c8062c61fbf146135325780630730adbb146131ef57806309b67301146131c6578063103841c6146130b85780631385d24c1461308957806324381a53146130635780632585d64614612d0d5780632ca8847f14612ce45780632dd3100014612c9f57806332fe7b2614612c5a5780633d05cbd314612c155780633e032a3b14612bf75780633f78817014612a93578063457ea7561461295857806349df728c146128b7578063527a53ad14612872578063551950c81461282d578063603f1afb1461278757806364cc89be146121f557806371065a9314612183578063715018a61461212a5780637224f3221461193257806375f12b211461190f57806376cbff3b146118ca57806389a30271146118855780638da5cb5b1461185e5780639735a634146117955780639779d1a61461175657806399116aba14611711578063993a37191461147f5780639c05a4cb14611421578063ad5c4648146113dc578063bc0ca6a514610d28578063bec872b014610d05578063bf8094621461090c578063d1090dc2146108c7578063de9a71291461089e578063e0a6dfa014610697578063e512073814610671578063f066de4b1461062c578063f2fde38b1461056c578063f355355b146105275763fb21cd01146101fd575061000e565b346105245761020b36613b69565b92906102178184614cce565b604051630240bc6b60e21b8152946001600160a01b038083169492939291606088600481895afa9283156103d757809881946104ed575b5060405196630dfe168160e01b8089526020998a8a600481865afa998a1561042257908b9291859b6104ca575b5086169986168a148015610473575b61029390614100565b60046040518094819382525afa908115610468579382918996958295949161043b575b50168514928315610434578a935b1561042d5784925b6040518b8160048163313ce56760e01b9b8c82525afa9081156104225760049261030a6103058f9461031094899161040b575b50614157565b614168565b9061403a565b9a604051928380928b82525afa9081156104005761033c6103058d9361034c9387916103e35750614157565b6001600160701b0396871661403a565b9660046040518094819382528b165afa9182156103d75761039e999795938561038d61030560409f9c9a98968f96849761039497926103aa575b5050614157565b911661403a565b9216961694614919565b90918351928352820152f35b6103c99250803d106103d0575b6103c18183613ccb565b81019061413e565b8f80610386565b503d6103b7565b604051903d90823e3d90fd5b6103fa9150853d87116103d0576103c18183613ccb565b5f6102ff565b6040513d85823e3d90fd5b6103fa9150863d88116103d0576103c18183613ccb565b6040513d86823e3d90fd5b8a926102cc565b84936102c4565b61045b91508b3d8d11610461575b6104538183613ccb565b810190613fa3565b5f6102b6565b503d610449565b6040513d84823e3d90fd5b5060405163d21220a760e01b81529091508a81600481865afa90811561042257868c93926102939287916104ad575b50168b14905061028a565b6104c49150853d8711610461576104538183613ccb565b5f6104a2565b87919b506104e58291853d8711610461576104538183613ccb565b9b915061027b565b90935061051291985060603d811161051d575b61050a8183613ccb565b810190613fd6565b50979097925f61024e565b503d610500565b80fd5b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461052457602036600319011261052457610586613aa5565b61058e613c2b565b6001600160a01b039081169081156105d8575f548260018060a01b03198216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034610524578060031936011261052457602060ff60035460a01c166040519015158152f35b5034610524576040366003190112610524576001600160401b0360043581811161089a576106c9903690600401613bcb565b90916024928335828111610896573660238201121561089657806004013592831161089657606090858285028201019036821161089257610708613c2b565b610711866140e9565b9361071f6040519586613ccb565b8685526020968786019060051b82019136831161088e578890915b838310610876575050505061074e856140e9565b9461075c6040519687613ccb565b855286018585015b828210610824575050505080519261077e8351851461481d565b855b84811061078b578680f35b6107bc61079882866141b9565b516001600160a01b036107ab84876141b9565b511689526007845260408920614870565b6107c681856141b9565b51906006918254600160401b811015610811576107ea906001948582019055613bfb565b6107fe57906107f891614870565b01610780565b634e487b7160e01b8a5260048a9052888afd5b634e487b7160e01b8a526041600452888afd5b83823603126108725786849160405161083c81613c95565b61084585613b13565b8152610852838601613b13565b8382015261086260408601613b13565b6040820152815201910190610764565b8880fd5b819061088184613b13565b815201910190889061073a565b8a80fd5b8780fd5b8580fd5b8280fd5b50346105245780600319360112610524576001546040516001600160a01b039091168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5060a036600319011261052457610921613aa5565b610929613abb565b906064356001600160401b038111610d0157610949903690600401613b9e565b90610952613afd565b9383928190610963604435876146e5565b93889760018060a01b039788807f000000000000000000000000000000000000000000000000000000000000000016961690868214610cf8575b8916610cda5750939550859487946109b99392915b858961443b565b5060065487805b828110610c69575050501693818514610aca575b50506040516370a0823160e01b808252306004830152602093909216908381602481855afa908115610abf578691610a92575b5080610a80575b50506040519081523060048201528181602481865afa918215610422578492610a4e575b505080610a3d578280f35b610a48913390613d45565b5f808280f35b90809250813d8311610a79575b610a658183613ccb565b81010312610a7557515f80610a32565b5f80fd5b503d610a5b565b610a8b913390613d45565b5f80610a0e565b90508381813d8311610ab8575b610aa98183613ccb565b81010312610a7557515f610a07565b503d610a9f565b6040513d88823e3d90fd5b604051866370a0823160e01b918281523060048201526020938482602481895afa918215610400578392610c37575b5015610b805750506040519081523060048201528181602481865afa918215610b75578792610b47575b505080610b35575b50505b5f806109d4565b610b40913390613d45565b5f80610b2b565b90809250813d8311610b6e575b610b5e8183613ccb565b81010312610a7557515f80610b23565b503d610b54565b6040513d89823e3d90fd5b80925093909293610b95575b50505050610b2e565b803b1561089a57828091602460405180948193632e1a7d4d60e01b83528760048401525af1908115610400578391610c1f575b50808092335af1610bd7613cec565b5015610be557848180610b8c565b6064906040519062461bcd60e51b825260048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152fd5b610c2890613c82565b610c3357815f610bc8565b5080fd5b925090508382813d8111610c62575b610c508183613ccb565b81010312610a7557889151905f610af9565b503d610c46565b909192936002610c7883613bfb565b500154168252600760205286604083205416803b1561089a5782809160046040518094819363b4879beb60e01b83525af1908115610400578391610cc6575b505060010191908693926109c0565b610ccf90613c82565b610c3357815f610cb7565b95949515610cf0575b906109b9929188956109b2565b859350610ce3565b60019a5061099d565b8380fd5b503461052457602036600319011261052457610d1f613c2b565b60043560045580f35b5061012036600319011261052457610d3e613abb565b90610d47613ad1565b91610d50613ae7565b91610d59613afd565b60a4356001600160a01b0381169003610a75576001600160401b039360c435858111610d0157610d8d903690600401613b9e565b96909560e4359081116113d857610da8903690600401613b9e565b906101043515156101043503610a7557610dc760ff6005541615613f50565b868399859860018060a01b03610ddd8888614cce565b1696878a52600760205260018060a01b03600160408c200154169660043592610e0684826146e5565b506001600160a01b0316156113a7575b6001600160a01b031615611376575b6001600160a01b031615611345575b60011c998a97604051630dfe168160e01b81526020816004818c5afa90811561133a578b9161131b575b506001600160a01b03808f16911603611310575b6001600160a01b038d8116908516036112fb575b5050506001600160a01b03888116908216036112e3575b5050506101043561112f575b60405163095ea7b360e01b8082529060208180610eca8b8760048401613d2a565b0381896001600160a01b038e165af18015610abf5791859391602093611112575b50610f026040519485938493845260048401613d2a565b0381876001600160a01b038a165af18015610422579060209392916110e5575b5083526007825260018060a01b0360408420541660045491846103e8610f5481610f4c878c61403a565b04958461403a565b604051636cfa229360e01b8152998a9687958694610f78940492336004870161404d565b03925af19283156110d85781936110a4575b506040516370a0823160e01b80825230600483015294906020816024816001600160a01b0386165afa908115610400578391611072575b5080611057575b50506040519384523060048501526020846024816001600160a01b0386165afa9081156103d75790611024575b6020935080611009575b5050604051908152f35b61101d9133906001600160a01b0316613d45565b5f80610fff565b506020833d60201161104f575b8161103e60209383613ccb565b81010312610a755760209251610ff5565b3d9150611031565b61106b9133906001600160a01b0316613d45565b5f80610fc8565b90506020813d60201161109c575b8161108d60209383613ccb565b81010312610a7557515f610fc1565b3d9150611080565b9092506020813d6020116110d0575b816110c060209383613ccb565b81010312610a755751915f610f8a565b3d91506110b3565b50604051903d90823e3d90fd5b61110490843d861161110b575b6110fc8183613ccb565b810190613d81565b505f610f22565b503d6110f2565b61112890843d861161110b576110fc8183613ccb565b505f610eeb565b9194604051630240bc6b60e21b8152606081600481865afa9081156112d857859086926112b6575b506040516318160ddd60e01b815291602083600481885afa928315610b7557908a939291889361127f575b5061118d838661403a565b6001600160701b03838116949091819081908e906111ac908990613f85565b926111b69161403a565b93851693846111c491613f85565b8083105f14946111f26111ff956111ed6111f8966111ed956112069a61127757509b5b8c61403a565b613f85565b9861403a565b948761402d565b938b61402d565b908184111561123657505087611230949361122a9361122493614179565b9261402d565b9661400c565b91610ea9565b91509182999694991161124c575b505050610ea9565b61126e93959892886112689361126193614179565b909261400c565b9661402d565b91865f80611244565b90509b6111e7565b935091506020833d6020116112ae575b8161129c60209383613ccb565b81010312610a7557899251915f611182565b3d915061128f565b90506112d0915060603d811161051d5761050a8183613ccb565b50905f611157565b6040513d87823e3d90fd5b6112f293958860a4359261443b565b915f8080610e9d565b839b8d6113079561443b565b975f8080610e86565b999b998b9850610e72565b611334915060203d602011610461576104538183613ccb565b5f610e5e565b6040513d8d823e3d90fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169950610e34565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169c50610e25565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169450610e16565b8480fd5b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461052457602036600319011261052457600435600654811015610c335761144990613bfb565b5080546001820154600290920154604080516001600160a01b0393841681529383166020850152911690820152606090f35b0390f35b50346105245761148e36613b36565b909290156116eb577f00000000000000000000000000000000000000000000000000000000000000005b604051630240bc6b60e21b8152936001600160a01b0390828216606087600481845afa9182156112d857859786936116c4575b5060405195630dfe168160e01b928388526020988989600481855afa9889156104005783996116a1575b5086169786168814801561164f575b61152d90614100565b6040518481528981600481855afa908115610400578a9188918591611632575b501689149485156115ec575060405163d21220a760e01b815291829060049082905afa908115610468579082918996959493916115cf575b50955b8315610434578a931561042d5784926040518b8160048163313ce56760e01b9b8c82525afa9081156104225760049261030a6103058f9461031094899161040b5750614157565b6115e691508a3d8c11610461576104538183613ccb565b5f611585565b60046040518094819382525afa90811561046857908291899695949391611615575b5095611588565b61162c91508a3d8c11610461576104538183613ccb565b5f61160e565b6116499150833d8511610461576104538183613ccb565b5f61154d565b5060405163d21220a760e01b81528981600481855afa9081156104005761152d9188918591611684575b501689149050611524565b61169b91508c8d3d10610461576104538183613ccb565b5f611679565b879199506116bc82918c8d3d10610461576104538183613ccb565b999150611515565b9092506116e091975060603d811161051d5761050a8183613ccb565b50969096915f6114eb565b7f00000000000000000000000000000000000000000000000000000000000000006114b8565b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245760203660031901126105245760209060ff906040906001600160a01b03611781613aa5565b168152600884522054166040519015158152f35b5034610524576040366003190112610524576001600160401b0360043581811161089a576117c7903690600401613bcb565b91602435908111610d01576117e0903690600401613bcb565b6117eb939193613c2b565b6117f681831461481d565b845b828110611803578580f35b61180e818387614860565b359081151580920361185a57611825818587614860565b356001600160a01b03811692908390036108925760019288526008602052604088209060ff80198354169116179055016117f8565b8680fd5b5034610524578060031936011261052457546040516001600160a01b039091168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034610524578060031936011261052457602060ff600554166040519015158152f35b5060e036600319011261052457611947613aa5565b90611950613afd565b60a4356001600160401b03811161089a5761196f903690600401613b9e565b92909361197a613b27565b9061198a60ff6005541615613f50565b808215612103577f0000000000000000000000000000000000000000000000000000000000000000955b83156120d3577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316975b6001546001600160a01b03169685156120c3578960ff60035460a81c16945b611a11602435886146e5565b966001600160a01b031615612093575b6001600160a01b038281169082160361207c575b5050604051630240bc6b60e21b81529250606091508290506004816001600160a01b038b165afa80156112d857839086928791612056575b508315611fd95750611a87916001600160701b03166148b0565b918215611fcd575b60405163d21220a760e01b81526020816004816001600160a01b038c165afa908115610abf5790611ac9918791611faf575b5089856141cd565b928315611fa757611ad99161402d565b915b60443583101580611f9b575b15611f70578115611f6557611b3f6020845b60405163095ea7b360e01b81529283918291907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660048401613d2a565b0381896001600160a01b038e165af18015610abf57611f46575b508115611f3b5760405163095ea7b360e01b815260208180611ba8856001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660048401613d2a565b0381898b5af18015610abf57906060939291611f1c575b508115611f1257611c23845b8315611f0857611c00835b8515611f025782905b600454938492611bf36103e896879261403a565b049715611efb575061403a565b04948a6040519687958695635a47ddc360e01b875242948d309560048a0161409e565b0381867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1801561040057611ecc575b5015611ea5577f0000000000000000000000000000000000000000000000000000000000000000935b6040516370a0823160e01b808252306004830152959094906020866024816001600160a01b0386165afa958615610422578496611e71575b5060405163095ea7b360e01b81526001600160a01b0391909116916020908290818781611cef8c8960048401613d2a565b03926001600160a01b03165af1801561042257611e52575b50803b1561089a57828091606460405180948193638dbdbe6d60e01b83528160048401528a60248401523360448401525af1801561040057908391611e3e575b50506040518581523060048201526020816024816001600160a01b0386165afa908115610400578391611e0c575b5080611df1575b5050604051938452306004850152602084602481855afa9081156103d75790611dbe575b6020935080611db3575050604051908152f35b61101d913390613d45565b506020833d602011611de9575b81611dd860209383613ccb565b81010312610a755760209251611da0565b3d9150611dcb565b611e059133906001600160a01b0316613d45565b5f80611d7c565b90506020813d602011611e36575b81611e2760209383613ccb565b81010312610a7557515f611d75565b3d9150611e1a565b611e4790613c82565b610c3357815f611d47565b611e6a9060203d60201161110b576110fc8183613ccb565b505f611d07565b9095506020813d602011611e9d575b81611e8d60209383613ccb565b81010312610a755751945f611cbe565b3d9150611e80565b7f000000000000000000000000000000000000000000000000000000000000000093611c86565b611eed9060603d606011611ef4575b611ee58183613ccb565b810190614083565b5050611c5d565b503d611edb565b905061403a565b80611bdf565b611c008193611bd6565b611c238194611bcb565b611f349060203d60201161110b576110fc8183613ccb565b505f611bbf565b611ba8602084611af9565b611f5e9060203d60201161110b576110fc8183613ccb565b505f611b59565b611b3f602082611af9565b606460405162461bcd60e51b81526020600482015260046024820152634553543360e01b6044820152fd5b50606435811015611ae7565b505083611ad9565b611fc7915060203d8111610461576104538183613ccb565b5f611ac1565b80925060011c91611a8f565b611fec92506001600160701b03166148b0565b91821561204a575b604051630dfe168160e01b81526020816004816001600160a01b038c165afa908115610abf579061202d918791611faf575089856141cd565b9283156120425761203d9161402d565b611adb565b505083611adb565b80925060011c91611ff4565b905061207291925060603d60601161051d5761050a8183613ccb565b509190915f611a6d565b9061208895969161443b565b905f80808981611a35565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611a21565b8960ff60035460a01c1694611a05565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316976119e6565b7f0000000000000000000000000000000000000000000000000000000000000000956119b4565b5034610524578060031936011261052457612143613c2b565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5034610524576020366003190112610524576001600160a01b0390604090826121aa613aa5565b1681526007602052209061147b81835416916002816001860154169401541660405193849384916040919493606084019560018060a01b039283809216865216602085015216910152565b50346105245760a03660031901126105245760243590600435612216613ad1565b9161221f613ae7565b93608435928315158403610a75576122448195839760018060a01b0392839183614cce565b169360405193630dfe168160e01b9485815260209384826004818b5afa91821561272c579086918a93612766575b50811691160361275b575b5050604051630240bc6b60e21b815293606085600481845afa948515610abf5786908796612737575b5060018060701b03809116951692604051996318160ddd60e01b95868c52848c600481875afa9a8b1561272c57899b6126fc575b8b809d506122fa886111ed6122f38d6111ed868861403a565b938761403a565b808210156126f45750905b612322612317839e6111ed8d8661403a565b9e6111ed8a8561403a565b9b61234b575b8d8d61147b8e604051938493846040919493926060820195825260208201520152565b8b61235f8f9d9f9e9b9c9d6123659361402d565b9461402d565b8084111561252c5750506040519081528481600481875afa998a156103d7579961250d575b5061239581896148b0565b91604051996378a051ad60e11b8b528360048c01521660248a01528389604481865afa98891561249f575f996124dc575b50906123d19161402d565b95604051908582528382600481865afa801561249f5784925f916124aa575b50906111ed6123ff928a61403a565b9460046040518094819382525afa91821561249f575f9261246e575b505085936124509361243b61245697946111ed61244a9561147b9b61403a565b8082101561246657509061400c565b9561400c565b9461400c565b905f808080808080808080612328565b90509061400c565b81819392933d8311612498575b6124858183613ccb565b810103126105245750518361245061241b565b503d61247b565b6040513d5f823e3d90fd5b919282813d83116124d5575b6124c08183613ccb565b810103126105245750518391906111ed6123f0565b503d6124b6565b90988482813d8311612506575b6124f38183613ccb565b81010312610524575051976123d16123c6565b503d6124e9565b612525919950843d8611610461576104538183613ccb565b975f61238a565b8092509c9a989b9c979695949392909711612554575b50505050505050505061147b90612456565b9091929394959697989a995060405163d21220a760e01b81528481600481875afa9889156103d757986126d5575b5061258d81866148b0565b91604051986378a051ad60e11b8a528360048b01521660248901528388604481865afa97881561249f575f986126a4575b50906125c99161402d565b96604051908582528382600481865afa801561249f5784925f91612672575b50906111ed6125f7928a61403a565b9460046040518094819382525afa91821561249f575f92612641575b505085936124509361243b61263397946111ed61244a9561147b9b61403a565b905f80808080808080612542565b81819392933d831161266b575b6126588183613ccb565b8101031261052457505183612450612613565b503d61264e565b919282813d831161269d575b6126888183613ccb565b810103126105245750518391906111ed6125e8565b503d61267e565b90978482813d83116126ce575b6126bb8183613ccb565b81010312610524575051966125c96125be565b503d6126b1565b6126ed919850843d8611610461576104538183613ccb565b965f612582565b905090612305565b9a509a8481813d8311612725575b6127148183613ccb565b81010312610a755751998b906122da565b503d61270a565b6040513d8b823e3d90fd5b905061275291955060603d811161051d5761050a8183613ccb565b5094905f6122a6565b985096505f8061227d565b8291935061278090873d8911610461576104538183613ccb565b9290612272565b50346105245780600319360112610524576127a0613c2b565b476127a85780f35b805460405147916001600160a01b031690602081016001600160401b03811182821017612819578493849384809484604052525af16127e5613cec565b50156127ee5780f35b60405162461bcd60e51b815260206004820152600360248201526253544560e81b6044820152606490fd5b634e487b7160e01b5f52604160045260245ffd5b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245760209081600319360112610524576128d3613aa5565b906128dc613c2b565b80546040516370a0823160e01b8152306004820152926001600160a01b0391821691168484602481845afa9283156103d75792612927575b61291e9350613d45565b60405160018152f35b91508383813d8311612951575b61293e8183613ccb565b81010312610a755761291e925191612914565b503d612934565b50346105245761297c61296a36613b69565b926001600160a01b0392909190614cce565b1690604051906318160ddd60e01b82526020938483600481875afa9283156110d8578193612a61575b50606060049460405195868092630240bc6b60e21b82525afa9384156110d8578194612a3d575b508215612a0957916111ed6129fe92604096946129f6846111ed60018060701b038094168561403a565b96169061403a565b908351928352820152f35b60405162461bcd60e51b815260048101869052600c60248201526b4e6f206c697175696469747960a01b6044820152606490fd5b9050612a5891935060603d811161051d5761050a8183613ccb565b5092905f6129cc565b9392508484813d8311612a8c575b612a798183613ccb565b81010312610a75579251919260606129a5565b503d612a6f565b503461052457602036600319011261052457612aad613aa5565b612ab5613c2b565b600680546001600160a01b03928316929190845b818110612aee578585815260076020525f600260408320828155826001820155015580f35b612af781613bfb565b509085856002809401541614612b12575b6001915001612ac9565b5f19838101848111612be357612b2790613bfb565b50612b3183613bfb565b612bcf57818103612b92575b505084548015612b7e5701612b5181613bfb565b612b6b57600193815f809355828682015501558455612b08565b634e487b7160e01b5f525f60045260245ffd5b634e487b7160e01b89526031600452602489fd5b878580828554169360018060a01b031994858254161781556001848183019188015416868254161790550193015416908254161790555f80612b3d565b634e487b7160e01b8a5260048a905260248afd5b634e487b7160e01b89526011600452602489fd5b50346105245780600319360112610524576020600454604051908152f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346105245780600319360112610524576002546040516001600160a01b039091168152602090f35b503461052457612d1c36613b36565b919290911561303c577f0000000000000000000000000000000000000000000000000000000000000000915b604051630240bc6b60e21b81526001600160a01b03938416939092606084600481885afa9384156110d85781908295613018575b50604051630dfe168160e01b81526001600160701b0391821695909116936020939192909184846004818b5afa938415610468578294612ff9575b5060405163d21220a760e01b815298858a6004818c5afa998a1561040057839a612fd6575b5081809116941684149081998215612fca575b505015612f9557508615612f8b57612e0781866148b0565b90604051926378a051ad60e11b8452826004850152602484015283836044818a5afa92831561249f575f93612f5a575b5090612e429161402d565b8615612f535780965b15612f4b5750935b6040516318160ddd60e01b808252948382600481865afa801561249f5784925f91612f19575b50906111ed612e88928a61403a565b9460046040518094819382525afa91821561249f575f92612ee8575b505061147b92916111ed612eb8928661403a565b80821015612ee05750915b604051938493846040919493926060820195825260208201520152565b905091612ec3565b81819392933d8311612f12575b612eff8183613ccb565b81010312610524575051816111ed612ea4565b503d612ef5565b919282813d8311612f44575b612f2f8183613ccb565b810103126105245750518391906111ed612e79565b503d612f25565b905093612e53565b8196612e4b565b90928482813d8311612f84575b612f718183613ccb565b8101031261052457505191612e42612e37565b503d612f67565b612e0781856148b0565b60405162461bcd60e51b815260048101859052600d60248201526c34b73b30b634b2103a37b5b2b760991b6044820152606490fd5b16841490505f80612def565b82919a50612ff18291883d8a11610461576104538183613ccb565b9a9150612ddc565b613011919450853d8711610461576104538183613ccb565b925f612db7565b905061303391945060603d811161051d5761050a8183613ccb565b5093905f612d7c565b7f000000000000000000000000000000000000000000000000000000000000000091612d48565b5034610524578060031936011261052457602060ff60035460a81c166040519015158152f35b50346105245780600319360112610524576130a2613c2b565b60055460ff80821615169060ff19161760055580f35b50346105245780600319360112610524576006546130d5816140e9565b906130e36040519283613ccb565b8082526006835260209182810191847ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f845b83831061317b57505050506040519280840191818552518092526040840192945b8281106131435784840385f35b855180516001600160a01b03908116865281840151811686850152604091820151169085015294810194606090930192600101613136565b60038760019260409a9997989a5161319281613c95565b848060a01b038087541682528086880154168483015260028701541660408201528152019201920191909694939596613115565b50346105245780600319360112610524576003546040516001600160a01b039091168152602090f35b50608036600319011261052457613204613aa5565b61320c613abb565b916064359061322060ff6005541615613f50565b6044359284926001600160a01b0381838261323b8883614cce565b16918287528360209a60078c528180600160408c200154169861325e8d826146e5565b5061326985846146e5565b501615613508575b16156134de575b604051630dfe168160e01b81528a81600481875afa9081156134aa5788916134c1575b50848084169116036134b5575b508216936040519663095ea7b360e01b978881528a81806132cd8d8760048401613d2a565b03818b8b5af180156134aa578b92879492879261348d575b5016986132fe6040519485938493845260048401613d2a565b0381898b5af18015610abf57908994939291613470575b5085526007835260408520541660045491856103e861333881610f4c878d61403a565b604051636cfa229360e01b81529a8b968795869461335c940492336004870161404d565b03925af1938415610468578294613441575b506040516370a0823160e01b80825230600483015291908681602481855afa908115610422578491613414575b5080613402575b50506040519081523060048201528481602481865afa9182156103d757916133d5575b5080611db3575050604051908152f35b90508381813d83116133fb575b6133ec8183613ccb565b81010312610a7557515f6133c5565b503d6133e2565b61340d913390613d45565b5f806133a2565b90508681813d831161343a575b61342b8183613ccb565b81010312610a7557515f61339b565b503d613421565b9093508481813d8311613469575b6134598183613ccb565b81010312610a755751925f61336e565b503d61344f565b61348690853d871161110b576110fc8183613ccb565b505f613315565b6134a390853d871161110b576110fc8183613ccb565b505f6132e5565b6040513d8a823e3d90fd5b979096909350826132a8565b6134d891508b3d8d11610461576104538183613ccb565b5f61329b565b7f000000000000000000000000000000000000000000000000000000000000000084169750613278565b7f000000000000000000000000000000000000000000000000000000000000000082169350613271565b5060e036600319011261052457613547613aa5565b61354f613abb565b613557613b27565b61356660ff6005541615613f50565b8383918394815f14613a7e577f0000000000000000000000000000000000000000000000000000000000000000915b15613a57577f0000000000000000000000000000000000000000000000000000000000000000945b6044356135ca81846146e5565b916135d7606435826146e5565b936001600160a01b031615613a26575b6001600160a01b0316156139f5575b60405163095ea7b360e01b81529060209082908190613642907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660048401613d2a565b0381886001600160a01b038b165af180156112d8576139d6575b5060405163095ea7b360e01b815291602083806136a86064357f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031660048401613d2a565b0381886001600160a01b038d165af19182156112d8576136f4936060936139b7575b50604051635a47ddc360e01b815293849283924291309160a43591608435918f8e60048a0161409e565b0381867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1801561040057613999575b506040516370a0823160e01b8082523060048301529490916001600160a01b039182169116602083602481845afa928315610422578493613964575b50602061378c936040518095819263095ea7b360e01b83528660048401613d2a565b038187855af190811561042257602493602092613947575b50604051938480928982523060048301525afa918215610400578392613913575b50803b1561089a57606483926040519485938492638dbdbe6d60e01b845282600485015260248401523360448401525af180156112d857613900575b506040518281523060048201526020816024816001600160a01b0386165afa9081156112d85785916138ce575b50806138b3575b50506040519081523060048201526020816024816001600160a01b0386165afa908115610400578391613881575b508061386d578280f35b610a489133906001600160a01b0316613d45565b90506020813d6020116138ab575b8161389c60209383613ccb565b81010312610a7557515f613863565b3d915061388f565b6138c79133906001600160a01b0316613d45565b5f80613835565b90506020813d6020116138f8575b816138e960209383613ccb565b81010312610a7557515f61382e565b3d91506138dc565b61390c90949194613c82565b925f613801565b9091506020813d60201161393f575b8161392f60209383613ccb565b8101031261089a5751905f6137c5565b3d9150613922565b61395d90833d851161110b576110fc8183613ccb565b505f6137a4565b92506020833d602011613991575b8161397f60209383613ccb565b81010312610d0157915191602061376a565b3d9150613972565b6139b09060603d8111611ef457611ee58183613ccb565b505061372e565b6139cf9060203d60201161110b576110fc8183613ccb565b505f6136ca565b6139ee9060203d60201161110b576110fc8183613ccb565b505f61365c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031697506135f6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031696506135e7565b7f0000000000000000000000000000000000000000000000000000000000000000946135bd565b7f000000000000000000000000000000000000000000000000000000000000000091613595565b600435906001600160a01b0382168203610a7557565b602435906001600160a01b0382168203610a7557565b604435906001600160a01b0382168203610a7557565b606435906001600160a01b0382168203610a7557565b608435906001600160a01b0382168203610a7557565b35906001600160a01b0382168203610a7557565b60c435908115158203610a7557565b6060906003190112610a75576004356001600160a01b0381168103610a755790602435906044358015158103610a755790565b6060906003190112610a75576001600160a01b03906004358281168103610a7557916024359081168103610a75579060443590565b9181601f84011215610a75578235916001600160401b038311610a755760208381860195010111610a7557565b9181601f84011215610a75578235916001600160401b038311610a75576020808501948460051b010111610a7557565b600654811015613c175760065f52600360205f20910201905f90565b634e487b7160e01b5f52603260045260245ffd5b5f546001600160a01b03163303613c3e57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160401b03811161281957604052565b606081019081106001600160401b0382111761281957604052565b604081019081106001600160401b0382111761281957604052565b90601f801991011681019081106001600160401b0382111761281957604052565b3d15613d25573d906001600160401b0382116128195760405191613d1a601f8201601f191660200184613ccb565b82523d5f602084013e565b606090565b6001600160a01b039091168152602081019190915260400190565b613d7a613d7f9392613d6c60405194859263a9059cbb60e01b602085015260248401613d2a565b03601f198101845283613ccb565b613d99565b565b90816020910312610a7557518015158103610a755790565b604051613df6916001600160a01b0316613db282613cb0565b5f806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af1613df0613cec565b91613e7e565b805190828215928315613e66575b50505015613e0f5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b613e769350820181019101613d81565b5f8281613e04565b91929015613ee05750815115613e92575090565b3b15613e9b5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015613ef35750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401525f935b828510613f37575050604492505f838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350613f15565b15613f5757565b60405162461bcd60e51b815260206004820152600660248201526514185d5cd95960d21b6044820152606490fd5b8115613f8f570490565b634e487b7160e01b5f52601260045260245ffd5b90816020910312610a7557516001600160a01b0381168103610a755790565b51906001600160701b0382168203610a7557565b90816060910312610a7557613fea81613fc2565b916040613ff960208401613fc2565b92015163ffffffff81168103610a755790565b9190820180921161401957565b634e487b7160e01b5f52601160045260245ffd5b9190820391821161401957565b8181029291811591840414171561401957565b9391959492909560c085019660018060a01b03168552602085015260408401526060830152608082015260a0600f60fc1b910152565b90816060910312610a75578051916040602083015192015190565b9490989796929361010096929461012087019a60018060a01b03968780921689521660208801525f60408801526060870152608086015260a085015260c08401521660e08201520152565b6001600160401b0381116128195760051b60200190565b1561410757565b60405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b2103a37b5b2b724b760891b6044820152606490fd5b90816020910312610a75575160ff81168103610a755790565b60ff166012039060ff821161401957565b60ff16604d811161401957600a0a90565b91935f9390929091614193916001600160701b03166148b0565b938461419d575050565b6141a9929350846141cd565b90565b805115613c175760200190565b8051821015613c175760209160051b010190565b9192906040918251916141df83613cb0565b6001948584525f5b6020808210156142185786516020929161420082613c95565b5f82525f818301525f898301528288010152016141e7565b50509295909394919561422a816141ac565b516001600160a01b0395861690819052602092909190868461424b846141ac565b5101911690525f8761425c836141ac565b5101525f83877f0000000000000000000000000000000000000000000000000000000000000000169360448a518094819363095ea7b360e01b8352886004840152811960248401525af1801561443157614414575b5090935f9485928851978893631e82ecdb60e31b855260a4850190600486015287602486015260a0604486015282518091528660c4860193019186905b89898484106143df5750505050505083838092306064830152600f60fc1b608483015203925af1938491849561434f575b505061432d57505050505f90565b8251111561433b5750015190565b634e487b7160e01b81526032600452602490fd5b909194503d8085843e6143628184613ccb565b82019181818403126113d8578051906001600160401b03821161089657019180601f840112156113d8578251614397816140e9565b936143a489519586613ccb565b818552838086019260051b82010192831161185a578301905b8282106143d05750505050925f8061431f565b815181529083019083016143bd565b8551805184168852808201518416888301528f015115158f8801528c99508d98506060909601959490940193909101906142ee565b61442a90843d861161110b576110fc8183613ccb565b505f6142b1565b88513d5f823e3d90fd5b9295949091939560018060a01b038094169060409788519263095ea7b360e01b908185526020968561447260049b878d8401613d2a565b039588815f98818a875af180156146db57908a92916146be575b5016938b51966370a0823160e01b94858952308c8a015260249a8a8a8d818b5afa998a156146b357908f9695949392918a9b614675575b508316808a5260088c529589205460ff161561463a5791818f8a9485948592519384928337810182815203925af16144f9613cec565b50156145fd5760448892878c938f5196879586948552840152818d8401525af180156145f357908692916145d6575b50868a51809481938252308b8301525afa9182156145cb578092614599575b5050906145539161402d565b9485156145605750505050565b5162461bcd60e51b8152928301526017908201527622b93937b91029bbb0b83834b733902a37b5b2b739901960491b6044820152606490fd5b9091508382813d83116145c4575b6145b18183613ccb565b810103126105245750516145535f614547565b503d6145a7565b8851903d90823e3d90fd5b6145ec90833d851161110b576110fc8183613ccb565b505f614528565b8a513d86823e3d90fd5b508a5162461bcd60e51b8152808a018890526017818a0152764572726f72205377617070696e6720546f6b656e73203160481b6044820152606490fd5b508d5162461bcd60e51b8152808d018b90526015818d01527415185c99d95d081b9bdd08105d5d1a1bdc9a5e9959605a1b6044820152606490fd5b8c80929c5081939495969798503d83116146ac575b6146948183613ccb565b810103126108725751988e95949392919060ff6144c3565b503d61468a565b508e513d8a823e3d90fd5b6146d4908a3d8c1161110b576110fc8183613ccb565b505f61448c565b8d513d89823e3d90fd5b6001600160a01b0390811690811561478357508115614747576040516323b872dd60e01b60208201523360248201523060448201526064808201849052815260a08101916001600160401b03831182841017612819576141a992604052613d99565b60405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a59081d1bdad95b88185b5bdd5b9d60621b6044820152606490fd5b91505034156147ea577f000000000000000000000000000000000000000000000000000000000000000016803b15610a75575f60049160405192838092630d0e30db60e41b825234905af1801561249f576147dd57503490565b6147e690613c82565b3490565b60405162461bcd60e51b815260206004820152600b60248201526a139bc8195d1a081cd95b9d60aa1b6044820152606490fd5b1561482457565b60405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c84092dce0eae840d8cadccee8d60631b6044820152606490fd5b9190811015613c175760051b0190565b60018060a01b0360406002828551169360018060a01b03199485825416178155600181018460208801511686825416179055019301511690825416179055565b90623cda209081810291818304149015171561401957623cda299081830283159284820414831715614019576148ec6148f2916148f79361400c565b8461403a565b614e07565b906107cd808402938404141715614019576107ca916149159161402d565b0490565b909396959294919461492f866111ed878561403a565b6040805163313ce56760e01b8082529891956001600160a01b039485169560209593949093919286816004818b5afa908115614b4d57610305614983939261497d925f91614b875750614157565b90613f85565b9b16968651916318160ddd60e01b835285836004818c5afa928315614431575f93614b57575b509060049186849a8a5194858092637464fc3d60e01b82525afa928315614b4d579187969593918b95935f93614b10575b5082614a6b575b505050506149f392916111ed9161403a565b96600485518095819382525afa928315614a625750614a296103056111ed94614a34979694614a2f945f92614a45575050614157565b8861403a565b61403a565b80821015614a40575090565b905090565b614a5b9250803d106103d0576103c18183613ccb565b5f80610386565b513d5f823e3d90fd5b614a7b614a8692614a809261403a565b614b9e565b91614b9e565b90818111614a95575b806149e1565b8193959650614aa592945061402d565b6127108082029082820481148315171561401957614add93614ad1614ad6926111ed940494859261400c565b61402d565b918461403a565b9081614af0575b91818594938993614a8f565b6149f3929750614b058594926111ed9261400c565b979250819350614ae4565b80939294965088919597983d8311614b46575b614b2d8183613ccb565b810103126105245750918993918796959351915f6149da565b503d614b23565b89513d5f823e3d90fd5b90928682813d8311614b80575b614b6e8183613ccb565b810103126105245750519160046149a9565b503d614b64565b6103fa91508a3d8c116103d0576103c18183613ccb565b8015614cc957614a34815f908360801c80614cbd575b508060401c80614cb0575b508060201c80614ca3575b508060101c80614c96575b508060081c80614c89575b508060041c80614c7c575b508060021c80614c6f575b50600191828092811c614c68575b1c1b614c108185613f85565b01811c614c1d8185613f85565b01811c614c2a8185613f85565b01811c614c378185613f85565b01811c614c448185613f85565b01811c614c518185613f85565b01811c614c5e8185613f85565b01901c8092613f85565b0181614c04565b600291509101905f614bf6565b600491509101905f614beb565b600891509101905f614be0565b601091509101905f614bd5565b602091509101905f614bca565b604091509101905f614bbf565b9150506080905f614bb4565b505f90565b6001600160a01b039291839081831615614ddd575b81811615614db4575b6040516306801cc360e41b815292821660048401521660248201525f60448201526020816064817f000000000000000000000000000000000000000000000000000000000000000087165afa801561249f5783915f91614d96575b501691825f526007602052600260405f2001541615614d6257565b60405162461bcd60e51b815260206004820152600c60248201526b24b73b30b634b2102830b4b960a11b6044820152606490fd5b614dae915060203d8111610461576104538183613ccb565b5f614d47565b50807f000000000000000000000000000000000000000000000000000000000000000016614cec565b7f000000000000000000000000000000000000000000000000000000000000000082169250614ce3565b8015614cc957600181600160801b811015614f2b575b614ecd614ec0614eb3614ea6614e99614e8c614a34976008614eda98600160401b811015614f1e575b640100000000811015614f11575b62010000811015614f05575b610100811015614ef9575b6010811015614eec575b1015614ee4575b614e86818b613f85565b9061400c565b60011c614e86818a613f85565b60011c614e868189613f85565b60011c614e868188613f85565b60011c614e868187613f85565b60011c614e868186613f85565b60011c614e868185613f85565b60011c8092613f85565b60011b614e7c565b60041c9160021b91614e75565b811c9160041b91614e6b565b60101c91811b91614e60565b60201c9160101b91614e54565b60401c9160201b91614e46565b50600160401b9050608082901c614e1d56fea26469706673582212205580da31fad79b4b0d6fed01ecab30f78ec6ed9d3dd0962de4d713871df873fb64736f6c634300081400330000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc00000000000000000000000029219dd400f2bf60e5a23d13be72b486d40388940000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf00000000000000000000000019d04a9bd2aeee1d1b9e86a05afeadb4c9c6e395000000000000000000000000c7f449eb12f20d66e33631ad5176993ccacb6acf00000000000000000000000012c0d2e69c309ba71d8ca55f61ce4395c01d15d10000000000000000000000007993620e9f66cb7cef1ffb755aa8ad8df4a10207000000000000000000000000f93d924b54955e113965e51641f360163709029700000000000000000000000031a5a7add82b1091821be91dececc13974c76e36
Deployed Bytecode
0x6080604052600436101561001a575b3615610018575f80fd5b005b5f803560e01c8062c61fbf146135325780630730adbb146131ef57806309b67301146131c6578063103841c6146130b85780631385d24c1461308957806324381a53146130635780632585d64614612d0d5780632ca8847f14612ce45780632dd3100014612c9f57806332fe7b2614612c5a5780633d05cbd314612c155780633e032a3b14612bf75780633f78817014612a93578063457ea7561461295857806349df728c146128b7578063527a53ad14612872578063551950c81461282d578063603f1afb1461278757806364cc89be146121f557806371065a9314612183578063715018a61461212a5780637224f3221461193257806375f12b211461190f57806376cbff3b146118ca57806389a30271146118855780638da5cb5b1461185e5780639735a634146117955780639779d1a61461175657806399116aba14611711578063993a37191461147f5780639c05a4cb14611421578063ad5c4648146113dc578063bc0ca6a514610d28578063bec872b014610d05578063bf8094621461090c578063d1090dc2146108c7578063de9a71291461089e578063e0a6dfa014610697578063e512073814610671578063f066de4b1461062c578063f2fde38b1461056c578063f355355b146105275763fb21cd01146101fd575061000e565b346105245761020b36613b69565b92906102178184614cce565b604051630240bc6b60e21b8152946001600160a01b038083169492939291606088600481895afa9283156103d757809881946104ed575b5060405196630dfe168160e01b8089526020998a8a600481865afa998a1561042257908b9291859b6104ca575b5086169986168a148015610473575b61029390614100565b60046040518094819382525afa908115610468579382918996958295949161043b575b50168514928315610434578a935b1561042d5784925b6040518b8160048163313ce56760e01b9b8c82525afa9081156104225760049261030a6103058f9461031094899161040b575b50614157565b614168565b9061403a565b9a604051928380928b82525afa9081156104005761033c6103058d9361034c9387916103e35750614157565b6001600160701b0396871661403a565b9660046040518094819382528b165afa9182156103d75761039e999795938561038d61030560409f9c9a98968f96849761039497926103aa575b5050614157565b911661403a565b9216961694614919565b90918351928352820152f35b6103c99250803d106103d0575b6103c18183613ccb565b81019061413e565b8f80610386565b503d6103b7565b604051903d90823e3d90fd5b6103fa9150853d87116103d0576103c18183613ccb565b5f6102ff565b6040513d85823e3d90fd5b6103fa9150863d88116103d0576103c18183613ccb565b6040513d86823e3d90fd5b8a926102cc565b84936102c4565b61045b91508b3d8d11610461575b6104538183613ccb565b810190613fa3565b5f6102b6565b503d610449565b6040513d84823e3d90fd5b5060405163d21220a760e01b81529091508a81600481865afa90811561042257868c93926102939287916104ad575b50168b14905061028a565b6104c49150853d8711610461576104538183613ccb565b5f6104a2565b87919b506104e58291853d8711610461576104538183613ccb565b9b915061027b565b90935061051291985060603d811161051d575b61050a8183613ccb565b810190613fd6565b50979097925f61024e565b503d610500565b80fd5b50346105245780600319360112610524576040517f000000000000000000000000c7f449eb12f20d66e33631ad5176993ccacb6acf6001600160a01b03168152602090f35b503461052457602036600319011261052457610586613aa5565b61058e613c2b565b6001600160a01b039081169081156105d8575f548260018060a01b03198216175f55167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b50346105245780600319360112610524576040517f00000000000000000000000031a5a7add82b1091821be91dececc13974c76e366001600160a01b03168152602090f35b5034610524578060031936011261052457602060ff60035460a01c166040519015158152f35b5034610524576040366003190112610524576001600160401b0360043581811161089a576106c9903690600401613bcb565b90916024928335828111610896573660238201121561089657806004013592831161089657606090858285028201019036821161089257610708613c2b565b610711866140e9565b9361071f6040519586613ccb565b8685526020968786019060051b82019136831161088e578890915b838310610876575050505061074e856140e9565b9461075c6040519687613ccb565b855286018585015b828210610824575050505080519261077e8351851461481d565b855b84811061078b578680f35b6107bc61079882866141b9565b516001600160a01b036107ab84876141b9565b511689526007845260408920614870565b6107c681856141b9565b51906006918254600160401b811015610811576107ea906001948582019055613bfb565b6107fe57906107f891614870565b01610780565b634e487b7160e01b8a5260048a9052888afd5b634e487b7160e01b8a526041600452888afd5b83823603126108725786849160405161083c81613c95565b61084585613b13565b8152610852838601613b13565b8382015261086260408601613b13565b6040820152815201910190610764565b8880fd5b819061088184613b13565b815201910190889061073a565b8a80fd5b8780fd5b8580fd5b8280fd5b50346105245780600319360112610524576001546040516001600160a01b039091168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000019d04a9bd2aeee1d1b9e86a05afeadb4c9c6e3956001600160a01b03168152602090f35b5060a036600319011261052457610921613aa5565b610929613abb565b906064356001600160401b038111610d0157610949903690600401613b9e565b90610952613afd565b9383928190610963604435876146e5565b93889760018060a01b039788807f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3816961690868214610cf8575b8916610cda5750939550859487946109b99392915b858961443b565b5060065487805b828110610c69575050501693818514610aca575b50506040516370a0823160e01b808252306004830152602093909216908381602481855afa908115610abf578691610a92575b5080610a80575b50506040519081523060048201528181602481865afa918215610422578492610a4e575b505080610a3d578280f35b610a48913390613d45565b5f808280f35b90809250813d8311610a79575b610a658183613ccb565b81010312610a7557515f80610a32565b5f80fd5b503d610a5b565b610a8b913390613d45565b5f80610a0e565b90508381813d8311610ab8575b610aa98183613ccb565b81010312610a7557515f610a07565b503d610a9f565b6040513d88823e3d90fd5b604051866370a0823160e01b918281523060048201526020938482602481895afa918215610400578392610c37575b5015610b805750506040519081523060048201528181602481865afa918215610b75578792610b47575b505080610b35575b50505b5f806109d4565b610b40913390613d45565b5f80610b2b565b90809250813d8311610b6e575b610b5e8183613ccb565b81010312610a7557515f80610b23565b503d610b54565b6040513d89823e3d90fd5b80925093909293610b95575b50505050610b2e565b803b1561089a57828091602460405180948193632e1a7d4d60e01b83528760048401525af1908115610400578391610c1f575b50808092335af1610bd7613cec565b5015610be557848180610b8c565b6064906040519062461bcd60e51b825260048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152fd5b610c2890613c82565b610c3357815f610bc8565b5080fd5b925090508382813d8111610c62575b610c508183613ccb565b81010312610a7557889151905f610af9565b503d610c46565b909192936002610c7883613bfb565b500154168252600760205286604083205416803b1561089a5782809160046040518094819363b4879beb60e01b83525af1908115610400578391610cc6575b505060010191908693926109c0565b610ccf90613c82565b610c3357815f610cb7565b95949515610cf0575b906109b9929188956109b2565b859350610ce3565b60019a5061099d565b8380fd5b503461052457602036600319011261052457610d1f613c2b565b60043560045580f35b5061012036600319011261052457610d3e613abb565b90610d47613ad1565b91610d50613ae7565b91610d59613afd565b60a4356001600160a01b0381169003610a75576001600160401b039360c435858111610d0157610d8d903690600401613b9e565b96909560e4359081116113d857610da8903690600401613b9e565b906101043515156101043503610a7557610dc760ff6005541615613f50565b868399859860018060a01b03610ddd8888614cce565b1696878a52600760205260018060a01b03600160408c200154169660043592610e0684826146e5565b506001600160a01b0316156113a7575b6001600160a01b031615611376575b6001600160a01b031615611345575b60011c998a97604051630dfe168160e01b81526020816004818c5afa90811561133a578b9161131b575b506001600160a01b03808f16911603611310575b6001600160a01b038d8116908516036112fb575b5050506001600160a01b03888116908216036112e3575b5050506101043561112f575b60405163095ea7b360e01b8082529060208180610eca8b8760048401613d2a565b0381896001600160a01b038e165af18015610abf5791859391602093611112575b50610f026040519485938493845260048401613d2a565b0381876001600160a01b038a165af18015610422579060209392916110e5575b5083526007825260018060a01b0360408420541660045491846103e8610f5481610f4c878c61403a565b04958461403a565b604051636cfa229360e01b8152998a9687958694610f78940492336004870161404d565b03925af19283156110d85781936110a4575b506040516370a0823160e01b80825230600483015294906020816024816001600160a01b0386165afa908115610400578391611072575b5080611057575b50506040519384523060048501526020846024816001600160a01b0386165afa9081156103d75790611024575b6020935080611009575b5050604051908152f35b61101d9133906001600160a01b0316613d45565b5f80610fff565b506020833d60201161104f575b8161103e60209383613ccb565b81010312610a755760209251610ff5565b3d9150611031565b61106b9133906001600160a01b0316613d45565b5f80610fc8565b90506020813d60201161109c575b8161108d60209383613ccb565b81010312610a7557515f610fc1565b3d9150611080565b9092506020813d6020116110d0575b816110c060209383613ccb565b81010312610a755751915f610f8a565b3d91506110b3565b50604051903d90823e3d90fd5b61110490843d861161110b575b6110fc8183613ccb565b810190613d81565b505f610f22565b503d6110f2565b61112890843d861161110b576110fc8183613ccb565b505f610eeb565b9194604051630240bc6b60e21b8152606081600481865afa9081156112d857859086926112b6575b506040516318160ddd60e01b815291602083600481885afa928315610b7557908a939291889361127f575b5061118d838661403a565b6001600160701b03838116949091819081908e906111ac908990613f85565b926111b69161403a565b93851693846111c491613f85565b8083105f14946111f26111ff956111ed6111f8966111ed956112069a61127757509b5b8c61403a565b613f85565b9861403a565b948761402d565b938b61402d565b908184111561123657505087611230949361122a9361122493614179565b9261402d565b9661400c565b91610ea9565b91509182999694991161124c575b505050610ea9565b61126e93959892886112689361126193614179565b909261400c565b9661402d565b91865f80611244565b90509b6111e7565b935091506020833d6020116112ae575b8161129c60209383613ccb565b81010312610a7557899251915f611182565b3d915061128f565b90506112d0915060603d811161051d5761050a8183613ccb565b50905f611157565b6040513d87823e3d90fd5b6112f293958860a4359261443b565b915f8080610e9d565b839b8d6113079561443b565b975f8080610e86565b999b998b9850610e72565b611334915060203d602011610461576104538183613ccb565b5f610e5e565b6040513d8d823e3d90fd5b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03169950610e34565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03169c50610e25565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03169450610e16565b8480fd5b50346105245780600319360112610524576040517f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b03168152602090f35b503461052457602036600319011261052457600435600654811015610c335761144990613bfb565b5080546001820154600290920154604080516001600160a01b0393841681529383166020850152911690820152606090f35b0390f35b50346105245761148e36613b36565b909290156116eb577f0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b5b604051630240bc6b60e21b8152936001600160a01b0390828216606087600481845afa9182156112d857859786936116c4575b5060405195630dfe168160e01b928388526020988989600481855afa9889156104005783996116a1575b5086169786168814801561164f575b61152d90614100565b6040518481528981600481855afa908115610400578a9188918591611632575b501689149485156115ec575060405163d21220a760e01b815291829060049082905afa908115610468579082918996959493916115cf575b50955b8315610434578a931561042d5784926040518b8160048163313ce56760e01b9b8c82525afa9081156104225760049261030a6103058f9461031094899161040b5750614157565b6115e691508a3d8c11610461576104538183613ccb565b5f611585565b60046040518094819382525afa90811561046857908291899695949391611615575b5095611588565b61162c91508a3d8c11610461576104538183613ccb565b5f61160e565b6116499150833d8511610461576104538183613ccb565b5f61154d565b5060405163d21220a760e01b81528981600481855afa9081156104005761152d9188918591611684575b501689149050611524565b61169b91508c8d3d10610461576104538183613ccb565b5f611679565b879199506116bc82918c8d3d10610461576104538183613ccb565b999150611515565b9092506116e091975060603d811161051d5761050a8183613ccb565b50969096915f6114eb565b7f0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf6114b8565b50346105245780600319360112610524576040517f0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b6001600160a01b03168152602090f35b50346105245760203660031901126105245760209060ff906040906001600160a01b03611781613aa5565b168152600884522054166040519015158152f35b5034610524576040366003190112610524576001600160401b0360043581811161089a576117c7903690600401613bcb565b91602435908111610d01576117e0903690600401613bcb565b6117eb939193613c2b565b6117f681831461481d565b845b828110611803578580f35b61180e818387614860565b359081151580920361185a57611825818587614860565b356001600160a01b03811692908390036108925760019288526008602052604088209060ff80198354169116179055016117f8565b8680fd5b5034610524578060031936011261052457546040516001600160a01b039091168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000029219dd400f2bf60e5a23d13be72b486d40388946001600160a01b03168152602090f35b50346105245780600319360112610524576040517f00000000000000000000000012c0d2e69c309ba71d8ca55f61ce4395c01d15d16001600160a01b03168152602090f35b5034610524578060031936011261052457602060ff600554166040519015158152f35b5060e036600319011261052457611947613aa5565b90611950613afd565b60a4356001600160401b03811161089a5761196f903690600401613b9e565b92909361197a613b27565b9061198a60ff6005541615613f50565b808215612103577f0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf955b83156120d3577f00000000000000000000000029219dd400f2bf60e5a23d13be72b486d40388946001600160a01b0316975b6001546001600160a01b03169685156120c3578960ff60035460a81c16945b611a11602435886146e5565b966001600160a01b031615612093575b6001600160a01b038281169082160361207c575b5050604051630240bc6b60e21b81529250606091508290506004816001600160a01b038b165afa80156112d857839086928791612056575b508315611fd95750611a87916001600160701b03166148b0565b918215611fcd575b60405163d21220a760e01b81526020816004816001600160a01b038c165afa908115610abf5790611ac9918791611faf575b5089856141cd565b928315611fa757611ad99161402d565b915b60443583101580611f9b575b15611f70578115611f6557611b3f6020845b60405163095ea7b360e01b81529283918291907f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b031660048401613d2a565b0381896001600160a01b038e165af18015610abf57611f46575b508115611f3b5760405163095ea7b360e01b815260208180611ba8856001600160a01b037f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc1660048401613d2a565b0381898b5af18015610abf57906060939291611f1c575b508115611f1257611c23845b8315611f0857611c00835b8515611f025782905b600454938492611bf36103e896879261403a565b049715611efb575061403a565b04948a6040519687958695635a47ddc360e01b875242948d309560048a0161409e565b0381867f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b03165af1801561040057611ecc575b5015611ea5577f00000000000000000000000031a5a7add82b1091821be91dececc13974c76e36935b6040516370a0823160e01b808252306004830152959094906020866024816001600160a01b0386165afa958615610422578496611e71575b5060405163095ea7b360e01b81526001600160a01b0391909116916020908290818781611cef8c8960048401613d2a565b03926001600160a01b03165af1801561042257611e52575b50803b1561089a57828091606460405180948193638dbdbe6d60e01b83528160048401528a60248401523360448401525af1801561040057908391611e3e575b50506040518581523060048201526020816024816001600160a01b0386165afa908115610400578391611e0c575b5080611df1575b5050604051938452306004850152602084602481855afa9081156103d75790611dbe575b6020935080611db3575050604051908152f35b61101d913390613d45565b506020833d602011611de9575b81611dd860209383613ccb565b81010312610a755760209251611da0565b3d9150611dcb565b611e059133906001600160a01b0316613d45565b5f80611d7c565b90506020813d602011611e36575b81611e2760209383613ccb565b81010312610a7557515f611d75565b3d9150611e1a565b611e4790613c82565b610c3357815f611d47565b611e6a9060203d60201161110b576110fc8183613ccb565b505f611d07565b9095506020813d602011611e9d575b81611e8d60209383613ccb565b81010312610a755751945f611cbe565b3d9150611e80565b7f000000000000000000000000f93d924b54955e113965e51641f360163709029793611c86565b611eed9060603d606011611ef4575b611ee58183613ccb565b810190614083565b5050611c5d565b503d611edb565b905061403a565b80611bdf565b611c008193611bd6565b611c238194611bcb565b611f349060203d60201161110b576110fc8183613ccb565b505f611bbf565b611ba8602084611af9565b611f5e9060203d60201161110b576110fc8183613ccb565b505f611b59565b611b3f602082611af9565b606460405162461bcd60e51b81526020600482015260046024820152634553543360e01b6044820152fd5b50606435811015611ae7565b505083611ad9565b611fc7915060203d8111610461576104538183613ccb565b5f611ac1565b80925060011c91611a8f565b611fec92506001600160701b03166148b0565b91821561204a575b604051630dfe168160e01b81526020816004816001600160a01b038c165afa908115610abf579061202d918791611faf575089856141cd565b9283156120425761203d9161402d565b611adb565b505083611adb565b80925060011c91611ff4565b905061207291925060603d60601161051d5761050a8183613ccb565b509190915f611a6d565b9061208895969161443b565b905f80808981611a35565b507f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b0316611a21565b8960ff60035460a01c1694611a05565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b0316976119e6565b7f0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b956119b4565b5034610524578060031936011261052457612143613c2b565b5f80546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b5034610524576020366003190112610524576001600160a01b0390604090826121aa613aa5565b1681526007602052209061147b81835416916002816001860154169401541660405193849384916040919493606084019560018060a01b039283809216865216602085015216910152565b50346105245760a03660031901126105245760243590600435612216613ad1565b9161221f613ae7565b93608435928315158403610a75576122448195839760018060a01b0392839183614cce565b169360405193630dfe168160e01b9485815260209384826004818b5afa91821561272c579086918a93612766575b50811691160361275b575b5050604051630240bc6b60e21b815293606085600481845afa948515610abf5786908796612737575b5060018060701b03809116951692604051996318160ddd60e01b95868c52848c600481875afa9a8b1561272c57899b6126fc575b8b809d506122fa886111ed6122f38d6111ed868861403a565b938761403a565b808210156126f45750905b612322612317839e6111ed8d8661403a565b9e6111ed8a8561403a565b9b61234b575b8d8d61147b8e604051938493846040919493926060820195825260208201520152565b8b61235f8f9d9f9e9b9c9d6123659361402d565b9461402d565b8084111561252c5750506040519081528481600481875afa998a156103d7579961250d575b5061239581896148b0565b91604051996378a051ad60e11b8b528360048c01521660248a01528389604481865afa98891561249f575f996124dc575b50906123d19161402d565b95604051908582528382600481865afa801561249f5784925f916124aa575b50906111ed6123ff928a61403a565b9460046040518094819382525afa91821561249f575f9261246e575b505085936124509361243b61245697946111ed61244a9561147b9b61403a565b8082101561246657509061400c565b9561400c565b9461400c565b905f808080808080808080612328565b90509061400c565b81819392933d8311612498575b6124858183613ccb565b810103126105245750518361245061241b565b503d61247b565b6040513d5f823e3d90fd5b919282813d83116124d5575b6124c08183613ccb565b810103126105245750518391906111ed6123f0565b503d6124b6565b90988482813d8311612506575b6124f38183613ccb565b81010312610524575051976123d16123c6565b503d6124e9565b612525919950843d8611610461576104538183613ccb565b975f61238a565b8092509c9a989b9c979695949392909711612554575b50505050505050505061147b90612456565b9091929394959697989a995060405163d21220a760e01b81528481600481875afa9889156103d757986126d5575b5061258d81866148b0565b91604051986378a051ad60e11b8a528360048b01521660248901528388604481865afa97881561249f575f986126a4575b50906125c99161402d565b96604051908582528382600481865afa801561249f5784925f91612672575b50906111ed6125f7928a61403a565b9460046040518094819382525afa91821561249f575f92612641575b505085936124509361243b61263397946111ed61244a9561147b9b61403a565b905f80808080808080612542565b81819392933d831161266b575b6126588183613ccb565b8101031261052457505183612450612613565b503d61264e565b919282813d831161269d575b6126888183613ccb565b810103126105245750518391906111ed6125e8565b503d61267e565b90978482813d83116126ce575b6126bb8183613ccb565b81010312610524575051966125c96125be565b503d6126b1565b6126ed919850843d8611610461576104538183613ccb565b965f612582565b905090612305565b9a509a8481813d8311612725575b6127148183613ccb565b81010312610a755751998b906122da565b503d61270a565b6040513d8b823e3d90fd5b905061275291955060603d811161051d5761050a8183613ccb565b5094905f6122a6565b985096505f8061227d565b8291935061278090873d8911610461576104538183613ccb565b9290612272565b50346105245780600319360112610524576127a0613c2b565b476127a85780f35b805460405147916001600160a01b031690602081016001600160401b03811182821017612819578493849384809484604052525af16127e5613cec565b50156127ee5780f35b60405162461bcd60e51b815260206004820152600360248201526253544560e81b6044820152606490fd5b634e487b7160e01b5f52604160045260245ffd5b50346105245780600319360112610524576040517f0000000000000000000000007993620e9f66cb7cef1ffb755aa8ad8df4a102076001600160a01b03168152602090f35b50346105245780600319360112610524576040517f0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf6001600160a01b03168152602090f35b50346105245760209081600319360112610524576128d3613aa5565b906128dc613c2b565b80546040516370a0823160e01b8152306004820152926001600160a01b0391821691168484602481845afa9283156103d75792612927575b61291e9350613d45565b60405160018152f35b91508383813d8311612951575b61293e8183613ccb565b81010312610a755761291e925191612914565b503d612934565b50346105245761297c61296a36613b69565b926001600160a01b0392909190614cce565b1690604051906318160ddd60e01b82526020938483600481875afa9283156110d8578193612a61575b50606060049460405195868092630240bc6b60e21b82525afa9384156110d8578194612a3d575b508215612a0957916111ed6129fe92604096946129f6846111ed60018060701b038094168561403a565b96169061403a565b908351928352820152f35b60405162461bcd60e51b815260048101869052600c60248201526b4e6f206c697175696469747960a01b6044820152606490fd5b9050612a5891935060603d811161051d5761050a8183613ccb565b5092905f6129cc565b9392508484813d8311612a8c575b612a798183613ccb565b81010312610a75579251919260606129a5565b503d612a6f565b503461052457602036600319011261052457612aad613aa5565b612ab5613c2b565b600680546001600160a01b03928316929190845b818110612aee578585815260076020525f600260408320828155826001820155015580f35b612af781613bfb565b509085856002809401541614612b12575b6001915001612ac9565b5f19838101848111612be357612b2790613bfb565b50612b3183613bfb565b612bcf57818103612b92575b505084548015612b7e5701612b5181613bfb565b612b6b57600193815f809355828682015501558455612b08565b634e487b7160e01b5f525f60045260245ffd5b634e487b7160e01b89526031600452602489fd5b878580828554169360018060a01b031994858254161781556001848183019188015416868254161790550193015416908254161790555f80612b3d565b634e487b7160e01b8a5260048a905260248afd5b634e487b7160e01b89526011600452602489fd5b50346105245780600319360112610524576020600454604051908152f35b50346105245780600319360112610524576040517f000000000000000000000000f93d924b54955e113965e51641f36016370902976001600160a01b03168152602090f35b50346105245780600319360112610524576040517f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b03168152602090f35b50346105245780600319360112610524576040517f0000000000000000000000002da25e7446a70d7be65fd4c053948becaa6374c86001600160a01b03168152602090f35b50346105245780600319360112610524576002546040516001600160a01b039091168152602090f35b503461052457612d1c36613b36565b919290911561303c577f0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b915b604051630240bc6b60e21b81526001600160a01b03938416939092606084600481885afa9384156110d85781908295613018575b50604051630dfe168160e01b81526001600160701b0391821695909116936020939192909184846004818b5afa938415610468578294612ff9575b5060405163d21220a760e01b815298858a6004818c5afa998a1561040057839a612fd6575b5081809116941684149081998215612fca575b505015612f9557508615612f8b57612e0781866148b0565b90604051926378a051ad60e11b8452826004850152602484015283836044818a5afa92831561249f575f93612f5a575b5090612e429161402d565b8615612f535780965b15612f4b5750935b6040516318160ddd60e01b808252948382600481865afa801561249f5784925f91612f19575b50906111ed612e88928a61403a565b9460046040518094819382525afa91821561249f575f92612ee8575b505061147b92916111ed612eb8928661403a565b80821015612ee05750915b604051938493846040919493926060820195825260208201520152565b905091612ec3565b81819392933d8311612f12575b612eff8183613ccb565b81010312610524575051816111ed612ea4565b503d612ef5565b919282813d8311612f44575b612f2f8183613ccb565b810103126105245750518391906111ed612e79565b503d612f25565b905093612e53565b8196612e4b565b90928482813d8311612f84575b612f718183613ccb565b8101031261052457505191612e42612e37565b503d612f67565b612e0781856148b0565b60405162461bcd60e51b815260048101859052600d60248201526c34b73b30b634b2103a37b5b2b760991b6044820152606490fd5b16841490505f80612def565b82919a50612ff18291883d8a11610461576104538183613ccb565b9a9150612ddc565b613011919450853d8711610461576104538183613ccb565b925f612db7565b905061303391945060603d811161051d5761050a8183613ccb565b5093905f612d7c565b7f0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf91612d48565b5034610524578060031936011261052457602060ff60035460a81c166040519015158152f35b50346105245780600319360112610524576130a2613c2b565b60055460ff80821615169060ff19161760055580f35b50346105245780600319360112610524576006546130d5816140e9565b906130e36040519283613ccb565b8082526006835260209182810191847ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f845b83831061317b57505050506040519280840191818552518092526040840192945b8281106131435784840385f35b855180516001600160a01b03908116865281840151811686850152604091820151169085015294810194606090930192600101613136565b60038760019260409a9997989a5161319281613c95565b848060a01b038087541682528086880154168483015260028701541660408201528152019201920191909694939596613115565b50346105245780600319360112610524576003546040516001600160a01b039091168152602090f35b50608036600319011261052457613204613aa5565b61320c613abb565b916064359061322060ff6005541615613f50565b6044359284926001600160a01b0381838261323b8883614cce565b16918287528360209a60078c528180600160408c200154169861325e8d826146e5565b5061326985846146e5565b501615613508575b16156134de575b604051630dfe168160e01b81528a81600481875afa9081156134aa5788916134c1575b50848084169116036134b5575b508216936040519663095ea7b360e01b978881528a81806132cd8d8760048401613d2a565b03818b8b5af180156134aa578b92879492879261348d575b5016986132fe6040519485938493845260048401613d2a565b0381898b5af18015610abf57908994939291613470575b5085526007835260408520541660045491856103e861333881610f4c878d61403a565b604051636cfa229360e01b81529a8b968795869461335c940492336004870161404d565b03925af1938415610468578294613441575b506040516370a0823160e01b80825230600483015291908681602481855afa908115610422578491613414575b5080613402575b50506040519081523060048201528481602481865afa9182156103d757916133d5575b5080611db3575050604051908152f35b90508381813d83116133fb575b6133ec8183613ccb565b81010312610a7557515f6133c5565b503d6133e2565b61340d913390613d45565b5f806133a2565b90508681813d831161343a575b61342b8183613ccb565b81010312610a7557515f61339b565b503d613421565b9093508481813d8311613469575b6134598183613ccb565b81010312610a755751925f61336e565b503d61344f565b61348690853d871161110b576110fc8183613ccb565b505f613315565b6134a390853d871161110b576110fc8183613ccb565b505f6132e5565b6040513d8a823e3d90fd5b979096909350826132a8565b6134d891508b3d8d11610461576104538183613ccb565b5f61329b565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3884169750613278565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3882169350613271565b5060e036600319011261052457613547613aa5565b61354f613abb565b613557613b27565b61356660ff6005541615613f50565b8383918394815f14613a7e577f0000000000000000000000001844f04a2e2f0aef0f72ba3ef9d94ac9b07fa8bf915b15613a57577f00000000000000000000000031a5a7add82b1091821be91dececc13974c76e36945b6044356135ca81846146e5565b916135d7606435826146e5565b936001600160a01b031615613a26575b6001600160a01b0316156139f5575b60405163095ea7b360e01b81529060209082908190613642907f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b031660048401613d2a565b0381886001600160a01b038b165af180156112d8576139d6575b5060405163095ea7b360e01b815291602083806136a86064357f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b031660048401613d2a565b0381886001600160a01b038d165af19182156112d8576136f4936060936139b7575b50604051635a47ddc360e01b815293849283924291309160a43591608435918f8e60048a0161409e565b0381867f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc6001600160a01b03165af1801561040057613999575b506040516370a0823160e01b8082523060048301529490916001600160a01b039182169116602083602481845afa928315610422578493613964575b50602061378c936040518095819263095ea7b360e01b83528660048401613d2a565b038187855af190811561042257602493602092613947575b50604051938480928982523060048301525afa918215610400578392613913575b50803b1561089a57606483926040519485938492638dbdbe6d60e01b845282600485015260248401523360448401525af180156112d857613900575b506040518281523060048201526020816024816001600160a01b0386165afa9081156112d85785916138ce575b50806138b3575b50506040519081523060048201526020816024816001600160a01b0386165afa908115610400578391613881575b508061386d578280f35b610a489133906001600160a01b0316613d45565b90506020813d6020116138ab575b8161389c60209383613ccb565b81010312610a7557515f613863565b3d915061388f565b6138c79133906001600160a01b0316613d45565b5f80613835565b90506020813d6020116138f8575b816138e960209383613ccb565b81010312610a7557515f61382e565b3d91506138dc565b61390c90949194613c82565b925f613801565b9091506020813d60201161393f575b8161392f60209383613ccb565b8101031261089a5751905f6137c5565b3d9150613922565b61395d90833d851161110b576110fc8183613ccb565b505f6137a4565b92506020833d602011613991575b8161397f60209383613ccb565b81010312610d0157915191602061376a565b3d9150613972565b6139b09060603d8111611ef457611ee58183613ccb565b505061372e565b6139cf9060203d60201161110b576110fc8183613ccb565b505f6136ca565b6139ee9060203d60201161110b576110fc8183613ccb565b505f61365c565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b031697506135f6565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad386001600160a01b031696506135e7565b7f000000000000000000000000f93d924b54955e113965e51641f3601637090297946135bd565b7f0000000000000000000000005b4747849f72bf9d0e673955842fe9cacd69b18b91613595565b600435906001600160a01b0382168203610a7557565b602435906001600160a01b0382168203610a7557565b604435906001600160a01b0382168203610a7557565b606435906001600160a01b0382168203610a7557565b608435906001600160a01b0382168203610a7557565b35906001600160a01b0382168203610a7557565b60c435908115158203610a7557565b6060906003190112610a75576004356001600160a01b0381168103610a755790602435906044358015158103610a755790565b6060906003190112610a75576001600160a01b03906004358281168103610a7557916024359081168103610a75579060443590565b9181601f84011215610a75578235916001600160401b038311610a755760208381860195010111610a7557565b9181601f84011215610a75578235916001600160401b038311610a75576020808501948460051b010111610a7557565b600654811015613c175760065f52600360205f20910201905f90565b634e487b7160e01b5f52603260045260245ffd5b5f546001600160a01b03163303613c3e57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6001600160401b03811161281957604052565b606081019081106001600160401b0382111761281957604052565b604081019081106001600160401b0382111761281957604052565b90601f801991011681019081106001600160401b0382111761281957604052565b3d15613d25573d906001600160401b0382116128195760405191613d1a601f8201601f191660200184613ccb565b82523d5f602084013e565b606090565b6001600160a01b039091168152602081019190915260400190565b613d7a613d7f9392613d6c60405194859263a9059cbb60e01b602085015260248401613d2a565b03601f198101845283613ccb565b613d99565b565b90816020910312610a7557518015158103610a755790565b604051613df6916001600160a01b0316613db282613cb0565b5f806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af1613df0613cec565b91613e7e565b805190828215928315613e66575b50505015613e0f5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b613e769350820181019101613d81565b5f8281613e04565b91929015613ee05750815115613e92575090565b3b15613e9b5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015613ef35750805190602001fd5b6040519062461bcd60e51b82528160208060048301528251908160248401525f935b828510613f37575050604492505f838284010152601f80199101168101030190fd5b8481018201518686016044015293810193859350613f15565b15613f5757565b60405162461bcd60e51b815260206004820152600660248201526514185d5cd95960d21b6044820152606490fd5b8115613f8f570490565b634e487b7160e01b5f52601260045260245ffd5b90816020910312610a7557516001600160a01b0381168103610a755790565b51906001600160701b0382168203610a7557565b90816060910312610a7557613fea81613fc2565b916040613ff960208401613fc2565b92015163ffffffff81168103610a755790565b9190820180921161401957565b634e487b7160e01b5f52601160045260245ffd5b9190820391821161401957565b8181029291811591840414171561401957565b9391959492909560c085019660018060a01b03168552602085015260408401526060830152608082015260a0600f60fc1b910152565b90816060910312610a75578051916040602083015192015190565b9490989796929361010096929461012087019a60018060a01b03968780921689521660208801525f60408801526060870152608086015260a085015260c08401521660e08201520152565b6001600160401b0381116128195760051b60200190565b1561410757565b60405162461bcd60e51b815260206004820152600f60248201526e24b73b30b634b2103a37b5b2b724b760891b6044820152606490fd5b90816020910312610a75575160ff81168103610a755790565b60ff166012039060ff821161401957565b60ff16604d811161401957600a0a90565b91935f9390929091614193916001600160701b03166148b0565b938461419d575050565b6141a9929350846141cd565b90565b805115613c175760200190565b8051821015613c175760209160051b010190565b9192906040918251916141df83613cb0565b6001948584525f5b6020808210156142185786516020929161420082613c95565b5f82525f818301525f898301528288010152016141e7565b50509295909394919561422a816141ac565b516001600160a01b0395861690819052602092909190868461424b846141ac565b5101911690525f8761425c836141ac565b5101525f83877f0000000000000000000000001d368773735ee1e678950b7a97bca2cafb330cdc169360448a518094819363095ea7b360e01b8352886004840152811960248401525af1801561443157614414575b5090935f9485928851978893631e82ecdb60e31b855260a4850190600486015287602486015260a0604486015282518091528660c4860193019186905b89898484106143df5750505050505083838092306064830152600f60fc1b608483015203925af1938491849561434f575b505061432d57505050505f90565b8251111561433b5750015190565b634e487b7160e01b81526032600452602490fd5b909194503d8085843e6143628184613ccb565b82019181818403126113d8578051906001600160401b03821161089657019180601f840112156113d8578251614397816140e9565b936143a489519586613ccb565b818552838086019260051b82010192831161185a578301905b8282106143d05750505050925f8061431f565b815181529083019083016143bd565b8551805184168852808201518416888301528f015115158f8801528c99508d98506060909601959490940193909101906142ee565b61442a90843d861161110b576110fc8183613ccb565b505f6142b1565b88513d5f823e3d90fd5b9295949091939560018060a01b038094169060409788519263095ea7b360e01b908185526020968561447260049b878d8401613d2a565b039588815f98818a875af180156146db57908a92916146be575b5016938b51966370a0823160e01b94858952308c8a015260249a8a8a8d818b5afa998a156146b357908f9695949392918a9b614675575b508316808a5260088c529589205460ff161561463a5791818f8a9485948592519384928337810182815203925af16144f9613cec565b50156145fd5760448892878c938f5196879586948552840152818d8401525af180156145f357908692916145d6575b50868a51809481938252308b8301525afa9182156145cb578092614599575b5050906145539161402d565b9485156145605750505050565b5162461bcd60e51b8152928301526017908201527622b93937b91029bbb0b83834b733902a37b5b2b739901960491b6044820152606490fd5b9091508382813d83116145c4575b6145b18183613ccb565b810103126105245750516145535f614547565b503d6145a7565b8851903d90823e3d90fd5b6145ec90833d851161110b576110fc8183613ccb565b505f614528565b8a513d86823e3d90fd5b508a5162461bcd60e51b8152808a018890526017818a0152764572726f72205377617070696e6720546f6b656e73203160481b6044820152606490fd5b508d5162461bcd60e51b8152808d018b90526015818d01527415185c99d95d081b9bdd08105d5d1a1bdc9a5e9959605a1b6044820152606490fd5b8c80929c5081939495969798503d83116146ac575b6146948183613ccb565b810103126108725751988e95949392919060ff6144c3565b503d61468a565b508e513d8a823e3d90fd5b6146d4908a3d8c1161110b576110fc8183613ccb565b505f61448c565b8d513d89823e3d90fd5b6001600160a01b0390811690811561478357508115614747576040516323b872dd60e01b60208201523360248201523060448201526064808201849052815260a08101916001600160401b03831182841017612819576141a992604052613d99565b60405162461bcd60e51b8152602060048201526014602482015273125b9d985b1a59081d1bdad95b88185b5bdd5b9d60621b6044820152606490fd5b91505034156147ea577f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3816803b15610a75575f60049160405192838092630d0e30db60e41b825234905af1801561249f576147dd57503490565b6147e690613c82565b3490565b60405162461bcd60e51b815260206004820152600b60248201526a139bc8195d1a081cd95b9d60aa1b6044820152606490fd5b1561482457565b60405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c84092dce0eae840d8cadccee8d60631b6044820152606490fd5b9190811015613c175760051b0190565b60018060a01b0360406002828551169360018060a01b03199485825416178155600181018460208801511686825416179055019301511690825416179055565b90623cda209081810291818304149015171561401957623cda299081830283159284820414831715614019576148ec6148f2916148f79361400c565b8461403a565b614e07565b906107cd808402938404141715614019576107ca916149159161402d565b0490565b909396959294919461492f866111ed878561403a565b6040805163313ce56760e01b8082529891956001600160a01b039485169560209593949093919286816004818b5afa908115614b4d57610305614983939261497d925f91614b875750614157565b90613f85565b9b16968651916318160ddd60e01b835285836004818c5afa928315614431575f93614b57575b509060049186849a8a5194858092637464fc3d60e01b82525afa928315614b4d579187969593918b95935f93614b10575b5082614a6b575b505050506149f392916111ed9161403a565b96600485518095819382525afa928315614a625750614a296103056111ed94614a34979694614a2f945f92614a45575050614157565b8861403a565b61403a565b80821015614a40575090565b905090565b614a5b9250803d106103d0576103c18183613ccb565b5f80610386565b513d5f823e3d90fd5b614a7b614a8692614a809261403a565b614b9e565b91614b9e565b90818111614a95575b806149e1565b8193959650614aa592945061402d565b6127108082029082820481148315171561401957614add93614ad1614ad6926111ed940494859261400c565b61402d565b918461403a565b9081614af0575b91818594938993614a8f565b6149f3929750614b058594926111ed9261400c565b979250819350614ae4565b80939294965088919597983d8311614b46575b614b2d8183613ccb565b810103126105245750918993918796959351915f6149da565b503d614b23565b89513d5f823e3d90fd5b90928682813d8311614b80575b614b6e8183613ccb565b810103126105245750519160046149a9565b503d614b64565b6103fa91508a3d8c116103d0576103c18183613ccb565b8015614cc957614a34815f908360801c80614cbd575b508060401c80614cb0575b508060201c80614ca3575b508060101c80614c96575b508060081c80614c89575b508060041c80614c7c575b508060021c80614c6f575b50600191828092811c614c68575b1c1b614c108185613f85565b01811c614c1d8185613f85565b01811c614c2a8185613f85565b01811c614c378185613f85565b01811c614c448185613f85565b01811c614c518185613f85565b01811c614c5e8185613f85565b01901c8092613f85565b0181614c04565b600291509101905f614bf6565b600491509101905f614beb565b600891509101905f614be0565b601091509101905f614bd5565b602091509101905f614bca565b604091509101905f614bbf565b9150506080905f614bb4565b505f90565b6001600160a01b039291839081831615614ddd575b81811615614db4575b6040516306801cc360e41b815292821660048401521660248201525f60448201526020816064817f0000000000000000000000002da25e7446a70d7be65fd4c053948becaa6374c887165afa801561249f5783915f91614d96575b501691825f526007602052600260405f2001541615614d6257565b60405162461bcd60e51b815260206004820152600c60248201526b24b73b30b634b2102830b4b960a11b6044820152606490fd5b614dae915060203d8111610461576104538183613ccb565b5f614d47565b50807f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3816614cec565b7f000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad3882169250614ce3565b8015614cc957600181600160801b811015614f2b575b614ecd614ec0614eb3614ea6614e99614e8c614a34976008614eda98600160401b811015614f1e575b640100000000811015614f11575b62010000811015614f05575b610100811015614ef9575b6010811015614eec575b1015614ee4575b614e86818b613f85565b9061400c565b60011c614e86818a613f85565b60011c614e868189613f85565b60011c614e868188613f85565b60011c614e868187613f85565b60011c614e868186613f85565b60011c614e868185613f85565b60011c8092613f85565b60011b614e7c565b60041c9160021b91614e75565b811c9160041b91614e6b565b60101c91811b91614e60565b60201c9160101b91614e54565b60401c9160201b91614e46565b50600160401b9050608082901c614e1d56fea26469706673582212205580da31fad79b4b0d6fed01ecab30f78ec6ed9d3dd0962de4d713871df873fb64736f6c63430008140033
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.