Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 331 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Multicall | 24510152 | 4 hrs ago | IN | 0.01 ETH | 0.00000496 | ||||
| Multicall | 24509882 | 5 hrs ago | IN | 0.5 ETH | 0.00004118 | ||||
| Multicall | 24509818 | 5 hrs ago | IN | 0.01 ETH | 0.00005352 | ||||
| Multicall | 24509778 | 5 hrs ago | IN | 0.05 ETH | 0.00072042 | ||||
| Multicall | 24509373 | 6 hrs ago | IN | 0.05078558 ETH | 0.00014736 | ||||
| Multicall | 24508763 | 9 hrs ago | IN | 0.0005 ETH | 0.00001722 | ||||
| Multicall | 24508723 | 9 hrs ago | IN | 0.0005 ETH | 0.00001706 | ||||
| Multicall | 24508038 | 11 hrs ago | IN | 0.0005 ETH | 0.00000589 | ||||
| Multicall | 24507466 | 13 hrs ago | IN | 0.0005 ETH | 0.00001745 | ||||
| Multicall | 24507452 | 13 hrs ago | IN | 0.0005 ETH | 0.00001776 | ||||
| Multicall | 24507166 | 14 hrs ago | IN | 0 ETH | 0.00000326 | ||||
| Multicall | 24506954 | 15 hrs ago | IN | 0.0005 ETH | 0.00000631 | ||||
| Multicall | 24506930 | 15 hrs ago | IN | 0.03928469 ETH | 0.00010475 | ||||
| Multicall | 24506928 | 15 hrs ago | IN | 0.03927673 ETH | 0.00013443 | ||||
| Multicall | 24506779 | 15 hrs ago | IN | 0.012345 ETH | 0.00038329 | ||||
| Ensure Allowance | 24506110 | 17 hrs ago | IN | 0 ETH | 0.00000247 | ||||
| Multicall | 24505582 | 19 hrs ago | IN | 0.0005 ETH | 0.00033265 | ||||
| Multicall | 24505364 | 20 hrs ago | IN | 0.00177514 ETH | 0.00002195 | ||||
| Multicall | 24505313 | 20 hrs ago | IN | 0.00005518 ETH | 0.00001688 | ||||
| Multicall | 24505299 | 20 hrs ago | IN | 0.00458729 ETH | 0.00002071 | ||||
| Multicall | 24505250 | 20 hrs ago | IN | 0 ETH | 0.00051825 | ||||
| Multicall | 24504785 | 22 hrs ago | IN | 0.0005 ETH | 0.00000558 | ||||
| Multicall | 24504453 | 23 hrs ago | IN | 0 ETH | 0.00000494 | ||||
| Multicall | 24504279 | 24 hrs ago | IN | 0 ETH | 0.00000697 | ||||
| Multicall | 24504043 | 24 hrs ago | IN | 0 ETH | 0.00001639 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Reveal | 24510152 | 4 hrs ago | 0.01 ETH | ||||
| Swap Exact In | 24509882 | 5 hrs ago | 0.5 ETH | ||||
| Swap Exact In | 24509818 | 5 hrs ago | 0.01 ETH | ||||
| Swap Exact In | 24509778 | 5 hrs ago | 0.05 ETH | ||||
| Transfer | 24509373 | 6 hrs ago | 0.00025266 ETH | ||||
| Transfer | 24509373 | 6 hrs ago | 0.05053292 ETH | ||||
| Reveal | 24508763 | 9 hrs ago | 0.0005 ETH | ||||
| Reveal | 24508723 | 9 hrs ago | 0.0005 ETH | ||||
| Reveal | 24508038 | 11 hrs ago | 0.0005 ETH | ||||
| Reveal | 24507466 | 13 hrs ago | 0.0005 ETH | ||||
| Reveal | 24507452 | 13 hrs ago | 0.0005 ETH | ||||
| Reveal | 24506954 | 15 hrs ago | 0.0005 ETH | ||||
| Transfer | 24506930 | 15 hrs ago | 0.00019544 ETH | ||||
| Transfer* | 24506930 | 15 hrs ago | 0.03908924 ETH | ||||
| Transfer | 24506928 | 15 hrs ago | 0.03909512 ETH | ||||
| Transfer* | 24506779 | 15 hrs ago | 0.012345 ETH | ||||
| Reveal | 24505582 | 19 hrs ago | 0.0005 ETH | ||||
| Swap Exact In | 24505364 | 20 hrs ago | 0.00177514 ETH | ||||
| Swap Exact In | 24505313 | 20 hrs ago | 0.00005518 ETH | ||||
| Swap Exact In | 24505299 | 20 hrs ago | 0.00458729 ETH | ||||
| Swap Exact In | 24505250 | 20 hrs ago | 0.02226339 ETH | ||||
| Transfer | 24505250 | 20 hrs ago | 0.02226339 ETH | ||||
| Reveal | 24504785 | 22 hrs ago | 0.0005 ETH | ||||
| Reveal | 24502262 | 30 hrs ago | 0.0005 ETH | ||||
| Reveal | 24502262 | 30 hrs ago | 0.0005 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
zRouter
Compiler Version
v0.8.33+commit.64118f21
Optimization Enabled:
Yes with 9999999 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.33;
/// @dev uniV2 / uniV3 / uniV4 / zAMM
/// multi-amm multi-call router
/// optimized with simple abi.
/// Includes trusted routers,
/// and a Curve AMM swapper,
/// as well as Lido staker,
/// and generic executor.
contract zRouter {
error BadSwap();
error Expired();
error Slippage();
error InvalidId();
error Unauthorized();
error InvalidMsgVal();
error SwapExactInFail();
error SwapExactOutFail();
error ETHTransferFailed();
error SnwapSlippage(address token, uint256 received, uint256 minimum);
SafeExecutor public immutable safeExecutor;
modifier checkDeadline(uint256 deadline) {
require(block.timestamp <= deadline, Expired());
_;
}
event OwnershipTransferred(address indexed from, address indexed to);
constructor() payable {
safeExecutor = new SafeExecutor();
safeApprove(STETH, WSTETH, type(uint256).max); // lido
emit OwnershipTransferred(address(0), _owner = tx.origin);
}
function swapV2(
address to,
bool exactOut,
address tokenIn,
address tokenOut,
uint256 swapAmount,
uint256 amountLimit,
uint256 deadline
) public payable checkDeadline(deadline) returns (uint256 amountIn, uint256 amountOut) {
bool ethIn = tokenIn == address(0);
bool ethOut = tokenOut == address(0);
if (ethIn) tokenIn = WETH;
if (ethOut) tokenOut = WETH;
bool sushiSwap;
unchecked {
if (deadline == type(uint256).max) {
(sushiSwap, deadline) = (true, block.timestamp + 30 minutes);
}
}
(address pool, bool zeroForOne) = _v2PoolFor(tokenIn, tokenOut, sushiSwap);
(uint112 r0, uint112 r1,) = IV2Pool(pool).getReserves();
(uint256 resIn, uint256 resOut) = zeroForOne ? (r0, r1) : (r1, r0);
unchecked {
if (exactOut) {
amountOut = swapAmount; // target
uint256 n = resIn * amountOut * 1000;
uint256 d = (resOut - amountOut) * 997;
amountIn = (n + d - 1) / d; // ceil-div
require(amountLimit == 0 || amountIn <= amountLimit, Slippage());
} else {
if (swapAmount == 0) {
amountIn = ethIn ? msg.value : balanceOf(tokenIn);
if (amountIn == 0) revert BadSwap();
} else {
amountIn = swapAmount;
}
amountOut = (amountIn * 997 * resOut) / (resIn * 1000 + amountIn * 997);
require(amountLimit == 0 || amountOut >= amountLimit, Slippage());
}
if (!_useTransientBalance(pool, tokenIn, 0, amountIn)) {
if (_useTransientBalance(address(this), tokenIn, 0, amountIn)) {
safeTransfer(tokenIn, pool, amountIn);
} else if (ethIn) {
wrapETH(pool, amountIn);
if (to != address(this)) {
if (msg.value > amountIn) {
_safeTransferETH(msg.sender, msg.value - amountIn);
}
}
} else {
safeTransferFrom(tokenIn, msg.sender, pool, amountIn);
}
}
}
if (zeroForOne) {
IV2Pool(pool).swap(0, amountOut, ethOut ? address(this) : to, "");
} else {
IV2Pool(pool).swap(amountOut, 0, ethOut ? address(this) : to, "");
}
if (ethOut) {
unwrapETH(amountOut);
_safeTransferETH(to, amountOut);
} else {
depositFor(tokenOut, 0, amountOut, to); // marks output target
}
}
function swapV3(
address to,
bool exactOut,
uint24 swapFee,
address tokenIn,
address tokenOut,
uint256 swapAmount,
uint256 amountLimit,
uint256 deadline
) public payable checkDeadline(deadline) returns (uint256 amountIn, uint256 amountOut) {
bool ethIn = tokenIn == address(0);
bool ethOut = tokenOut == address(0);
if (ethIn) tokenIn = WETH;
if (ethOut) tokenOut = WETH;
(address pool, bool zeroForOne) = _v3PoolFor(tokenIn, tokenOut, swapFee);
uint160 sqrtPriceLimitX96 = zeroForOne ? MIN_SQRT_RATIO_PLUS_ONE : MAX_SQRT_RATIO_MINUS_ONE;
unchecked {
if (!exactOut && swapAmount == 0) {
swapAmount = ethIn ? msg.value : balanceOf(tokenIn);
if (swapAmount == 0) revert BadSwap();
}
(int256 a0, int256 a1) = IV3Pool(pool)
.swap(
ethOut ? address(this) : to,
zeroForOne,
exactOut ? -(int256(swapAmount)) : int256(swapAmount),
sqrtPriceLimitX96,
abi.encodePacked(ethIn, ethOut, msg.sender, tokenIn, tokenOut, to, swapFee)
);
if (amountLimit != 0) {
if (exactOut) require(uint256(zeroForOne ? a0 : a1) <= amountLimit, Slippage());
else require(uint256(-(zeroForOne ? a1 : a0)) >= amountLimit, Slippage());
}
// ── return values ────────────────────────────────
// ── translate pool deltas to user-facing amounts ─
(int256 dIn, int256 dOut) = zeroForOne ? (a0, a1) : (a1, a0);
amountIn = dIn >= 0 ? uint256(dIn) : uint256(-dIn);
amountOut = dOut <= 0 ? uint256(-dOut) : uint256(dOut);
// Handle ETH input refund (separate from output tracking)
if (ethIn) {
if ((swapAmount = address(this).balance) != 0 && to != address(this)) {
_safeTransferETH(msg.sender, swapAmount);
}
}
// Handle output tracking for chaining (must always run when !ethOut)
if (!ethOut) {
depositFor(tokenOut, 0, amountOut, to);
}
}
}
/// @dev `uniswapV3SwapCallback`.
fallback() external payable {
assembly ("memory-safe") {
if gt(tload(0x00), 0) { revert(0, 0) }
}
unchecked {
int256 amount0Delta;
int256 amount1Delta;
bool ethIn;
bool ethOut;
address payer;
address tokenIn;
address tokenOut;
address to;
uint24 swapFee;
assembly ("memory-safe") {
amount0Delta := calldataload(0x4)
amount1Delta := calldataload(0x24)
ethIn := byte(0, calldataload(0x84))
ethOut := byte(0, calldataload(add(0x84, 1)))
payer := shr(96, calldataload(add(0x84, 2)))
tokenIn := shr(96, calldataload(add(0x84, 22)))
tokenOut := shr(96, calldataload(add(0x84, 42)))
to := shr(96, calldataload(add(0x84, 62)))
swapFee := and(shr(232, calldataload(add(0x84, 82))), 0xFFFFFF)
}
require(amount0Delta != 0 || amount1Delta != 0, BadSwap());
(address pool, bool zeroForOne) = _v3PoolFor(tokenIn, tokenOut, swapFee);
require(msg.sender == pool, Unauthorized());
uint256 amountRequired = uint256(zeroForOne ? amount0Delta : amount1Delta);
if (_useTransientBalance(address(this), tokenIn, 0, amountRequired)) {
safeTransfer(tokenIn, pool, amountRequired);
} else if (ethIn) {
wrapETH(pool, amountRequired);
} else {
safeTransferFrom(tokenIn, payer, pool, amountRequired);
}
if (ethOut) {
uint256 amountOut = uint256(-(zeroForOne ? amount1Delta : amount0Delta));
unwrapETH(amountOut);
_safeTransferETH(to, amountOut);
}
}
}
function swapV4(
address to,
bool exactOut,
uint24 swapFee,
int24 tickSpace,
address tokenIn,
address tokenOut,
uint256 swapAmount,
uint256 amountLimit,
uint256 deadline
) public payable checkDeadline(deadline) returns (uint256 amountIn, uint256 amountOut) {
if (!exactOut && swapAmount == 0) {
swapAmount = tokenIn == address(0) ? msg.value : balanceOf(tokenIn);
if (swapAmount == 0) revert BadSwap();
}
(amountIn, amountOut) = abi.decode(
IV4PoolManager(V4_POOL_MANAGER)
.unlock(
abi.encode(
msg.sender,
to,
exactOut,
swapFee,
tickSpace,
tokenIn,
tokenOut,
swapAmount,
amountLimit
)
),
(uint256, uint256)
);
depositFor(tokenOut, 0, amountOut, to); // marks output target
}
/// @dev Handle V4 PoolManager swap callback - hookless default.
function unlockCallback(bytes calldata callbackData)
public
payable
returns (bytes memory result)
{
require(msg.sender == V4_POOL_MANAGER, Unauthorized());
assembly ("memory-safe") {
if gt(tload(0x00), 0) { revert(0, 0) }
}
(
address payer,
address to,
bool exactOut,
uint24 swapFee,
int24 tickSpace,
address tokenIn,
address tokenOut,
uint256 swapAmount,
uint256 amountLimit
) = abi.decode(
callbackData,
(address, address, bool, uint24, int24, address, address, uint256, uint256)
);
bool zeroForOne = tokenIn < tokenOut;
bool ethIn = tokenIn == address(0);
V4PoolKey memory key = V4PoolKey(
zeroForOne ? tokenIn : tokenOut,
zeroForOne ? tokenOut : tokenIn,
swapFee,
tickSpace,
address(0)
);
unchecked {
int256 delta = _swap(swapAmount, key, zeroForOne, exactOut);
uint256 takeAmount = zeroForOne
? (!exactOut
? uint256(uint128(delta.amount1()))
: uint256(uint128(-delta.amount0())))
: (!exactOut
? uint256(uint128(delta.amount0()))
: uint256(uint128(-delta.amount1())));
IV4PoolManager(msg.sender).sync(tokenIn);
uint256 amountIn = !exactOut ? swapAmount : takeAmount;
if (_useTransientBalance(address(this), tokenIn, 0, amountIn)) {
if (tokenIn != address(0)) {
safeTransfer(
tokenIn,
msg.sender, // V4_POOL_MANAGER
amountIn
);
}
} else if (!ethIn) {
safeTransferFrom(
tokenIn,
payer,
msg.sender, // V4_POOL_MANAGER
amountIn
);
}
uint256 amountOut = !exactOut ? takeAmount : swapAmount;
if (amountLimit != 0 && (exactOut ? takeAmount > amountLimit : amountOut < amountLimit))
{
revert Slippage();
}
IV4PoolManager(msg.sender)
.settle{value: ethIn ? (exactOut ? takeAmount : swapAmount) : 0}();
IV4PoolManager(msg.sender).take(tokenOut, to, amountOut);
result = abi.encode(amountIn, amountOut);
if (ethIn) {
uint256 ethRefund = address(this).balance;
if (ethRefund != 0 && to != address(this)) {
_safeTransferETH(payer, ethRefund);
}
}
}
}
function _swap(uint256 swapAmount, V4PoolKey memory key, bool zeroForOne, bool exactOut)
internal
returns (int256 delta)
{
unchecked {
delta = IV4PoolManager(msg.sender)
.swap(
key,
V4SwapParams(
zeroForOne,
exactOut ? int256(swapAmount) : -int256(swapAmount),
zeroForOne ? MIN_SQRT_RATIO_PLUS_ONE : MAX_SQRT_RATIO_MINUS_ONE
),
""
);
}
}
/// @dev Pull in full and refund excess against zAMM.
function swapVZ(
address to,
bool exactOut,
uint256 feeOrHook,
address tokenIn,
address tokenOut,
uint256 idIn,
uint256 idOut,
uint256 swapAmount,
uint256 amountLimit,
uint256 deadline
) public payable checkDeadline(deadline) returns (uint256 amountIn, uint256 amountOut) {
(address token0, address token1, bool zeroForOne) = _sortTokens(tokenIn, tokenOut);
(uint256 id0, uint256 id1) = tokenIn == token0 ? (idIn, idOut) : (idOut, idIn);
PoolKey memory key = PoolKey(id0, id1, token0, token1, feeOrHook);
bool ethIn = tokenIn == address(0);
if (!exactOut && swapAmount == 0) {
if (ethIn) {
swapAmount = msg.value;
} else if (idIn == 0) {
swapAmount = balanceOf(tokenIn);
} else {
swapAmount = IERC6909(tokenIn).balanceOf(address(this), idIn);
}
if (swapAmount == 0) revert BadSwap();
}
if (!_useTransientBalance(
address(this), tokenIn, idIn, !exactOut ? swapAmount : amountLimit
)) {
if (!ethIn) {
if (idIn == 0) {
safeTransferFrom(
tokenIn, msg.sender, address(this), !exactOut ? swapAmount : amountLimit
);
} else {
IERC6909(tokenIn)
.transferFrom(
msg.sender, address(this), idIn, !exactOut ? swapAmount : amountLimit
);
}
}
}
address dst = deadline != type(uint256).max ? ZAMM : ZAMM_0; // support hookless zAMM
unchecked {
if (dst == ZAMM_0) {
key.feeOrHook = uint256(uint96(key.feeOrHook));
deadline = block.timestamp + 30 minutes;
}
}
uint256 swapResult;
if (!exactOut) {
bytes4 sel = (dst == ZAMM) ? bytes4(0x3c5eec50) : bytes4(0x7466fde7);
bytes memory callData =
abi.encodeWithSelector(sel, key, swapAmount, amountLimit, zeroForOne, to, deadline);
(bool ok, bytes memory ret) = dst.call{value: ethIn ? swapAmount : 0}(callData);
require(ok, SwapExactInFail());
swapResult = abi.decode(ret, (uint256));
} else {
bytes4 sel = (dst == ZAMM) ? bytes4(0x38c3f8db) : bytes4(0xd4ff3f0e);
bytes memory callData =
abi.encodeWithSelector(sel, key, swapAmount, amountLimit, zeroForOne, to, deadline);
(bool ok, bytes memory ret) = dst.call{value: ethIn ? amountLimit : 0}(callData);
require(ok, SwapExactOutFail());
swapResult = abi.decode(ret, (uint256));
}
// ── return values ────────────────────────────────
(amountIn, amountOut) = exactOut ? (swapResult, swapAmount) : (swapAmount, swapResult);
if (exactOut && to != address(this)) {
uint256 refund;
if (ethIn) {
refund = address(this).balance;
if (refund != 0) _safeTransferETH(msg.sender, refund);
} else if (idIn == 0) {
refund = balanceOf(tokenIn);
if (refund != 0) safeTransfer(tokenIn, msg.sender, refund);
} else {
refund = IERC6909(tokenIn).balanceOf(address(this), idIn);
if (refund != 0) IERC6909(tokenIn).transfer(msg.sender, idIn, refund);
}
} else {
depositFor(tokenOut, idOut, amountOut, to); // marks output target
}
}
function swapCurve(
address to,
bool exactOut,
address[11] calldata route,
uint256[4][5] calldata swapParams, // [i, j, swap_type, pool_type]
address[5] calldata basePools, // for meta pools (only used by type=2 get_dx)
uint256 swapAmount,
uint256 amountLimit,
uint256 deadline
) public payable checkDeadline(deadline) returns (uint256 amountIn, uint256 amountOut) {
// ---- resolve last hop & output token ----
address inputToken = route[0];
address outputToken;
uint256 lastIdx;
unchecked {
for (uint256 i; i < 5; ++i) {
address pool = route[i * 2 + 1];
if (pool == address(0)) break;
outputToken = route[(i + 1) * 2];
lastIdx = i;
}
}
bool ethIn = _isETH(inputToken);
// ---- compute working amount ----
uint256 amount = swapAmount;
if (exactOut) {
// backward pass: Curve-style get_dx to find required input:
unchecked {
for (uint256 k = lastIdx + 1; k != 0;) {
uint256 i = --k;
address pool = route[i * 2 + 1];
uint256[4] memory p = swapParams[i]; // [i, j, swap_type, pool_type]
uint256 st = p[2];
uint256 pt = p[3];
if (st == 8) {
// ETH<->WETH is 1:1
} else if (st == 1) {
if (pt == 10) {
int128 pi = int128(int256(p[0]));
int128 pj = int128(int256(p[1]));
amount = IStableNgPool(pool).get_dx(pi, pj, amount);
} else {
amount = ICryptoNgPool(pool).get_dx(p[0], p[1], amount);
}
} else if (st == 2) {
int128 pi = int128(int256(p[0]));
int128 pj = int128(int256(p[1]));
if (pi > 0 && pj > 0) {
amount = IStableNgPool(basePools[i]).get_dx(pi - 1, pj - 1, amount);
} else {
amount = IStableNgMetaPool(pool).get_dx_underlying(pi, pj, amount);
}
} else if (st == 4) {
// inverse of add_liquidity (approx):
amount = (pt == 10)
? IStableNgPool(pool)
.calc_withdraw_one_coin(amount, int128(int256(p[0])))
: ICryptoNgPool(pool).calc_withdraw_one_coin(amount, p[0]);
} else if (st == 6) {
if (pt == 10) {
uint256[8] memory a;
a[p[1]] = amount;
amount = IStableNgPool(pool).calc_token_amount(a, false);
} else if (pt == 20) {
uint256[2] memory a2;
a2[p[1]] = amount;
amount = ITwoCryptoNgPool(pool).calc_token_amount(a2, false);
} else if (pt == 30) {
uint256[3] memory a3;
a3[p[1]] = amount;
amount = ITriCryptoNgPool(pool).calc_token_amount(a3, false);
} else {
revert BadSwap();
}
} else {
revert BadSwap();
}
}
}
amountIn = amount;
if (amountLimit != 0 && amountIn > amountLimit) revert Slippage();
} else {
// exact-in flow:
if (swapAmount == 0) {
amountIn = ethIn ? msg.value : balanceOf(inputToken);
if (amountIn == 0) revert BadSwap();
} else {
amountIn = swapAmount;
if (ethIn && msg.value != amountIn) revert InvalidMsgVal();
}
}
// ---- pre-fund router (Curve pools pull via transferFrom(router)) ----
address firstToken = ethIn ? WETH : inputToken;
{
uint256 need = amountIn;
if (!_useTransientBalance(address(this), firstToken, 0, need)) {
if (ethIn) {
if (msg.value < need) revert InvalidMsgVal();
wrap(need); // wrap exactly what we need as WETH
} else {
safeTransferFrom(firstToken, msg.sender, address(this), need);
}
}
}
// ---- execute the route (forward pass) ----
address curIn = inputToken;
amount = amountIn; // start with dx
unchecked {
for (uint256 i; i <= lastIdx; ++i) {
address pool = route[i * 2 + 1];
address nextToken = route[(i + 1) * 2];
uint256[4] memory p = swapParams[i]; // [i, j, swap_type, pool_type]
uint256 st = p[2];
uint256 pt = p[3];
if (st == 8) {
if (_isETH(curIn) && nextToken == WETH) {
// if first hop, we already wrapped in pre-fund; otherwise wrap what we just got:
if (i != 0) {
if (address(this).balance < amount) revert BadSwap();
wrap(amount);
}
curIn = WETH;
} else if (curIn == WETH && _isETH(nextToken)) {
unwrapETH(amount);
curIn = address(0); // normalize to 0x00 internally
} else {
revert BadSwap();
}
continue;
}
// ---- lazy approve current input token for this pool (ERC20 only) ----
address inToken = _isETH(curIn) ? WETH : curIn;
if (allowance(inToken, address(this), pool) == 0) {
safeApprove(inToken, pool, type(uint256).max);
}
// track output balance before hop
uint256 outBalBefore =
_isETH(nextToken) ? address(this).balance : balanceOf(nextToken);
// perform hop:
if (st == 1) {
if (pt == 10) {
IStableNgPool(pool)
.exchange(int128(int256(p[0])), int128(int256(p[1])), amount, 0);
} else {
ICryptoNgPool(pool).exchange(p[0], p[1], amount, 0);
}
} else if (st == 2) {
IStableNgMetaPool(pool)
.exchange_underlying(int128(int256(p[0])), int128(int256(p[1])), amount, 0);
} else if (st == 4) {
if (pt == 10) {
uint256[8] memory a;
a[p[0]] = amount;
IStableNgPool(pool).add_liquidity(a, 0);
} else if (pt == 20) {
uint256[2] memory a2;
a2[p[0]] = amount;
ITwoCryptoNgPool(pool).add_liquidity(a2, 0);
} else if (pt == 30) {
uint256[3] memory a3;
a3[p[0]] = amount;
ITriCryptoNgPool(pool).add_liquidity(a3, 0);
} else {
revert BadSwap();
}
} else if (st == 6) {
if (pt == 10) {
IStableNgPool(pool)
.remove_liquidity_one_coin(amount, int128(int256(p[1])), 0);
} else {
ICryptoNgPool(pool).remove_liquidity_one_coin(amount, p[1], 0);
}
} else {
revert BadSwap();
}
// compute output of hop:
uint256 outBalAfter =
_isETH(nextToken) ? address(this).balance : balanceOf(nextToken);
if (outBalAfter <= outBalBefore) revert BadSwap();
amount = outBalAfter - outBalBefore; // next hop input
curIn = nextToken;
}
}
// ---- finalize & slippage ----
if (!exactOut) {
amountOut = amount;
if (amountLimit != 0 && amountOut < amountLimit) revert Slippage();
} else {
// actual produced amount is `amount`; must be >= desired swapAmount:
if (amount < swapAmount) revert Slippage();
amountOut = swapAmount; // user-facing target
}
// ---- deliver final output to `to` and refund surplus output (exactOut) ----
if (!exactOut) {
// deliver full amount for exact-in:
if (_isETH(outputToken)) {
_safeTransferETH(to, amount);
} else if (to == address(this)) {
depositFor(outputToken, 0, amount, to); // chaining
} else {
safeTransfer(outputToken, to, amount);
}
} else {
// send only swapAmount to `to`; refund surplus to msg.sender:
uint256 surplus = amount - swapAmount;
if (_isETH(outputToken)) {
// pay receiver
_safeTransferETH(to, swapAmount);
// refund any extra output
if (surplus != 0) _safeTransferETH(msg.sender, surplus);
} else {
if (to == address(this)) {
// chaining: only mark the requested target amount
depositFor(outputToken, 0, swapAmount, to);
} else {
safeTransfer(outputToken, to, swapAmount);
}
if (surplus != 0) safeTransfer(outputToken, msg.sender, surplus);
}
}
// ---- leftover input refund (exactOut only, not chaining) ----
if (exactOut && to != address(this)) {
if (ethIn) {
// refund any ETH dust first:
uint256 e = address(this).balance;
if (e != 0) _safeTransferETH(msg.sender, e);
// refund any *WETH* dust created by positive slippage:
uint256 w = balanceOf(WETH);
if (w != 0) {
unwrapETH(w);
_safeTransferETH(msg.sender, w);
}
} else {
// non-ETH inputs already use `firstToken`:
uint256 refund = balanceOf(firstToken);
if (refund != 0) safeTransfer(firstToken, msg.sender, refund);
}
}
}
function _isETH(address a) internal pure returns (bool r) {
assembly { r := or(iszero(a), eq(a, CURVE_ETH)) }
}
/// @dev To be called for zAMM following deposit() or other swaps in sequence.
function addLiquidity(
PoolKey calldata poolKey,
uint256 amount0Desired,
uint256 amount1Desired,
uint256 amount0Min,
uint256 amount1Min,
address to,
uint256 deadline
) public payable returns (uint256 amount0, uint256 amount1, uint256 liquidity) {
bool ethIn = (poolKey.token0 == address(0));
(amount0, amount1, liquidity) = IZAMM(ZAMM).addLiquidity{value: ethIn ? amount0Desired : 0}(
poolKey, amount0Desired, amount1Desired, amount0Min, amount1Min, to, deadline
);
}
function ensureAllowance(address token, bool is6909, address to) public payable onlyOwner {
if (is6909) IERC6909(token).setOperator(to, true);
else safeApprove(token, to, type(uint256).max);
}
// ** PERMIT HELPERS
function permit(address token, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
public
payable
{
IERC2612(token).permit(msg.sender, address(this), value, deadline, v, r, s);
}
function permitDAI(uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)
public
payable
{
IDAIPermit(DAI).permit(msg.sender, address(this), nonce, expiry, true, v, r, s);
}
function permit2TransferFrom(
address token,
uint256 amount,
uint256 nonce,
uint256 deadline,
bytes calldata signature
) public payable {
IPermit2(PERMIT2)
.permitTransferFrom(
IPermit2.PermitTransferFrom({
permitted: IPermit2.TokenPermissions({token: token, amount: amount}),
nonce: nonce,
deadline: deadline
}),
IPermit2.SignatureTransferDetails({to: address(this), requestedAmount: amount}),
msg.sender,
signature
);
depositFor(token, 0, amount, address(this));
}
function permit2BatchTransferFrom(
IPermit2.TokenPermissions[] calldata permitted,
uint256 nonce,
uint256 deadline,
bytes calldata signature
) public payable {
uint256 len = permitted.length;
IPermit2.SignatureTransferDetails[] memory details =
new IPermit2.SignatureTransferDetails[](len);
for (uint256 i; i != len; ++i) {
details[i] = IPermit2.SignatureTransferDetails({
to: address(this), requestedAmount: permitted[i].amount
});
}
IPermit2(PERMIT2)
.permitBatchTransferFrom(
IPermit2.PermitBatchTransferFrom({
permitted: permitted, nonce: nonce, deadline: deadline
}),
details,
msg.sender,
signature
);
for (uint256 i; i != len; ++i) {
depositFor(permitted[i].token, 0, permitted[i].amount, address(this));
}
}
// ** MULTISWAP HELPER
function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i; i != data.length; ++i) {
(bool ok, bytes memory result) = address(this).delegatecall(data[i]);
if (!ok) {
assembly ("memory-safe") {
revert(add(result, 0x20), mload(result))
}
}
results[i] = result;
}
}
// ** TRANSIENT STORAGE
function deposit(address token, uint256 id, uint256 amount) public payable {
if (msg.value != 0) {
require(id == 0, InvalidId());
if (token == WETH) {
require(msg.value == amount, InvalidMsgVal());
_safeTransferETH(WETH, amount); // wrap to WETH
} else {
require(msg.value == (token == address(0) ? amount : 0), InvalidMsgVal());
}
}
if (token != address(0) && msg.value == 0) {
if (id == 0) safeTransferFrom(token, msg.sender, address(this), amount);
else IERC6909(token).transferFrom(msg.sender, address(this), id, amount);
}
depositFor(token, id, amount, address(this)); // transient storage tracker
}
function _useTransientBalance(address user, address token, uint256 id, uint256 amount)
internal
returns (bool credited)
{
assembly ("memory-safe") {
let m := mload(0x40)
mstore(0x00, user)
mstore(0x20, token)
mstore(0x40, id)
let slot := keccak256(0x00, 0x60)
let bal := tload(slot)
if iszero(lt(bal, amount)) {
tstore(slot, sub(bal, amount))
credited := 1
}
mstore(0x40, m)
}
}
function _safeTransferETH(address to, uint256 amount) internal {
if (to == address(this)) {
depositFor(address(0), 0, amount, to);
return;
}
assembly ("memory-safe") {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
}
}
// ** RECEIVER & SWEEPER
receive() external payable {}
function sweep(address token, uint256 id, uint256 amount, address to) public payable {
if (token == address(0)) {
_safeTransferETH(to, amount == 0 ? address(this).balance : amount);
} else if (id == 0) {
safeTransfer(token, to, amount == 0 ? balanceOf(token) : amount);
} else {
IERC6909(token)
.transfer(
to, id, amount == 0 ? IERC6909(token).balanceOf(address(this), id) : amount
);
}
}
// ** WETH HELPERS
function wrap(uint256 amount) public payable {
amount = amount == 0 ? address(this).balance : amount;
_safeTransferETH(WETH, amount);
depositFor(WETH, 0, amount, address(this));
}
function unwrap(uint256 amount) public payable {
unwrapETH(amount == 0 ? balanceOf(WETH) : amount);
}
// ** POOL HELPERS
function _v2PoolFor(address tokenA, address tokenB, bool sushi)
internal
pure
returns (address v2pool, bool zeroForOne)
{
unchecked {
(address token0, address token1, bool zF1) = _sortTokens(tokenA, tokenB);
zeroForOne = zF1;
v2pool = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
!sushi ? V2_FACTORY : SUSHI_FACTORY,
keccak256(abi.encodePacked(token0, token1)),
!sushi ? V2_POOL_INIT_CODE_HASH : SUSHI_POOL_INIT_CODE_HASH
)
)
)
)
);
}
}
function _v3PoolFor(address tokenA, address tokenB, uint24 fee)
internal
pure
returns (address v3pool, bool zeroForOne)
{
(address token0, address token1, bool zF1) = _sortTokens(tokenA, tokenB);
zeroForOne = zF1;
v3pool = _computeV3pool(token0, token1, fee);
}
function _computeV3pool(address token0, address token1, uint24 fee)
internal
pure
returns (address v3pool)
{
bytes32 salt = _hash(token0, token1, fee);
assembly ("memory-safe") {
mstore8(0x00, 0xff)
mstore(0x35, V3_POOL_INIT_CODE_HASH)
mstore(0x01, shl(96, V3_FACTORY))
mstore(0x15, salt)
v3pool := keccak256(0x00, 0x55)
mstore(0x35, 0)
}
}
function _hash(address value0, address value1, uint24 value2)
internal
pure
returns (bytes32 result)
{
assembly ("memory-safe") {
let m := mload(0x40)
mstore(m, value0)
mstore(add(m, 0x20), value1)
mstore(add(m, 0x40), value2)
result := keccak256(m, 0x60)
}
}
function _sortTokens(address tokenA, address tokenB)
internal
pure
returns (address token0, address token1, bool zeroForOne)
{
(token0, token1) = (zeroForOne = tokenA < tokenB) ? (tokenA, tokenB) : (tokenB, tokenA);
}
// EXECUTE EXTENSIONS
address _owner;
modifier onlyOwner() {
require(msg.sender == _owner, Unauthorized());
_;
}
mapping(address target => bool) _isTrustedForCall;
function trust(address target, bool ok) public payable onlyOwner {
_isTrustedForCall[target] = ok;
}
function transferOwnership(address owner) public payable onlyOwner {
emit OwnershipTransferred(msg.sender, _owner = owner);
}
function execute(address target, uint256 value, bytes calldata data)
public
payable
returns (bytes memory result)
{
require(_isTrustedForCall[target], Unauthorized());
assembly ("memory-safe") {
tstore(0x00, 1) // lock callback (V3/V4)
result := mload(0x40)
calldatacopy(result, data.offset, data.length)
if iszero(call(gas(), target, value, result, data.length, codesize(), 0x00)) {
returndatacopy(result, 0x00, returndatasize())
revert(result, returndatasize())
}
mstore(result, returndatasize())
let o := add(result, 0x20)
returndatacopy(o, 0x00, returndatasize())
mstore(0x40, add(o, returndatasize()))
tstore(0x00, 0) // unlock callback
}
}
// SNWAP - GENERIC EXECUTOR ****
function snwap(
address tokenIn,
uint256 amountIn,
address recipient,
address tokenOut,
uint256 amountOutMin,
address executor,
bytes calldata executorData
) public payable returns (uint256 amountOut) {
uint256 initialBalance = tokenOut == address(0)
? recipient.balance
: balanceOfAccount(tokenOut, recipient);
if (tokenIn != address(0)) {
if (amountIn != 0) {
safeTransferFrom(tokenIn, msg.sender, executor, amountIn);
} else {
unchecked {
uint256 bal = balanceOf(tokenIn);
if (bal > 1) safeTransfer(tokenIn, executor, bal - 1);
}
}
}
safeExecutor.execute{value: msg.value}(executor, executorData);
uint256 finalBalance =
tokenOut == address(0) ? recipient.balance : balanceOfAccount(tokenOut, recipient);
amountOut = finalBalance - initialBalance;
if (amountOut < amountOutMin) revert SnwapSlippage(tokenOut, amountOut, amountOutMin);
if (recipient == address(this)) depositFor(tokenOut, 0, amountOut, address(this));
}
function snwapMulti(
address tokenIn,
uint256 amountIn,
address recipient,
address[] calldata tokensOut,
uint256[] calldata amountsOutMin,
address executor,
bytes calldata executorData
) public payable returns (uint256[] memory amountsOut) {
uint256 len = tokensOut.length;
uint256[] memory initBals = new uint256[](len);
for (uint256 i; i != len; ++i) {
initBals[i] = tokensOut[i] == address(0)
? recipient.balance
: balanceOfAccount(tokensOut[i], recipient);
}
if (tokenIn != address(0)) {
if (amountIn != 0) {
safeTransferFrom(tokenIn, msg.sender, executor, amountIn);
} else {
unchecked {
uint256 bal = balanceOf(tokenIn);
if (bal > 1) safeTransfer(tokenIn, executor, bal - 1);
}
}
}
safeExecutor.execute{value: msg.value}(executor, executorData);
amountsOut = new uint256[](len);
for (uint256 i; i != len; ++i) {
uint256 finalBal = tokensOut[i] == address(0)
? recipient.balance
: balanceOfAccount(tokensOut[i], recipient);
amountsOut[i] = finalBal - initBals[i];
if (amountsOut[i] < amountsOutMin[i]) {
revert SnwapSlippage(tokensOut[i], amountsOut[i], amountsOutMin[i]);
}
if (recipient == address(this)) {
depositFor(tokensOut[i], 0, amountsOut[i], address(this));
}
}
}
// LIDO STAKING ****
// **** EXACT ETH IN - MAX TOKEN OUT
// note: If user doesn't care about `to` then just send ETH to STETH or WSTETH
function exactETHToSTETH(address to) public payable returns (uint256 shares) {
assembly ("memory-safe") {
// submit(address referral) -> returns shares
mstore(0x00, 0xa1903eab000000000000000000000000)
if iszero(call(gas(), STETH, callvalue(), 0x10, 0x24, 0x00, 0x20)) {
revert(0x00, 0x00)
}
shares := mload(0x00)
// transferShares(address to, uint256 shares)
mstore(0x00, 0x8fcb4e5b000000000000000000000000)
mstore(0x14, to)
mstore(0x34, shares)
if iszero(call(gas(), STETH, 0, 0x10, 0x44, codesize(), 0x00)) {
revert(0x00, 0x00)
}
mstore(0x34, 0)
}
}
function exactETHToWSTETH(address to) public payable returns (uint256 wstOut) {
assembly ("memory-safe") {
// Send ETH to WSTETH (triggers receive() which auto-wraps)
if iszero(call(gas(), WSTETH, callvalue(), codesize(), 0x00, codesize(), 0x00)) {
revert(0x00, 0x00)
}
// balanceOf(address) to get wstETH received
mstore(0x14, address())
mstore(0x00, 0x70a08231000000000000000000000000)
if iszero(staticcall(gas(), WSTETH, 0x10, 0x24, 0x00, 0x20)) {
revert(0x00, 0x00)
}
wstOut := mload(0x00)
// transfer(address to, uint256 amount)
mstore(0x00, 0xa9059cbb000000000000000000000000)
mstore(0x14, to)
mstore(0x34, wstOut)
if iszero(call(gas(), WSTETH, 0, 0x10, 0x44, codesize(), 0x00)) {
revert(0x00, 0x00)
}
mstore(0x34, 0)
}
}
// **** EXACT TOKEN OUT - REFUND EXCESS ETH IN
function ethToExactSTETH(address to, uint256 exactOut) public payable {
assembly ("memory-safe") {
// getSharesByPooledEth(1e18) to get share rate
mstore(0x00, 0xd5002f2e000000000000000000000000)
if iszero(staticcall(gas(), STETH, 0x10, 0x04, 0x00, 0x20)) {
revert(0x00, 0x00)
}
let S := mload(0x00)
// getTotalPooledEther()
mstore(0x00, 0x37cfdaca000000000000000000000000)
if iszero(staticcall(gas(), STETH, 0x10, 0x04, 0x00, 0x20)) {
revert(0x00, 0x00)
}
let T := mload(0x00)
let z := mul(exactOut, S)
let sharesNeeded := add(iszero(iszero(mod(z, T))), div(z, T))
z := mul(sharesNeeded, T)
let ethIn := add(iszero(iszero(mod(z, S))), div(z, S))
if gt(ethIn, callvalue()) { revert(0x00, 0x00) }
// submit() to stake ETH
if iszero(call(gas(), STETH, ethIn, codesize(), 0x00, codesize(), 0x00)) {
revert(0x00, 0x00)
}
// transferShares(address to, uint256 shares)
mstore(0x00, 0x8fcb4e5b000000000000000000000000)
mstore(0x14, to)
mstore(0x34, sharesNeeded)
if iszero(call(gas(), STETH, 0, 0x10, 0x44, codesize(), 0x00)) {
revert(0x00, 0x00)
}
mstore(0x34, 0)
// Refund excess ETH
if gt(callvalue(), ethIn) {
if iszero(
call(
gas(),
caller(),
sub(callvalue(), ethIn),
codesize(),
0x00,
codesize(),
0x00
)
) {
// ETHTransferFailed selector: 0xb12d13eb
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
}
}
}
function ethToExactWSTETH(address to, uint256 exactOut) public payable {
assembly ("memory-safe") {
// getSharesByPooledEth(1e18) to get share rate
mstore(0x00, 0xd5002f2e000000000000000000000000)
if iszero(staticcall(gas(), STETH, 0x10, 0x04, 0x00, 0x20)) {
revert(0x00, 0x00)
}
let S := mload(0x00)
// getTotalPooledEther()
mstore(0x00, 0x37cfdaca000000000000000000000000)
if iszero(staticcall(gas(), STETH, 0x10, 0x04, 0x00, 0x20)) {
revert(0x00, 0x00)
}
let ethIn := mul(exactOut, mload(0x00))
ethIn := add(iszero(iszero(mod(ethIn, S))), div(ethIn, S))
if gt(ethIn, callvalue()) { revert(0x00, 0x00) }
// Send ETH to WSTETH (triggers receive() which auto-wraps)
if iszero(call(gas(), WSTETH, ethIn, codesize(), 0x00, codesize(), 0x00)) {
revert(0x00, 0x00)
}
// transfer(address to, uint256 amount)
mstore(0x00, 0xa9059cbb000000000000000000000000)
mstore(0x14, to)
mstore(0x34, exactOut)
if iszero(call(gas(), WSTETH, 0, 0x10, 0x44, codesize(), 0x00)) {
revert(0x00, 0x00)
}
mstore(0x34, 0)
// Refund excess ETH
if gt(callvalue(), ethIn) {
if iszero(
call(
gas(),
caller(),
sub(callvalue(), ethIn),
codesize(),
0x00,
codesize(),
0x00
)
) {
// ETHTransferFailed selector: 0xb12d13eb
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
}
}
}
// NameNFT - REVEAL NAME ****
function onERC721Received(address, address, uint256, bytes calldata)
public
pure
returns (bytes4)
{
return this.onERC721Received.selector;
}
/// @notice Reveal and register a .wei name after commitment.
/// @dev User must first commit on NameNFT using `makeCommitment(label, routerAddress, derivedSecret)`.
/// The derived secret is `keccak256(abi.encode(innerSecret, to))`, binding the commitment
/// to the intended recipient. This prevents mempool front-running of the reveal tx.
/// Chain with swap via multicall for atomic swap-to-reveal. Excess ETH stays in
/// router for sweep.
function revealName(string calldata label, bytes32 innerSecret, address to)
public
payable
returns (uint256 tokenId)
{
bytes32 secret = keccak256(abi.encode(innerSecret, to));
uint256 val = address(this).balance;
_useTransientBalance(address(this), address(0), 0, val);
tokenId = INameNFT(NAME_NFT).reveal{value: val}(label, secret);
INameNFT(NAME_NFT).transferFrom(address(this), to, tokenId);
}
}
// NameNFT helpers:
address constant NAME_NFT = 0x0000000000696760E15f265e828DB644A0c242EB;
interface INameNFT {
function reveal(string calldata label, bytes32 secret)
external
payable
returns (uint256 tokenId);
function transferFrom(address from, address to, uint256 tokenId) external;
}
// Lido helpers:
address constant STETH = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
address constant WSTETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0;
// Uniswap helpers:
address constant V2_FACTORY = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
bytes32 constant V2_POOL_INIT_CODE_HASH =
0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f;
// ** SushiSwap:
address constant SUSHI_FACTORY = 0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac;
bytes32 constant SUSHI_POOL_INIT_CODE_HASH =
0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303;
interface IV2Pool {
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32);
}
address constant V3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984;
bytes32 constant V3_POOL_INIT_CODE_HASH =
0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;
uint160 constant MIN_SQRT_RATIO_PLUS_ONE = 4295128740;
uint160 constant MAX_SQRT_RATIO_MINUS_ONE = 1461446703485210103287273052203988822378723970341;
interface IV3Pool {
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
}
address constant V4_POOL_MANAGER = 0x000000000004444c5dc75cB358380D2e3dE08A90;
struct V4PoolKey {
address currency0;
address currency1;
uint24 fee;
int24 tickSpacing;
address hooks;
}
struct V4SwapParams {
bool zeroForOne;
int256 amountSpecified;
uint160 sqrtPriceLimitX96;
}
interface IV4PoolManager {
function unlock(bytes calldata data) external returns (bytes memory);
function swap(V4PoolKey memory key, V4SwapParams memory params, bytes calldata hookData)
external
returns (int256 swapDelta);
function sync(address currency) external;
function settle() external payable returns (uint256 paid);
function take(address currency, address to, uint256 amount) external;
}
using BalanceDeltaLibrary for int256;
library BalanceDeltaLibrary {
function amount0(int256 balanceDelta) internal pure returns (int128 _amount0) {
assembly ("memory-safe") {
_amount0 := sar(128, balanceDelta)
}
}
function amount1(int256 balanceDelta) internal pure returns (int128 _amount1) {
assembly ("memory-safe") {
_amount1 := signextend(15, balanceDelta)
}
}
}
// zAMM helpers:
address constant ZAMM = 0x000000000000040470635EB91b7CE4D132D616eD;
address constant ZAMM_0 = 0x00000000000008882D72EfA6cCE4B6a40b24C860;
struct PoolKey {
uint256 id0;
uint256 id1;
address token0;
address token1;
uint256 feeOrHook;
}
interface IZAMM {
function addLiquidity(
PoolKey calldata poolKey,
uint256 amount0Desired,
uint256 amount1Desired,
uint256 amount0Min,
uint256 amount1Min,
address to,
uint256 deadline
) external payable returns (uint256 amount0, uint256 amount1, uint256 liquidity);
}
// Curve helpers:
address constant CURVE_ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
interface IStableNgPool {
function get_dx(int128 i, int128 j, uint256 out_amount) external view returns (uint256);
function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external;
function calc_token_amount(uint256[8] calldata _amounts, bool _is_deposit)
external
view
returns (uint256);
function add_liquidity(uint256[8] calldata _amounts, uint256 _min_mint_amount)
external
returns (uint256);
function calc_withdraw_one_coin(uint256 token_amount, int128 i) external view returns (uint256);
function remove_liquidity_one_coin(uint256 token_amount, int128 i, uint256 min_amount) external;
}
interface IStableNgMetaPool {
function get_dx_underlying(int128 i, int128 j, uint256 amount) external view returns (uint256);
function exchange_underlying(int128 i, int128 j, uint256 dx, uint256 min_dy) external;
}
interface ICryptoNgPool {
function get_dx(uint256 i, uint256 j, uint256 out_amount) external view returns (uint256);
function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) external;
function calc_withdraw_one_coin(uint256 token_amount, uint256 i) external view returns (uint256);
function remove_liquidity_one_coin(uint256 token_amount, uint256 i, uint256 min_amount) external;
}
interface ITwoCryptoNgPool {
function calc_token_amount(uint256[2] calldata amounts, bool is_deposit)
external
view
returns (uint256);
function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount)
external
returns (uint256);
}
interface ITriCryptoNgPool {
function calc_token_amount(uint256[3] calldata amounts, bool is_deposit)
external
view
returns (uint256);
function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount)
external
returns (uint256);
}
// Solady safe transfer helpers:
error TransferFailed();
function safeTransfer(address token, address to, uint256 amount) {
assembly ("memory-safe") {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0xa9059cbb000000000000000000000000)
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x90b8ec18)
revert(0x1c, 0x04)
}
}
mstore(0x34, 0)
}
}
error TransferFromFailed();
function safeTransferFrom(address token, address from, address to, uint256 amount) {
assembly ("memory-safe") {
let m := mload(0x40)
mstore(0x60, amount)
mstore(0x40, to)
mstore(0x2c, shl(96, from))
mstore(0x0c, 0x23b872dd000000000000000000000000)
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x7939f424)
revert(0x1c, 0x04)
}
}
mstore(0x60, 0)
mstore(0x40, m)
}
}
error ApproveFailed();
function safeApprove(address token, address to, uint256 amount) {
assembly ("memory-safe") {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0x095ea7b3000000000000000000000000)
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x3e3f8f73)
revert(0x1c, 0x04)
}
}
mstore(0x34, 0)
}
}
function balanceOf(address token) view returns (uint256 amount) {
assembly ("memory-safe") {
mstore(0x14, address())
mstore(0x00, 0x70a08231000000000000000000000000)
amount := mul(
mload(0x20),
and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20))
)
}
}
function allowance(address token, address owner, address spender) view returns (uint256 amount) {
assembly ("memory-safe") {
let m := mload(0x40)
mstore(0x40, spender)
mstore(0x2c, shl(96, owner))
mstore(0x0c, 0xdd62ed3e000000000000000000000000)
amount := mul(
mload(0x20),
and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x1c, 0x44, 0x20, 0x20))
)
mstore(0x40, m)
}
}
function balanceOfAccount(address token, address account) view returns (uint256 amount) {
assembly ("memory-safe") {
mstore(0x14, account)
mstore(0x00, 0x70a08231000000000000000000000000)
amount := mul(
mload(0x20),
and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20))
)
}
}
// ** ERC6909
interface IERC6909 {
function setOperator(address spender, bool approved) external returns (bool);
function balanceOf(address owner, uint256 id) external view returns (uint256 amount);
function transfer(address receiver, uint256 id, uint256 amount) external returns (bool);
function transferFrom(address sender, address receiver, uint256 id, uint256 amount)
external
returns (bool);
}
// Low-level WETH helpers - we know WETH so we can make assumptions:
address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
function wrapETH(address pool, uint256 amount) {
assembly ("memory-safe") {
pop(call(gas(), WETH, amount, codesize(), 0x00, codesize(), 0x00))
mstore(0x14, pool)
mstore(0x34, amount)
mstore(0x00, 0xa9059cbb000000000000000000000000)
pop(call(gas(), WETH, 0, 0x10, 0x44, codesize(), 0x00))
mstore(0x34, 0)
}
}
function unwrapETH(uint256 amount) {
assembly ("memory-safe") {
mstore(0x00, 0x2e1a7d4d)
mstore(0x20, amount)
pop(call(gas(), WETH, 0, 0x1c, 0x24, codesize(), 0x00))
}
}
// ** TRANSIENT DEPOSIT
function depositFor(address token, uint256 id, uint256 amount, address _for) {
assembly ("memory-safe") {
let m := mload(0x40)
mstore(0x00, _for)
mstore(0x20, token)
mstore(0x40, id)
let slot := keccak256(0x00, 0x60)
tstore(slot, add(tload(slot), amount))
mstore(0x40, m)
}
}
// ** PERMIT HELPERS
address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
interface IERC2612 {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
interface IDAIPermit {
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
interface IPermit2 {
struct TokenPermissions {
address token;
uint256 amount;
}
struct PermitTransferFrom {
TokenPermissions permitted;
uint256 nonce;
uint256 deadline;
}
struct PermitBatchTransferFrom {
TokenPermissions[] permitted;
uint256 nonce;
uint256 deadline;
}
struct SignatureTransferDetails {
address to;
uint256 requestedAmount;
}
function permitTransferFrom(
PermitTransferFrom calldata permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
function permitBatchTransferFrom(
PermitBatchTransferFrom calldata permit,
SignatureTransferDetails[] calldata transferDetails,
address owner,
bytes calldata signature
) external;
}
// ** SNWAP HELPERS
// modified from 0xAC4c6e212A361c968F1725b4d055b47E63F80b75 - sushi yum
/// @dev SafeExecutor - has no token approvals, safe for arbitrary external calls
contract SafeExecutor {
function execute(address target, bytes calldata data) public payable {
assembly ("memory-safe") {
let m := mload(0x40)
calldatacopy(m, data.offset, data.length)
if iszero(call(gas(), target, callvalue(), m, data.length, codesize(), 0x00)) {
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
}
}{
"remappings": [
"@solady/=lib/solady/",
"@soledge/=lib/soledge/",
"@forge/=lib/forge-std/src/",
"solady/=lib/solady/src/",
"soledge/=lib/soledge/src/",
"forge-std/=lib/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 9999999
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"BadSwap","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"Expired","type":"error"},{"inputs":[],"name":"InvalidId","type":"error"},{"inputs":[],"name":"InvalidMsgVal","type":"error"},{"inputs":[],"name":"Slippage","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"minimum","type":"uint256"}],"name":"SnwapSlippage","type":"error"},{"inputs":[],"name":"SwapExactInFail","type":"error"},{"inputs":[],"name":"SwapExactOutFail","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"components":[{"internalType":"uint256","name":"id0","type":"uint256"},{"internalType":"uint256","name":"id1","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"feeOrHook","type":"uint256"}],"internalType":"struct PoolKey","name":"poolKey","type":"tuple"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"is6909","type":"bool"},{"internalType":"address","name":"to","type":"address"}],"name":"ensureAllowance","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"exactOut","type":"uint256"}],"name":"ethToExactSTETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"exactOut","type":"uint256"}],"name":"ethToExactWSTETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"exactETHToSTETH","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"exactETHToWSTETH","outputs":[{"internalType":"uint256","name":"wstOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IPermit2.TokenPermissions[]","name":"permitted","type":"tuple[]"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"permit2BatchTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"permit2TransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitDAI","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"label","type":"string"},{"internalType":"bytes32","name":"innerSecret","type":"bytes32"},{"internalType":"address","name":"to","type":"address"}],"name":"revealName","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"safeExecutor","outputs":[{"internalType":"contract SafeExecutor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"bytes","name":"executorData","type":"bytes"}],"name":"snwap","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address[]","name":"tokensOut","type":"address[]"},{"internalType":"uint256[]","name":"amountsOutMin","type":"uint256[]"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"bytes","name":"executorData","type":"bytes"}],"name":"snwapMulti","outputs":[{"internalType":"uint256[]","name":"amountsOut","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactOut","type":"bool"},{"internalType":"address[11]","name":"route","type":"address[11]"},{"internalType":"uint256[4][5]","name":"swapParams","type":"uint256[4][5]"},{"internalType":"address[5]","name":"basePools","type":"address[5]"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapCurve","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactOut","type":"bool"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapV2","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactOut","type":"bool"},{"internalType":"uint24","name":"swapFee","type":"uint24"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapV3","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactOut","type":"bool"},{"internalType":"uint24","name":"swapFee","type":"uint24"},{"internalType":"int24","name":"tickSpace","type":"int24"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapV4","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"exactOut","type":"bool"},{"internalType":"uint256","name":"feeOrHook","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"idIn","type":"uint256"},{"internalType":"uint256","name":"idOut","type":"uint256"},{"internalType":"uint256","name":"swapAmount","type":"uint256"},{"internalType":"uint256","name":"amountLimit","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapVZ","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"ok","type":"bool"}],"name":"trust","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"callbackData","type":"bytes"}],"name":"unlockCallback","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unwrap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wrap","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a060408190526101158082016001600160401b0381118382101761012e5782916160ba833903905ff0801561012357608052737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06014525f196034526f095ea7b30000000000000000000000005f5260205f604460108273ae7ab96520de3a18e5e111b5eaab095312d7fe845af18060015f511416156100f1575b5f603481905280546001600160a01b031916329081178255604051917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3615f77908161014382396080518181816104de01528181612f6301526133a20152f35b3d73ae7ab96520de3a18e5e111b5eaab095312d7fe843b15171015610116575f61008e565b633e3f8f735f526004601cfd5b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffdfe6080604052600436101561014d575b36156100b7575f5c61014957609a3560601c6024356004358015801590610140575b156101185761004a60d63560e81c60ae3560601c85615ec8565b939073ffffffffffffffffffffffffffffffffffffffff811633036100f05784156100e95782905b61007d828430615c9c565b156100c05761008b92615da8565b6085355f1a61009657005b6100b792156100b957505b5f036100ac81615d03565b60c23560601c615b7c565b005b90506100a1565b6084355f1a156100d9576100d49250615e2f565b61008b565b6100d49260863560601c90615bc7565b8390610072565b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f7c7f7bb9000000000000000000000000000000000000000000000000000000005f5260045ffd5b50811515610030565b5f80fd5b5f5f3560e01c806306262f1b146153ac57806309d31579146151d25780630efe6a8b14614fdd57806312db224a14613caf578063150b7a0214613c2157806321c0dad21461398b578063230390f4146138ac5780632cb9f974146136c65780633f896275146132a657806341abb1ef146131d157806347c1ba3a146131195780635f3bd1c814612e8f5780636e0a4f98146128235780637984d8b1146124195780637ac2ff7b1461233657806391dd734614611cfe5780639d5b5af8146113dc578063ac9650d8146111c5578063afeae12b14610cb0578063b61d27f614610b92578063bd6b76d714610a60578063c391b38114610914578063c42957a81461073e578063cb019b841461054f578063de0e9a3e14610502578063e8382b0114610493578063ea598cb01461045a578063f2fde38b146103775763f978602c14610297575061000e565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576102c9615458565b8138818034737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af11561037257306014526f70a08231000000000000000000000000825260208260246010737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05afa15610372578151906fa9059cbb00000000000000000000000083526014528060345281386044601083737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af11561037257602091603452604051908152f35b505b80fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576103aa615458565b81549073ffffffffffffffffffffffffffffffffffffffff82163303610432579073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116178255337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6004837f82b42900000000000000000000000000000000000000000000000000000000008152fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610490600435615a9b565b80f35b503461037457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457600435806105465750610490610541615c2e565b615d03565b61049090615d03565b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610582615458565b60243590604435610591615507565b9173ffffffffffffffffffffffffffffffffffffffff8116806105c85750610490935050806105c257504790615b7c565b90615b7c565b9092919085856105ee5750610490945050806105e857506105e882615c6f565b91615da8565b92935091908061072e57506040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260248101859052602081604481865afa9081156106e75782916106f2575b509360209392916106ac95935b604051968795869485937f095bcdb60000000000000000000000000000000000000000000000000000000085526004850160409194939273ffffffffffffffffffffffffffffffffffffffff606083019616825260208201520152565b03925af180156106e7576106bf575b5080f35b6106bb9060203d6020116106e0575b6106d8818361568f565b81019061570e565b503d6106ce565b6040513d84823e3d90fd5b93929150506020833d602011610726575b816107106020938361568f565b8101031261014957915190919084906020610642565b3d9150610703565b9360209392916106ac959361064f565b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360161016081126103725760a0136103745760a4356101243573ffffffffffffffffffffffffffffffffffffffff81168091036109105760609073ffffffffffffffffffffffffffffffffffffffff6107b7615765565b1661090657610164835b60405194859384927fc42957a80000000000000000000000000000000000000000000000000000000084526004356004850152602435602485015273ffffffffffffffffffffffffffffffffffffffff6108196154e4565b16604485015273ffffffffffffffffffffffffffffffffffffffff61083c615507565b166064850152608435608485015260a484015260c43560c484015260e43560e484015261010435610104840152610124830152610144356101448301526d040470635eb91b7ce4d132d616ed5af180156106e75782918380926108c1575b50506108bd90604051938493846040919493926060820195825260208201520152565b0390f35b92509250506060823d6060116108fe575b816108df6060938361568f565b810103126103745750805160208201516040909201516108bd5f61089a565b3d91506108d2565b61016484936107c1565b8280fd5b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745780610948615458565b6024356fd5002f2e00000000000000000000000083526020836004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5c5782516f37cfdaca00000000000000000000000084526020846004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5a578351820290808204910615150191348311610a5a578338818086737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af115610a5a576fa9059cbb000000000000000000000000845260145260345281386044601083737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af115610a575781603452803411610a395750f35b818038923403335af115610a4a5780f35b63b12d13eb90526004601cfd5b50fd5b505b5050fd5b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745780610a94615458565b6fd5002f2e00000000000000000000000082526020826004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a575781516f37cfdaca00000000000000000000000083526020836004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5c57825190806024350282808204910615150191820290808204910615150191348311610a5a57833881808673ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610a5a576f8fcb4e5b00000000000000000000000084526014526034528138604460108373ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610a575781603452803411610a395750f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610bc5615458565b60443567ffffffffffffffff811161091057610be590369060040161555a565b73ffffffffffffffffffffffffffffffffffffffff839293168452600160205260ff60408520541615610c88579083916001835d80604051948537833892602435905af115610c7f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0903d81523d83602083013e610c7a3d820191602083019485604052805d6020855260408301906155cb565b030190f35b903d90823e3d90fd5b6004847f82b42900000000000000000000000000000000000000000000000000000000008152fd5b506101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610ce4615458565b610cec61554b565b90610cf5615588565b90610cfe615507565b91610d0761549e565b60e435421161119d5794849560a435819373ffffffffffffffffffffffffffffffffffffffff87931615928373ffffffffffffffffffffffffffffffffffffffff891615611181575b611165575b808786610d64858a8096615ec8565b9d8e9591948615611148578d8a6401000276a49a5b84158061113e575b6110c8575b81156110c15730945b156110565786039a7fffffff000000000000000000000000000000000000000000000000000000000060409b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9a818c9a81610ea69a8d995b60408b90519c161560f81b60208d015260f81b60218c01523360601b60228c015260601b1660368a015260601b16604a88015260601b16605e86015260e81b16607284015260558352610e5160758461568f565b8a519b8c9a8b998a977f128acb0800000000000000000000000000000000000000000000000000000000895216600488015215156024870152604486015216606484015260a0608484015260a48301906155cb565b0393165af196871561104b5783918498611010575b5060c435610fa2575b5060409715610f865773ffffffffffffffffffffffffffffffffffffffff905b838112610f7e57965b838113610f78578303955b1615610f33575b15610f14575b50505082519182526020820152f35b60609186519382526020528086522082815c01905d83525f8080610f05565b4780151580610f58575b610f48575b50610eff565b610f529033615b7c565b5f610f42565b503073ffffffffffffffffffffffffffffffffffffffff86161415610f3d565b95610ef8565b830396610eed565b9573ffffffffffffffffffffffffffffffffffffffff90610ee4565b15610fef578715610fe957805b60c43510610fc1576040975b97610ec4565b6004837f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b86610faf565b871561100a57865b60c43590840310610fc157604097610fbb565b80610ff7565b915096506040813d604011611043575b8161102d6040938361568f565b810103126109105760208151910151965f610ebb565b3d9150611020565b6040513d85823e3d90fd5b9a7fffffff000000000000000000000000000000000000000000000000000000000060409b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9a818c9a81610ea69a8d99610dfd565b8794610d8f565b505050949550505090505073ffffffffffffffffffffffffffffffffffffffff8916155f1461113057345b80156111085786888c8e95948d8a8e96610d86565b6004877f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b61113981615c6f565b6110f3565b5060a43515610d81565b8d8a73fffd8963efd1fc6a506488495d951d5263988d259a610d79565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29550610d55565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29150610d50565b6004867f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff81116103725761121090369060040161559a565b9061121a82615922565b91611228604051938461568f565b8083527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061125582615922565b01845b8181106113cb5750509083907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301915b8381036113155784866040519182916020830160208452825180915260408401602060408360051b870101940192905b8282106112ca57505050500390f35b91936020611305827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288516155cb565b96019201920185949391926112bb565b8381101561139e57858160051b8301358481121561037257830180359067ffffffffffffffff82116109105760200190803603821361091057829181604051928392833781018381520390305af461136b615a6c565b901561139657906113919161138082886159c6565b5261138b81876159c6565b50615989565b61128b565b602081519101fd5b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b806060602080938801015201611258565b506101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457611410615458565b61141861554b565b611420615507565b61142861549e565b9260e4359361012435421161119d57858573ffffffffffffffffffffffffffffffffffffffff806101243561145d8689615e8a565b9491909316928982168403611cf25760a4359360c4355b6040519561148187615673565b8652602086015260408501521660608301526044356080830152881580948195611ce9575b50611bd3575b84939291908315611bca578a5b8590604051903088528b60205260a4356040526060882090815c81811015611bb7575b50505060405215611aa7575b610124357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14611a91578a6d040470635eb91b7ce4d132d616ed945b73ffffffffffffffffffffffffffffffffffffffff8616906d08882d72efa6cce4b6a40b24c8608214611a6f575b156119045761164b9261161f916d040470635eb91b7ce4d132d616ed036118dc578a7f3c5eec5000000000000000000000000000000000000000000000000000000000965b60405196879560208701998a5261010435916024880192936101209473ffffffffffffffffffffffffffffffffffffffff939897969298608061014087019a80518852602081015160208901528660408201511660408901528660608201511660608901520151608087015260a086015260c0850152151560e0840152166101008201520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261568f565b73ffffffffffffffffffffffffffffffffffffffff88166118d55789905b51925af1611675615a6c565b90156118ad576020815191818082019384920101031261014957515b84156118a75794935b80611887575b1561186e57505073ffffffffffffffffffffffffffffffffffffffff81166116ec57506040925047806116dc575b505b82519182526020820152f35b6116e69033615b7c565b5f6116ce565b60a43561171f576040935061170081615c6f565b8061170d575b50506116d0565b611718913390615da8565b5f80611706565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260a435602482015260208160448173ffffffffffffffffffffffffffffffffffffffff86165afa908115611863578591611831575b5080611791575b5050604092506116d0565b6040517f095bcdb600000000000000000000000000000000000000000000000000000000815233600482015260a435602482015260448101919091529060209082906064908290889073ffffffffffffffffffffffffffffffffffffffff165af180156118265760409450611807575b80611786565b61181f9060203d6020116106e0576106d8818361568f565b505f611801565b6040513d86823e3d90fd5b90506020813d60201161185b575b8161184c6020938361568f565b8101031261014957515f61177f565b3d915061183f565b6040513d87823e3d90fd5b604095506118829250839060c43590615ae3565b6116d0565b503073ffffffffffffffffffffffffffffffffffffffff831614156116a0565b9361169a565b6004877f28982d61000000000000000000000000000000000000000000000000000000008152fd5b8390611669565b8a7f7466fde70000000000000000000000000000000000000000000000000000000096611597565b6119cb9261161f916d040470635eb91b7ce4d132d616ed03611a47578a7f38c3f8db000000000000000000000000000000000000000000000000000000009660405196879560208701998a5261010435916024880192936101209473ffffffffffffffffffffffffffffffffffffffff939897969298608061014087019a80518852602081015160208901528660408201511660408901528660608201511660608901520151608087015260a086015260c0850152151560e0840152166101008201520152565b73ffffffffffffffffffffffffffffffffffffffff8816611a405761010435905b51925af16119f8615a6c565b9015611a1857602081519181808201938492010103126101495751611691565b6004877fb4fff567000000000000000000000000000000000000000000000000000000008152fd5b83906119ec565b8a7fd4ff3f0e0000000000000000000000000000000000000000000000000000000096611597565b6080850180516bffffffffffffffffffffffff16905242610708019350611552565b8a6d08882d72efa6cce4b6a40b24c86094611524565b73ffffffffffffffffffffffffffffffffffffffff8916611ac8575b6114e8565b60a435611aee578315611ae257611ac38b5b30338c615bc7565b611ac361010435611ada565b73ffffffffffffffffffffffffffffffffffffffff94508315611ba8576020611b658a8d5b6040517ffe99049a00000000000000000000000000000000000000000000000000000000815233600482015230602482015260a4356044820152606481019190915297889283918b9183906084820190565b0393165af1948515611b9d578695611b7e575b506114e8565b611b969060203d6020116106e0576106d8818361568f565b505f611b78565b6040513d88823e3d90fd5b6020611b658a61010435611b13565b909192935003905d6001905f80806114dc565b610104356114b9565b98509192509073ffffffffffffffffffffffffffffffffffffffff8616611c2f5734975b8815611c075790899392916114ac565b60048a7f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b60a435611c4557611c3f86615c6f565b97611bf7565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260a435602482015260208160448173ffffffffffffffffffffffffffffffffffffffff8b165afa908115611cde578a91611cac575b5097611bf7565b90506020813d602011611cd6575b81611cc76020938361568f565b8101031261014957515f611ca5565b3d9150611cba565b6040513d8c823e3d90fd5b9050155f6114a6565b60c4359360a435611474565b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff811161037257611d4990369060040161555a565b6e04444c5dc75cb358380d2e3de08a90330361043257825c6109105781610120918101031261037257611d7b8161552a565b90611d886020820161552a565b90604081013590811593841583036121895760608201359162ffffff8316809303612332576080810135908160020b80920361232e57611dca60a0820161552a565b94611dd760c0830161552a565b9773ffffffffffffffffffffffffffffffffffffffff80808061010060e088013597013598169a169816991693848a108a1597815f14612326578c8c935b831561231f5788905b73ffffffffffffffffffffffffffffffffffffffff60405196611e4088615673565b16865273ffffffffffffffffffffffffffffffffffffffff602087019216825260408601938452606086019081526080860190838252885f146123165789935b5085156122fb576401000276a4945b60405193611e9c85615657565b87855260208501958652604085019673ffffffffffffffffffffffffffffffffffffffff168752604051987ff3cd914c000000000000000000000000000000000000000000000000000000008a525173ffffffffffffffffffffffffffffffffffffffff1660048a01525173ffffffffffffffffffffffffffffffffffffffff1660248901525162ffffff1660448801525160020b60648701525173ffffffffffffffffffffffffffffffffffffffff16608486015251151560a48501525160c48401525173ffffffffffffffffffffffffffffffffffffffff1660e4830152610104820161012090528b6101248301528b8233815a9361014492602095f19081156122f0578c916122a8575b6fffffffffffffffffffffffffffffffff92501561228c57821561228157165b905b333b1561227d578a6040517fa58411940000000000000000000000000000000000000000000000000000000081528b6004820152818160248183335af180156106e757612268575b505080156122615783995b6120298b8230615c9c565b1561223f578a881561222d575b50505b156122265780945b801515908161220e575b506121e65785156121d957600492602092156121d257505b604051928380927f11da60b4000000000000000000000000000000000000000000000000000000008252335af180156121c757612198575b5086333b15610374576040517f0b0d9c0900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201529185166024830152604482018390528160648183335af1801561218d57612174575b506108bd955060405194602086015260408501526040845261212c60608561568f565b612147575b50506040519182916020835260208301906155cb565b47908115159081612169575b50156121315761216291615b7c565b5f80612131565b90503014155f612153565b61217f87809261568f565b6121895785612109565b8580fd5b6040513d89823e3d90fd5b6020813d6020116121bf575b816121b16020938361568f565b81010312610149575161209b565b3d91506121a4565b6040513d8a823e3d90fd5b9050612063565b5050506004602088612063565b60048a7f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b9050821561221f5781115b5f61204b565b8510612219565b8294612041565b612238913390615da8565b5f8a612036565b8a881561224e575b5050612039565b61225a918b3391615bc7565b5f8a612247565b819961201e565b816122729161568f565b61227d578a5f612013565b8a80fd5b60801d8b0316611fc9565b821561229d5760801d165b90611fcb565b600f0b8b0316612297565b90506020823d6020116122e8575b816122c36020938361568f565b810103126122e4576fffffffffffffffffffffffffffffffff915190611fa9565b8b80fd5b3d91506122b6565b6040513d8e823e3d90fd5b73fffd8963efd1fc6a506488495d951d5263988d2594611e8f565b89840393611e80565b8d90611e1e565b8c8793611e15565b8780fd5b8680fd5b5060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374578061236a615458565b6064359060ff8216809203610a5c5773ffffffffffffffffffffffffffffffffffffffff1690813b15610a5c57829160e4839260405194859384927fd505accf00000000000000000000000000000000000000000000000000000000845233600485015230602485015260243560448501526044356064850152608484015260843560a484015260a43560c48401525af180156106e7576124085750f35b816124129161568f565b6103745780f35b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff811161037257366023820112156103725780600401359067ffffffffffffffff8211610910576024808201918360061b010136811161281f5760643567ffffffffffffffff811161281b576124a990369060040161555a565b6124b285615922565b916124c0604051938461568f565b8583527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06124ed87615922565b01875b8181106127f8575050865b8681036127b657506040519361251085615657565b61251987615922565b90612527604051928361568f565b8782528690602083015b81831061277e575050508452602084019360243585526040810160443581526e22d473030f116ddee9f6b43ac78ba33b1561277a5790889594939291604051957f4da3e5d90000000000000000000000000000000000000000000000000000000087526080600488015260e4870192519260606084890152835180915260206101048901940190895b81811061272a575050505160a48701525160c48601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc85820301602486015260208085519283815201940190865b8181106126e0575050506126518593859384933360448601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8584030160648601526156d0565b0381836e22d473030f116ddee9f6b43ac78ba35af180156106e7576126cb575b5050825b828103612680578380f35b806126976126926126c6938686615a5c565b615788565b60206126a4838787615a5c565b013560405191308852602052866040526060872090815c01905d604052615989565b612675565b816126d59161568f565b61091057825f612671565b9195965091929360206040826127196001948a516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b019601910191899695949392612609565b9195969798995091929360206040826127666001948a516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b0196019101918c99989796959493926125ba565b8880fd5b60408336031261227d57602060409182516127988161560e565b6127a18661552a565b81528286013583820152815201920191612531565b8060206127c76127f3938a8a615a5c565b0135604051906127d68261560e565b30825260208201526127e882876159c6565b5261138b81866159c6565b6124fb565b6020906040516128078161560e565b8a81528a83820152828288010152016124f0565b8480fd5b8380fd5b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457612856615458565b61285e61554b565b6128666154e4565b9161286f615507565b60843560a4359460c43590814211612e675773ffffffffffffffffffffffffffffffffffffffff84811615939291908116158481612e4b575b612e2f575b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a9314612e26575b73ffffffffffffffffffffffffffffffffffffffff6128f58784615e8a565b9590919015908115612e0b57735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f925b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519181602084019460601b16845260601b1660348201526028815261296160488261568f565b5190209015612de5577f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f5b604051917fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060208401947fff00000000000000000000000000000000000000000000000000000000000000865260601b16602184015260358301526055820152605581526129fb60758261568f565b51902016936040517f0902f1ac000000000000000000000000000000000000000000000000000000008152606081600481895afa9081156122f0578c908d92612d89575b508515612d72576dffffffffffffffffffffffffffff80915b169116995f14612cd057907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612a9f926103e86103e584809e030293849202020101615a25565b988015908115612cc5575b50156121e6578389915b612abf838584615c9c565b15612c51575b505050505f14612ba9578115612ba25786305b823b156103725760a473ffffffffffffffffffffffffffffffffffffffff918360405195869485937f022c0d9f0000000000000000000000000000000000000000000000000000000085528360048601528c6024860152166044840152608060648401528160848401525af1801561218d57612b8d575b509483916040965b15612b705750506116d091612b6b82615d03565b615b7c565b6060925086519382526020528086522082815c01905d83526116d0565b612b9887809261568f565b612189575f612b4f565b8684612ad8565b8115612c4a5786305b823b156103725760a473ffffffffffffffffffffffffffffffffffffffff918360405195869485937f022c0d9f0000000000000000000000000000000000000000000000000000000085528c6004860152836024860152166044840152608060648401528160848401525af1801561218d57612c35575b50948391604096612b57565b612c4087809261568f565b612189575f612c29565b8684612bb2565b612c5c838530615c9c565b15612c745750612c6b92615da8565b5f878382612ac5565b15612cba57612c839250615e2f565b3073ffffffffffffffffffffffffffffffffffffffff861603612ca6575b612c6b565b86341115612ca157612ca187340333615b7c565b612ca1923390615bc7565b90508911155f612aaa565b99989080612d5e57508115612d4f5734995b8a15612d2757906103e5612d03926103e8828e5b02910201918c0202615a25565b978015908115612d1c575b50156121e657838991612ab4565b90508810155f612d0e565b60048c7f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b612d5883615c6f565b99612ce2565b906103e5809b6103e8612d03949d8e612cf6565b906dffffffffffffffffffffffffffff8091612a58565b9150506060813d606011612ddd575b81612da56060938361568f565b810103126122e457612db681615a0a565b6040612dc460208401615a0a565b92015163ffffffff811603612dd9575f612a3f565b8c80fd5b3d9150612d98565b7fe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c630361298c565b73c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac92612918565b600192506128d6565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc295506128ad565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292506128a8565b6004887f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457612ec2615458565b9060243590612ecf6154e4565b90612ed8615507565b9160843593612ee56154c1565b9560c43567ffffffffffffffff811161281b57612f0690369060040161555a565b909773ffffffffffffffffffffffffffffffffffffffff871698891593845f14613109578631955b73ffffffffffffffffffffffffffffffffffffffff821661309e575b505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691823b1561232e5791612fc993918893604051958694859384937f1cff79cd000000000000000000000000000000000000000000000000000000008552600485016159da565b039134905af1801561186357908591613089575b50612ff1929115905061307a5782316158ae565b9380851061304657506020945073ffffffffffffffffffffffffffffffffffffffff163014613025575b5050604051908152f35b606090604051923082528552806040522082815c01905d6040525f8061301b565b8260649186887f20768e08000000000000000000000000000000000000000000000000000000008452600452602452604452fd5b6130848386615e01565b6158ae565b816130939161568f565b61281f57835f612fdd565b8381156130b7576130b0923390615bc7565b5f80612f4a565b50506130c281615c6f565b9083600183116130d5575b5050506130b0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613101930191615da8565b5f80836130cd565b613113878a615e01565b95612f2e565b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745761314c615458565b6fa1903eab0000000000000000000000008252602082602460103473ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610372578151906f8fcb4e5b0000000000000000000000008352601452806034528138604460108373ae7ab96520de3a18e5e111b5eaab095312d7fe845af11561037257602091603452604051908152f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613204615458565b61320c61554b565b6132146154e4565b9073ffffffffffffffffffffffffffffffffffffffff8454163303610c88571561329d5773ffffffffffffffffffffffffffffffffffffffff6044602092858360405196879586947f558a729700000000000000000000000000000000000000000000000000000000865216600485015260016024850152165af180156106e7576106bf575080f35b61049091615d2e565b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576132d9615458565b6024356132e46154e4565b9060643567ffffffffffffffff811161281b5761330590369060040161559a565b60843567ffffffffffffffff81116123325761332590369060040161559a565b9561332e6154c1565b60c43567ffffffffffffffff81116136c257906133518a9392369060040161555a565b909261335c8761593a565b98855b8b898b818403613651575050505073ffffffffffffffffffffffffffffffffffffffff82166135e6575b505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b1561281b57613405938593604051958694859384937f1cff79cd000000000000000000000000000000000000000000000000000000008552600485016159da565b039134905af180156106e7576135d1575b50506134248295949561593a565b9573ffffffffffffffffffffffffffffffffffffffff8516301495885b84810361348e57888a604051918291602083016020845282518091526020604085019301915b818110613475575050500390f35b8251845285945060209384019390920191600101613467565b73ffffffffffffffffffffffffffffffffffffffff6134b161269283888a6159b6565b166135b2576134cd87315b6134c683856159c6565b51906158ae565b6134d7828b6159c6565b526134e2818a6159c6565b516134ee8285876159b6565b351161354157613502908861350757615989565b613441565b61351561269282888a6159b6565b61351f828c6159c6565b51604051918d3090526020528c60405260608d2090815c01905d604052615989565b89939150613581818a9461357a8261357461269273ffffffffffffffffffffffffffffffffffffffff9760649c8e6159b6565b976159c6565b51946159b6565b35927f20768e0800000000000000000000000000000000000000000000000000000000855216600452602452604452fd5b6134cd6135cc886135c7612692858a8c6159b6565b615e01565b6134bc565b816135db9161568f565b61233257865f613416565b8381156135ff576135f8923390615bc7565b5f80613389565b505061360a81615c6f565b90836001831161361d575b5050506135f8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613649930191615da8565b5f8083613615565b90816136a095969798999a73ffffffffffffffffffffffffffffffffffffffff61368161269288868199986159b6565b16151590506136ac5750509050315b61369a828d6159c6565b52615989565b908c959493929161335f565b6136bd936135c792612692926159b6565b613690565b8980fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff81116103725761371190369060040161555a565b60206137a561371e6154e4565b9260405183810190602435825273ffffffffffffffffffffffffffffffffffffffff861660408201526040815261375660608261568f565b5190209447916137668330615cd9565b50604051968794859384937fea9384fa0000000000000000000000000000000000000000000000000000000085526040600486015260448501916156d0565b90602483015203916e696760e15f265e828db644a0c242eb5af191821561104b578392613878575b50826e696760e15f265e828db644a0c242eb3b15610374576040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9290921660248301526044820183905281606481836e696760e15f265e828db644a0c242eb5af1801561104b57613863575b602082604051908152f35b61386e83809261568f565b6103725781613858565b9091506020813d6020116138a4575b816138946020938361568f565b810103126101495751905f6137cd565b3d9150613887565b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374578060443560ff8116809103610a5757736b175474e89094c44da98b954eedeac495271d0f3b15610a5757604051907f8fcbaf0c000000000000000000000000000000000000000000000000000000008252336004830152306024830152600435604483015260243560648301526001608483015260a482015260643560c482015260843560e482015281816101048183736b175474e89094c44da98b954eedeac495271d0f5af180156106e7576124085750f35b506101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576139bf615458565b6139c761554b565b6139cf615588565b606435908160020b80920361281b576139e661549e565b926139ef6154c1565b9360c43592610104354211612e675787939215929190838381613c18575b50613ba8575b90613ad29562ffffff73ffffffffffffffffffffffffffffffffffffffff9360405196336020890152858c16604089015215606088015216608086015260a08501521660c083015273ffffffffffffffffffffffffffffffffffffffff851660e083015261010082015260e4356101208201526101208152613a976101408261568f565b604051809381927f48c894910000000000000000000000000000000000000000000000000000000083526020600484015260248301906155cb565b0381836e04444c5dc75cb358380d2e3de08a905af1908115611826578491613b30575b5060408180518101031261281f5760606040948560208401519301519386519582526020528086522082815c01905d82845282526020820152f35b9050833d8082843e613b42818461568f565b8201916020818403126103725780519067ffffffffffffffff8211610910570182601f82011215610372578051613b78816158e8565b93613b86604051958661568f565b81855260208284010111610910578060208093018386015e830101525f613af5565b9390929491505073ffffffffffffffffffffffffffffffffffffffff8216155f14613c095734925b8315613be157918793919492613a13565b6004887f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b613c1282615c6f565b92613bd0565b9050155f613a0d565b50346103745760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613c59615458565b50613c6261547b565b5060643567ffffffffffffffff811161037257613c8390369060040161555a565b505060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b506105207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613ce3615458565b90613cec61554b565b91366101a41161037257366104241161037257366104c411610372576104c435926104e43591610504354211614fb557613d24615765565b91849182805b60058110614f63575b5073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8514851517938897845f14614ed75760018201805b6148245750871515888a8261481a575b50506147f2575b85156147ec5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2965b613d9d8a8930615c9c565b1561479d575b918992823060601b915b8382111561400a57505050508415998a5f14613ff45782988015159081613fea575b50613fc25760409a5b15613f065750821573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84141715613eba5750613e09915082615b7c565b81613e99575b50613e23575b505082519182526020820152f35b15613e7157504780613e61575b50613e39615c2e565b80613e48575b505b5f80613e15565b80613e55613e5b92615d03565b33615b7c565b5f613e3f565b613e6b9033615b7c565b5f613e30565b613e7a81615c6f565b80613e87575b5050613e41565b613e92913390615da8565b5f80613e80565b73ffffffffffffffffffffffffffffffffffffffff1630141590505f613e0f565b8373ffffffffffffffffffffffffffffffffffffffff81163003613ef657506060908a5193858252602052808b522090815c01905d8752613e09565b9050613f0192615da8565b613e09565b909181613f12916158ae565b91831573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85141715613f5b5750613f3f91925083615b7c565b80613f4b575b50613e09565b613f559033615b7c565b5f613f45565b9073ffffffffffffffffffffffffffffffffffffffff85163003613fb15760608b519286815285602052808d522090815c01905d89525b80613f9f575b5050613e09565b613faa913390615da8565b5f80613f98565b613fbd91508484615da8565b613f92565b6004827f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b905083105f613dcf565b80919a985082106121e657988960409a98613dd8565b61401b612692600184811b01615726565b61402d6126926001850160011b615726565b9661403f61403a856157a9565b6157bc565b60408101516060820151946008821461466f57801573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8214171561466a575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b846040518160405289602c526fdd62ed3e000000000000000000000000600c526020806044601c865afa601f3d111660205102906040521561465a575b5050891573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8b141793841561464b5747955b8a6001840361427a575073ffffffffffffffffffffffffffffffffffffffff9250600a036141f657169060208151600f0b910151600f0b90823b156136c2576040517f3df02124000000000000000000000000000000000000000000000000000000008152600f91820b600482015291900b602482015260448101929092525f606483015287908290608490829084905af1801561218d579087916141e1575b50505b156141d357475b818111156141ab570394906001905b0190613dad565b6004867f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b6141dc86615c6f565b614195565b816141eb9161568f565b61218957855f61418b565b16906020815191015191803b156136c2578992918360849260405196879586947f5b41b9080000000000000000000000000000000000000000000000000000000086526004860152602485015260448401528160648401525af1801561218d57908791614265575b505061418e565b8161426f9161568f565b61218957855f61425e565b91926002810361431a5750505073ffffffffffffffffffffffffffffffffffffffff169060208151600f0b910151600f0b90823b156136c2576040517fa6417ed6000000000000000000000000000000000000000000000000000000008152600f91820b600482015291900b602482015260448101929092525f606483015287908290608490829084905af1801561218d5790879161426557505061418e565b9294939192600481036145565750600a81036143f157506040516020936143a8936101249361435c9161010090614351828761568f565b503685375183615876565b528a73ffffffffffffffffffffffffffffffffffffffff60405196879586947f52d7f3170000000000000000000000000000000000000000000000000000000086526004860190615887565b82610104850152165af1801561218d576143c3575b5061418e565b6143e39060203d81116143ea575b6143db818361568f565b810190615808565b505f6143bd565b503d6143d1565b90919060148103614497575060648160209394614473935061442860409687519361441c898661568f565b5087368537518361583e565b528b73ffffffffffffffffffffffffffffffffffffffff865197889586947f0b4c7e4d000000000000000000000000000000000000000000000000000000008652600486019061584f565b826044850152165af190811561448e57506143c3575061418e565b513d89823e3d90fd5b601e1415905061452e576084896020936144c9614515946060604051946144be828761568f565b5036853751836157f7565b528a73ffffffffffffffffffffffffffffffffffffffff60405196879586947f4515cef30000000000000000000000000000000000000000000000000000000086526004860190615817565b826064850152165af1801561218d576143c3575061418e565b6004897f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b9194925090600603611c075760209173ffffffffffffffffffffffffffffffffffffffff91600a036145e85716920151600f0b90823b1561277a5790606489928360405195869485937f1a4d01d2000000000000000000000000000000000000000000000000000000008552600485015260248401528160448401525af1801561218d5790879161426557505061418e565b1692015190823b1561277a5790606489928360405195869485937ff1dc3cc9000000000000000000000000000000000000000000000000000000008552600485015260248401528160448401525af1801561218d5790879161426557505061418e565b6146548b615c6f565b956140eb565b61466391615d2e565b5f846140c5565b614088565b9350505096915073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81148115178061476a575b156146fd575050806146c0575b600173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916141a4565b8447106146d5576146d085615a9b565b6146a3565b6004847f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff1673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2149081614748575b50156146d55761473f85615d03565b600184916141a4565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81149015175f614730565b5073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff831614614696565b86156147e0578934106147b8576147b38a615a9b565b613da3565b6004827f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b6147b38a30338b615bc7565b86613d92565b807f7dd37f700000000000000000000000000000000000000000000000000000000060049252fd5b119050885f613d6e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614857612692600183811b01615726565b61486361403a836157a9565b604081015160608201519060088103614881575b5050505080613d5e565b939c93600181036149fa5750600a0361494b5780516020918201516040517f67df02ca000000000000000000000000000000000000000000000000000000008152600f92830b6004820152910b60248201526044810193909352908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a918391614917575b50995b5f8080614877565b9150506020813d8211614943575b816149326020938361568f565b81010312610149578990515f61490c565b3d9150614925565b80516020918201516040517f37ed3a7a000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044810193909352908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a9183916149c6575b509961490f565b9150506020813d82116149f2575b816149e16020938361568f565b81010312610149578990515f6149bf565b3d91506149d4565b9193929160028103614ba157505060208351600f0b930151600f0b9084841380614b98575b15614b1d575060058c1015614af0576020917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8092614ad58f614a7d73ffffffffffffffffffffffffffffffffffffffff9160051b61042401615788565b1693604051978896879586957f67df02ca00000000000000000000000000000000000000000000000000000000875201600f0b9101600f0b600485016040919493926060820195600f0b8252600f0b60208201520152565b03915afa9081156106e757908a9183916149c657509961490f565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6040517f0e71d1b9000000000000000000000000000000000000000000000000000000008152600f94850b60048201529190930b60248201526044810191909152906020908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a9183916149c657509961490f565b50848213614a1f565b9293919260048103614cc357506020929391600a604492145f14614c295751600f0b9173ffffffffffffffffffffffffffffffffffffffff60405195869485937fcc2b27d700000000000000000000000000000000000000000000000000000000855260048501526024840152165afa9081156106e757908a9183916149c657505b9961490f565b519173ffffffffffffffffffffffffffffffffffffffff60405195869485937f4fb08c5e00000000000000000000000000000000000000000000000000000000855260048501526024840152165afa9081156106e757908a918391614c8f575b50614c23565b9150506020813d8211614cbb575b81614caa6020938361568f565b81010312610149578990515f614c89565b3d9150614c9d565b600603614eaf57600a8103614d6b5750610124614d4a9160209394614cff856101009360405194614cf4818761568f565b368637015183615876565b5273ffffffffffffffffffffffffffffffffffffffff60405195869485937f2f0149080000000000000000000000000000000000000000000000000000000085526004850190615887565b87610104840152165afa9081156106e757908a9183916149c657509961490f565b60148103614e105750614de66064602092604095614d9c85885193614d908a8661568f565b8936863701518361583e565b5273ffffffffffffffffffffffffffffffffffffffff865195869485937fed8e84f3000000000000000000000000000000000000000000000000000000008552600485019061584f565b886044840152165afa918215614e075750908a9183916149c657509961490f565b513d84823e3d90fd5b91929091601e036146d5576084602092614e8f92614e448560609360405194614e39818761568f565b3686370151836157f7565b5273ffffffffffffffffffffffffffffffffffffffff60405195869485937f3883e1190000000000000000000000000000000000000000000000000000000085526004850190615817565b876064840152165afa9081156106e757908a9183916149c657509961490f565b6004857f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b975088614f23578415614f145734975b88613d7557807f7c7f7bb90000000000000000000000000000000000000000000000000000000060049252fd5b614f1d86615c6f565b97614ee7565b88978580614f59575b15613d7557807f85cf0a350000000000000000000000000000000000000000000000000000000060049252fd5b5089341415614f2c565b939073ffffffffffffffffffffffffffffffffffffffff614f8b612692600188811b01615726565b1615614fae575050614fa56126926001850160011b615726565b60018401613d2a565b9093613d33565b6004847f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457615010615458565b34159060443560243583156150fb575b73ffffffffffffffffffffffffffffffffffffffff83169384151590816150f3575b50615054575b61049093503092615ae3565b8061506f57610490935061506a82303386615bc7565b615048565b6040517ffe99049a0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810182905260648101839052936020908590608490829089905af193841561186357610490946150d4575b50615048565b6150ec9060203d6020116106e0576106d8818361568f565b505f6150ce565b90505f615042565b806151aa5773ffffffffffffffffffffffffffffffffffffffff831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2810361517057508134036151485761514382615afe565b615020565b6004857f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b6151a457815b3414615020576004857f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b84615176565b6004857fdfa1a408000000000000000000000000000000000000000000000000000000008152fd5b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014957615205615458565b6024359060843567ffffffffffffffff81116101495761522990369060040161555a565b604051916152368361560e565b73ffffffffffffffffffffffffffffffffffffffff841683528460208401526040519261526284615657565b83526020830192604435845260408101916064358352604051906152858261560e565b3082528760208301526e22d473030f116ddee9f6b43ac78ba33b15610149575f9461533b6153549361530796604051998a9889987f30f28b7a000000000000000000000000000000000000000000000000000000008a5260048a0190516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b516044880152516064870152805173ffffffffffffffffffffffffffffffffffffffff1660848701526020015160a4860152565b3360c485015261010060e48501526101048401916156d0565b0381836e22d473030f116ddee9f6b43ac78ba35af180156153a15761538c575b50308352602052816040526060822090815c01905d80f35b6153999193505f9061568f565b5f915f615374565b6040513d5f823e3d90fd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610149576153de615458565b6153e661554b565b9073ffffffffffffffffffffffffffffffffffffffff5f541633036100f05773ffffffffffffffffffffffffffffffffffffffff165f52600160205260405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00835416911515161790555f80f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6084359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b60a4359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6064359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b60243590811515820361014957565b9181601f840112156101495782359167ffffffffffffffff8311610149576020838186019501011161014957565b6044359062ffffff8216820361014957565b9181601f840112156101495782359167ffffffffffffffff8311610149576020808501948460051b01011161014957565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b6040810190811067ffffffffffffffff82111761562a57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761562a57604052565b60a0810190811067ffffffffffffffff82111761562a57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761562a57604052565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b90816020910312610149575180151581036101495790565b600b8110156157385760051b60440190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60443573ffffffffffffffffffffffffffffffffffffffff811681036101495790565b3573ffffffffffffffffffffffffffffffffffffffff811681036101495790565b60058110156157385760071b6101a40190565b604051906157cb60808361568f565b81608082019136831161014957905b8282106157e75750505090565b81358152602091820191016157da565b9060038110156157385760051b0190565b90816020910312610149575190565b905f905b6003821061582857505050565b602080600192855181520193019101909161581b565b9060028110156157385760051b0190565b905f905b6002821061586057505050565b6020806001928551815201930191019091615853565b9060088110156157385760051b0190565b905f905b6008821061589857505050565b602080600192855181520193019101909161588b565b919082039182116158bb57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff811161562a57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b67ffffffffffffffff811161562a5760051b60200190565b9061594482615922565b615951604051918261568f565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061597f8294615922565b0190602036910137565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146158bb5760010190565b91908110156157385760051b0190565b80518210156157385760209160051b010190565b60409073ffffffffffffffffffffffffffffffffffffffff615a07959316815281602082015201916156d0565b90565b51906dffffffffffffffffffffffffffff8216820361014957565b8115615a2f570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b91908110156157385760061b0190565b3d15615a96573d90615a7d826158e8565b91615a8b604051938461568f565b82523d5f602084013e565b606090565b80615ade5750475b615aac81615afe565b60405190305f5273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26020525f60405260605f2090815c01905d604052565b615aa3565b604051935f5260205260405260605f2090815c01905d604052565b3073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214615b4a575f908180389273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af115615b3d57565b63b12d13eb5f526004601cfd5b6040519073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f525f6020525f60405260605f2090815c01905d604052565b903073ffffffffffffffffffffffffffffffffffffffff831614615baa57905f80809338935af115615b3d57565b604051915f525f6020525f60405260605f2090815c01905d604052565b916040519360605260405260601b602c526f23b872dd000000000000000000000000600c5260205f6064601c82855af1908160015f51141615615c10575b50505f606052604052565b3b153d171015615c21575f80615c05565b637939f4245f526004601cfd5b306014526f70a082310000000000000000000000005f526020806024601073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25afa601f3d11166020510290565b6020602460108293306014526f70a082310000000000000000000000005f525afa601f3d11166020510290565b9092915f93604051925f526020525f60405260605f2090815c81811015615cc6575b505050604052565b909192945003905d6001915f8080615cbe565b9190915f92604051915f525f6020525f60405260605f2090815c81811015615cc657505050604052565b632e1a7d4d5f526020525f386024601c8373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af150565b906014527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6034526f095ea7b30000000000000000000000005f5260205f6044601082855af1908160015f51141615615d8a575b50505f603452565b3b153d171015615d9b575f80615d82565b633e3f8f735f526004601cfd5b91906014526034526fa9059cbb0000000000000000000000005f5260205f6044601082855af1908160015f51141615615de35750505f603452565b3b153d171015615df4575f80615d82565b6390b8ec185f526004601cfd5b602460106020939284936014526f70a082310000000000000000000000005f525afa601f3d11166020510290565b5f3881808573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1506014526034526fa9059cbb0000000000000000000000005f525f38604460108373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1505f603452565b73ffffffffffffffffffffffffffffffffffffffff821673ffffffffffffffffffffffffffffffffffffffff82161090815f14615ec45792565b9192565b606091615ed491615e8a565b9390604051928352602083015260408201522060ff5f537fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b546035527f1f98431c8ad98523631ae4a59f267346ea31f98400000000000000000000000060015260155260555f205f6035529156fea2646970667358221220680d3856dd5dd9a45a7a5d84fcf6d844dbc78e980b32ee2b70e49457f3162b8964736f6c634300082100336080806040523460145760fc90816100198239f35b5f80fdfe60808060405260043610156011575f80fd5b5f3560e01c631cff79cd146023575f80fd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011260c25760043573ffffffffffffffffffffffffffffffffffffffff8116810360c2576024359067ffffffffffffffff821160c2573660238301121560c257816004013567ffffffffffffffff811160c257366024828501011160c2578060245f9401853783389234905af11560ba57005b3d5f823e3d90fd5b5f80fdfea26469706673582212200f5b73cf8afffc1fc335ed24633eddf2915c1ffea4db11019ab1228a477a388b64736f6c63430008210033
Deployed Bytecode
0x6080604052600436101561014d575b36156100b7575f5c61014957609a3560601c6024356004358015801590610140575b156101185761004a60d63560e81c60ae3560601c85615ec8565b939073ffffffffffffffffffffffffffffffffffffffff811633036100f05784156100e95782905b61007d828430615c9c565b156100c05761008b92615da8565b6085355f1a61009657005b6100b792156100b957505b5f036100ac81615d03565b60c23560601c615b7c565b005b90506100a1565b6084355f1a156100d9576100d49250615e2f565b61008b565b6100d49260863560601c90615bc7565b8390610072565b7f82b42900000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f7c7f7bb9000000000000000000000000000000000000000000000000000000005f5260045ffd5b50811515610030565b5f80fd5b5f5f3560e01c806306262f1b146153ac57806309d31579146151d25780630efe6a8b14614fdd57806312db224a14613caf578063150b7a0214613c2157806321c0dad21461398b578063230390f4146138ac5780632cb9f974146136c65780633f896275146132a657806341abb1ef146131d157806347c1ba3a146131195780635f3bd1c814612e8f5780636e0a4f98146128235780637984d8b1146124195780637ac2ff7b1461233657806391dd734614611cfe5780639d5b5af8146113dc578063ac9650d8146111c5578063afeae12b14610cb0578063b61d27f614610b92578063bd6b76d714610a60578063c391b38114610914578063c42957a81461073e578063cb019b841461054f578063de0e9a3e14610502578063e8382b0114610493578063ea598cb01461045a578063f2fde38b146103775763f978602c14610297575061000e565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576102c9615458565b8138818034737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af11561037257306014526f70a08231000000000000000000000000825260208260246010737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05afa15610372578151906fa9059cbb00000000000000000000000083526014528060345281386044601083737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af11561037257602091603452604051908152f35b505b80fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576103aa615458565b81549073ffffffffffffffffffffffffffffffffffffffff82163303610432579073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116178255337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b6004837f82b42900000000000000000000000000000000000000000000000000000000008152fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610490600435615a9b565b80f35b503461037457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025fc36455aa30d012bbfb86f283975440d7ee8db168152f35b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457600435806105465750610490610541615c2e565b615d03565b61049090615d03565b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610582615458565b60243590604435610591615507565b9173ffffffffffffffffffffffffffffffffffffffff8116806105c85750610490935050806105c257504790615b7c565b90615b7c565b9092919085856105ee5750610490945050806105e857506105e882615c6f565b91615da8565b92935091908061072e57506040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260248101859052602081604481865afa9081156106e75782916106f2575b509360209392916106ac95935b604051968795869485937f095bcdb60000000000000000000000000000000000000000000000000000000085526004850160409194939273ffffffffffffffffffffffffffffffffffffffff606083019616825260208201520152565b03925af180156106e7576106bf575b5080f35b6106bb9060203d6020116106e0575b6106d8818361568f565b81019061570e565b503d6106ce565b6040513d84823e3d90fd5b93929150506020833d602011610726575b816107106020938361568f565b8101031261014957915190919084906020610642565b3d9150610703565b9360209392916106ac959361064f565b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360161016081126103725760a0136103745760a4356101243573ffffffffffffffffffffffffffffffffffffffff81168091036109105760609073ffffffffffffffffffffffffffffffffffffffff6107b7615765565b1661090657610164835b60405194859384927fc42957a80000000000000000000000000000000000000000000000000000000084526004356004850152602435602485015273ffffffffffffffffffffffffffffffffffffffff6108196154e4565b16604485015273ffffffffffffffffffffffffffffffffffffffff61083c615507565b166064850152608435608485015260a484015260c43560c484015260e43560e484015261010435610104840152610124830152610144356101448301526d040470635eb91b7ce4d132d616ed5af180156106e75782918380926108c1575b50506108bd90604051938493846040919493926060820195825260208201520152565b0390f35b92509250506060823d6060116108fe575b816108df6060938361568f565b810103126103745750805160208201516040909201516108bd5f61089a565b3d91506108d2565b61016484936107c1565b8280fd5b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745780610948615458565b6024356fd5002f2e00000000000000000000000083526020836004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5c5782516f37cfdaca00000000000000000000000084526020846004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5a578351820290808204910615150191348311610a5a578338818086737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af115610a5a576fa9059cbb000000000000000000000000845260145260345281386044601083737f39c581f595b53c5cb19bd0b3f8da6c935e2ca05af115610a575781603452803411610a395750f35b818038923403335af115610a4a5780f35b63b12d13eb90526004601cfd5b50fd5b505b5050fd5b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745780610a94615458565b6fd5002f2e00000000000000000000000082526020826004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a575781516f37cfdaca00000000000000000000000083526020836004601073ae7ab96520de3a18e5e111b5eaab095312d7fe845afa15610a5c57825190806024350282808204910615150191820290808204910615150191348311610a5a57833881808673ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610a5a576f8fcb4e5b00000000000000000000000084526014526034528138604460108373ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610a575781603452803411610a395750f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610bc5615458565b60443567ffffffffffffffff811161091057610be590369060040161555a565b73ffffffffffffffffffffffffffffffffffffffff839293168452600160205260ff60408520541615610c88579083916001835d80604051948537833892602435905af115610c7f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0903d81523d83602083013e610c7a3d820191602083019485604052805d6020855260408301906155cb565b030190f35b903d90823e3d90fd5b6004847f82b42900000000000000000000000000000000000000000000000000000000008152fd5b506101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457610ce4615458565b610cec61554b565b90610cf5615588565b90610cfe615507565b91610d0761549e565b60e435421161119d5794849560a435819373ffffffffffffffffffffffffffffffffffffffff87931615928373ffffffffffffffffffffffffffffffffffffffff891615611181575b611165575b808786610d64858a8096615ec8565b9d8e9591948615611148578d8a6401000276a49a5b84158061113e575b6110c8575b81156110c15730945b156110565786039a7fffffff000000000000000000000000000000000000000000000000000000000060409b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9a818c9a81610ea69a8d995b60408b90519c161560f81b60208d015260f81b60218c01523360601b60228c015260601b1660368a015260601b16604a88015260601b16605e86015260e81b16607284015260558352610e5160758461568f565b8a519b8c9a8b998a977f128acb0800000000000000000000000000000000000000000000000000000000895216600488015215156024870152604486015216606484015260a0608484015260a48301906155cb565b0393165af196871561104b5783918498611010575b5060c435610fa2575b5060409715610f865773ffffffffffffffffffffffffffffffffffffffff905b838112610f7e57965b838113610f78578303955b1615610f33575b15610f14575b50505082519182526020820152f35b60609186519382526020528086522082815c01905d83525f8080610f05565b4780151580610f58575b610f48575b50610eff565b610f529033615b7c565b5f610f42565b503073ffffffffffffffffffffffffffffffffffffffff86161415610f3d565b95610ef8565b830396610eed565b9573ffffffffffffffffffffffffffffffffffffffff90610ee4565b15610fef578715610fe957805b60c43510610fc1576040975b97610ec4565b6004837f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b86610faf565b871561100a57865b60c43590840310610fc157604097610fbb565b80610ff7565b915096506040813d604011611043575b8161102d6040938361568f565b810103126109105760208151910151965f610ebb565b3d9150611020565b6040513d85823e3d90fd5b9a7fffffff000000000000000000000000000000000000000000000000000000000060409b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000073ffffffffffffffffffffffffffffffffffffffff9a818c9a81610ea69a8d99610dfd565b8794610d8f565b505050949550505090505073ffffffffffffffffffffffffffffffffffffffff8916155f1461113057345b80156111085786888c8e95948d8a8e96610d86565b6004877f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b61113981615c6f565b6110f3565b5060a43515610d81565b8d8a73fffd8963efd1fc6a506488495d951d5263988d259a610d79565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29550610d55565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29150610d50565b6004867f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff81116103725761121090369060040161559a565b9061121a82615922565b91611228604051938461568f565b8083527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061125582615922565b01845b8181106113cb5750509083907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301915b8381036113155784866040519182916020830160208452825180915260408401602060408360051b870101940192905b8282106112ca57505050500390f35b91936020611305827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288516155cb565b96019201920185949391926112bb565b8381101561139e57858160051b8301358481121561037257830180359067ffffffffffffffff82116109105760200190803603821361091057829181604051928392833781018381520390305af461136b615a6c565b901561139657906113919161138082886159c6565b5261138b81876159c6565b50615989565b61128b565b602081519101fd5b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b806060602080938801015201611258565b506101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457611410615458565b61141861554b565b611420615507565b61142861549e565b9260e4359361012435421161119d57858573ffffffffffffffffffffffffffffffffffffffff806101243561145d8689615e8a565b9491909316928982168403611cf25760a4359360c4355b6040519561148187615673565b8652602086015260408501521660608301526044356080830152881580948195611ce9575b50611bd3575b84939291908315611bca578a5b8590604051903088528b60205260a4356040526060882090815c81811015611bb7575b50505060405215611aa7575b610124357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14611a91578a6d040470635eb91b7ce4d132d616ed945b73ffffffffffffffffffffffffffffffffffffffff8616906d08882d72efa6cce4b6a40b24c8608214611a6f575b156119045761164b9261161f916d040470635eb91b7ce4d132d616ed036118dc578a7f3c5eec5000000000000000000000000000000000000000000000000000000000965b60405196879560208701998a5261010435916024880192936101209473ffffffffffffffffffffffffffffffffffffffff939897969298608061014087019a80518852602081015160208901528660408201511660408901528660608201511660608901520151608087015260a086015260c0850152151560e0840152166101008201520152565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810183528261568f565b73ffffffffffffffffffffffffffffffffffffffff88166118d55789905b51925af1611675615a6c565b90156118ad576020815191818082019384920101031261014957515b84156118a75794935b80611887575b1561186e57505073ffffffffffffffffffffffffffffffffffffffff81166116ec57506040925047806116dc575b505b82519182526020820152f35b6116e69033615b7c565b5f6116ce565b60a43561171f576040935061170081615c6f565b8061170d575b50506116d0565b611718913390615da8565b5f80611706565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260a435602482015260208160448173ffffffffffffffffffffffffffffffffffffffff86165afa908115611863578591611831575b5080611791575b5050604092506116d0565b6040517f095bcdb600000000000000000000000000000000000000000000000000000000815233600482015260a435602482015260448101919091529060209082906064908290889073ffffffffffffffffffffffffffffffffffffffff165af180156118265760409450611807575b80611786565b61181f9060203d6020116106e0576106d8818361568f565b505f611801565b6040513d86823e3d90fd5b90506020813d60201161185b575b8161184c6020938361568f565b8101031261014957515f61177f565b3d915061183f565b6040513d87823e3d90fd5b604095506118829250839060c43590615ae3565b6116d0565b503073ffffffffffffffffffffffffffffffffffffffff831614156116a0565b9361169a565b6004877f28982d61000000000000000000000000000000000000000000000000000000008152fd5b8390611669565b8a7f7466fde70000000000000000000000000000000000000000000000000000000096611597565b6119cb9261161f916d040470635eb91b7ce4d132d616ed03611a47578a7f38c3f8db000000000000000000000000000000000000000000000000000000009660405196879560208701998a5261010435916024880192936101209473ffffffffffffffffffffffffffffffffffffffff939897969298608061014087019a80518852602081015160208901528660408201511660408901528660608201511660608901520151608087015260a086015260c0850152151560e0840152166101008201520152565b73ffffffffffffffffffffffffffffffffffffffff8816611a405761010435905b51925af16119f8615a6c565b9015611a1857602081519181808201938492010103126101495751611691565b6004877fb4fff567000000000000000000000000000000000000000000000000000000008152fd5b83906119ec565b8a7fd4ff3f0e0000000000000000000000000000000000000000000000000000000096611597565b6080850180516bffffffffffffffffffffffff16905242610708019350611552565b8a6d08882d72efa6cce4b6a40b24c86094611524565b73ffffffffffffffffffffffffffffffffffffffff8916611ac8575b6114e8565b60a435611aee578315611ae257611ac38b5b30338c615bc7565b611ac361010435611ada565b73ffffffffffffffffffffffffffffffffffffffff94508315611ba8576020611b658a8d5b6040517ffe99049a00000000000000000000000000000000000000000000000000000000815233600482015230602482015260a4356044820152606481019190915297889283918b9183906084820190565b0393165af1948515611b9d578695611b7e575b506114e8565b611b969060203d6020116106e0576106d8818361568f565b505f611b78565b6040513d88823e3d90fd5b6020611b658a61010435611b13565b909192935003905d6001905f80806114dc565b610104356114b9565b98509192509073ffffffffffffffffffffffffffffffffffffffff8616611c2f5734975b8815611c075790899392916114ac565b60048a7f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b60a435611c4557611c3f86615c6f565b97611bf7565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815230600482015260a435602482015260208160448173ffffffffffffffffffffffffffffffffffffffff8b165afa908115611cde578a91611cac575b5097611bf7565b90506020813d602011611cd6575b81611cc76020938361568f565b8101031261014957515f611ca5565b3d9150611cba565b6040513d8c823e3d90fd5b9050155f6114a6565b60c4359360a435611474565b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff811161037257611d4990369060040161555a565b6e04444c5dc75cb358380d2e3de08a90330361043257825c6109105781610120918101031261037257611d7b8161552a565b90611d886020820161552a565b90604081013590811593841583036121895760608201359162ffffff8316809303612332576080810135908160020b80920361232e57611dca60a0820161552a565b94611dd760c0830161552a565b9773ffffffffffffffffffffffffffffffffffffffff80808061010060e088013597013598169a169816991693848a108a1597815f14612326578c8c935b831561231f5788905b73ffffffffffffffffffffffffffffffffffffffff60405196611e4088615673565b16865273ffffffffffffffffffffffffffffffffffffffff602087019216825260408601938452606086019081526080860190838252885f146123165789935b5085156122fb576401000276a4945b60405193611e9c85615657565b87855260208501958652604085019673ffffffffffffffffffffffffffffffffffffffff168752604051987ff3cd914c000000000000000000000000000000000000000000000000000000008a525173ffffffffffffffffffffffffffffffffffffffff1660048a01525173ffffffffffffffffffffffffffffffffffffffff1660248901525162ffffff1660448801525160020b60648701525173ffffffffffffffffffffffffffffffffffffffff16608486015251151560a48501525160c48401525173ffffffffffffffffffffffffffffffffffffffff1660e4830152610104820161012090528b6101248301528b8233815a9361014492602095f19081156122f0578c916122a8575b6fffffffffffffffffffffffffffffffff92501561228c57821561228157165b905b333b1561227d578a6040517fa58411940000000000000000000000000000000000000000000000000000000081528b6004820152818160248183335af180156106e757612268575b505080156122615783995b6120298b8230615c9c565b1561223f578a881561222d575b50505b156122265780945b801515908161220e575b506121e65785156121d957600492602092156121d257505b604051928380927f11da60b4000000000000000000000000000000000000000000000000000000008252335af180156121c757612198575b5086333b15610374576040517f0b0d9c0900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201529185166024830152604482018390528160648183335af1801561218d57612174575b506108bd955060405194602086015260408501526040845261212c60608561568f565b612147575b50506040519182916020835260208301906155cb565b47908115159081612169575b50156121315761216291615b7c565b5f80612131565b90503014155f612153565b61217f87809261568f565b6121895785612109565b8580fd5b6040513d89823e3d90fd5b6020813d6020116121bf575b816121b16020938361568f565b81010312610149575161209b565b3d91506121a4565b6040513d8a823e3d90fd5b9050612063565b5050506004602088612063565b60048a7f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b9050821561221f5781115b5f61204b565b8510612219565b8294612041565b612238913390615da8565b5f8a612036565b8a881561224e575b5050612039565b61225a918b3391615bc7565b5f8a612247565b819961201e565b816122729161568f565b61227d578a5f612013565b8a80fd5b60801d8b0316611fc9565b821561229d5760801d165b90611fcb565b600f0b8b0316612297565b90506020823d6020116122e8575b816122c36020938361568f565b810103126122e4576fffffffffffffffffffffffffffffffff915190611fa9565b8b80fd5b3d91506122b6565b6040513d8e823e3d90fd5b73fffd8963efd1fc6a506488495d951d5263988d2594611e8f565b89840393611e80565b8d90611e1e565b8c8793611e15565b8780fd5b8680fd5b5060c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374578061236a615458565b6064359060ff8216809203610a5c5773ffffffffffffffffffffffffffffffffffffffff1690813b15610a5c57829160e4839260405194859384927fd505accf00000000000000000000000000000000000000000000000000000000845233600485015230602485015260243560448501526044356064850152608484015260843560a484015260a43560c48401525af180156106e7576124085750f35b816124129161568f565b6103745780f35b5060807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff811161037257366023820112156103725780600401359067ffffffffffffffff8211610910576024808201918360061b010136811161281f5760643567ffffffffffffffff811161281b576124a990369060040161555a565b6124b285615922565b916124c0604051938461568f565b8583527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06124ed87615922565b01875b8181106127f8575050865b8681036127b657506040519361251085615657565b61251987615922565b90612527604051928361568f565b8782528690602083015b81831061277e575050508452602084019360243585526040810160443581526e22d473030f116ddee9f6b43ac78ba33b1561277a5790889594939291604051957f4da3e5d90000000000000000000000000000000000000000000000000000000087526080600488015260e4870192519260606084890152835180915260206101048901940190895b81811061272a575050505160a48701525160c48601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc85820301602486015260208085519283815201940190865b8181106126e0575050506126518593859384933360448601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8584030160648601526156d0565b0381836e22d473030f116ddee9f6b43ac78ba35af180156106e7576126cb575b5050825b828103612680578380f35b806126976126926126c6938686615a5c565b615788565b60206126a4838787615a5c565b013560405191308852602052866040526060872090815c01905d604052615989565b612675565b816126d59161568f565b61091057825f612671565b9195965091929360206040826127196001948a516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b019601910191899695949392612609565b9195969798995091929360206040826127666001948a516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b0196019101918c99989796959493926125ba565b8880fd5b60408336031261227d57602060409182516127988161560e565b6127a18661552a565b81528286013583820152815201920191612531565b8060206127c76127f3938a8a615a5c565b0135604051906127d68261560e565b30825260208201526127e882876159c6565b5261138b81866159c6565b6124fb565b6020906040516128078161560e565b8a81528a83820152828288010152016124f0565b8480fd5b8380fd5b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457612856615458565b61285e61554b565b6128666154e4565b9161286f615507565b60843560a4359460c43590814211612e675773ffffffffffffffffffffffffffffffffffffffff84811615939291908116158481612e4b575b612e2f575b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a9314612e26575b73ffffffffffffffffffffffffffffffffffffffff6128f58784615e8a565b9590919015908115612e0b57735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f925b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519181602084019460601b16845260601b1660348201526028815261296160488261568f565b5190209015612de5577f96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f5b604051917fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060208401947fff00000000000000000000000000000000000000000000000000000000000000865260601b16602184015260358301526055820152605581526129fb60758261568f565b51902016936040517f0902f1ac000000000000000000000000000000000000000000000000000000008152606081600481895afa9081156122f0578c908d92612d89575b508515612d72576dffffffffffffffffffffffffffff80915b169116995f14612cd057907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff612a9f926103e86103e584809e030293849202020101615a25565b988015908115612cc5575b50156121e6578389915b612abf838584615c9c565b15612c51575b505050505f14612ba9578115612ba25786305b823b156103725760a473ffffffffffffffffffffffffffffffffffffffff918360405195869485937f022c0d9f0000000000000000000000000000000000000000000000000000000085528360048601528c6024860152166044840152608060648401528160848401525af1801561218d57612b8d575b509483916040965b15612b705750506116d091612b6b82615d03565b615b7c565b6060925086519382526020528086522082815c01905d83526116d0565b612b9887809261568f565b612189575f612b4f565b8684612ad8565b8115612c4a5786305b823b156103725760a473ffffffffffffffffffffffffffffffffffffffff918360405195869485937f022c0d9f0000000000000000000000000000000000000000000000000000000085528c6004860152836024860152166044840152608060648401528160848401525af1801561218d57612c35575b50948391604096612b57565b612c4087809261568f565b612189575f612c29565b8684612bb2565b612c5c838530615c9c565b15612c745750612c6b92615da8565b5f878382612ac5565b15612cba57612c839250615e2f565b3073ffffffffffffffffffffffffffffffffffffffff861603612ca6575b612c6b565b86341115612ca157612ca187340333615b7c565b612ca1923390615bc7565b90508911155f612aaa565b99989080612d5e57508115612d4f5734995b8a15612d2757906103e5612d03926103e8828e5b02910201918c0202615a25565b978015908115612d1c575b50156121e657838991612ab4565b90508810155f612d0e565b60048c7f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b612d5883615c6f565b99612ce2565b906103e5809b6103e8612d03949d8e612cf6565b906dffffffffffffffffffffffffffff8091612a58565b9150506060813d606011612ddd575b81612da56060938361568f565b810103126122e457612db681615a0a565b6040612dc460208401615a0a565b92015163ffffffff811603612dd9575f612a3f565b8c80fd5b3d9150612d98565b7fe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c630361298c565b73c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac92612918565b600192506128d6565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc295506128ad565b73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc292506128a8565b6004887f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457612ec2615458565b9060243590612ecf6154e4565b90612ed8615507565b9160843593612ee56154c1565b9560c43567ffffffffffffffff811161281b57612f0690369060040161555a565b909773ffffffffffffffffffffffffffffffffffffffff871698891593845f14613109578631955b73ffffffffffffffffffffffffffffffffffffffff821661309e575b505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025fc36455aa30d012bbfb86f283975440d7ee8db1691823b1561232e5791612fc993918893604051958694859384937f1cff79cd000000000000000000000000000000000000000000000000000000008552600485016159da565b039134905af1801561186357908591613089575b50612ff1929115905061307a5782316158ae565b9380851061304657506020945073ffffffffffffffffffffffffffffffffffffffff163014613025575b5050604051908152f35b606090604051923082528552806040522082815c01905d6040525f8061301b565b8260649186887f20768e08000000000000000000000000000000000000000000000000000000008452600452602452604452fd5b6130848386615e01565b6158ae565b816130939161568f565b61281f57835f612fdd565b8381156130b7576130b0923390615bc7565b5f80612f4a565b50506130c281615c6f565b9083600183116130d5575b5050506130b0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613101930191615da8565b5f80836130cd565b613113878a615e01565b95612f2e565b5060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745761314c615458565b6fa1903eab0000000000000000000000008252602082602460103473ae7ab96520de3a18e5e111b5eaab095312d7fe845af115610372578151906f8fcb4e5b0000000000000000000000008352601452806034528138604460108373ae7ab96520de3a18e5e111b5eaab095312d7fe845af11561037257602091603452604051908152f35b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613204615458565b61320c61554b565b6132146154e4565b9073ffffffffffffffffffffffffffffffffffffffff8454163303610c88571561329d5773ffffffffffffffffffffffffffffffffffffffff6044602092858360405196879586947f558a729700000000000000000000000000000000000000000000000000000000865216600485015260016024850152165af180156106e7576106bf575080f35b61049091615d2e565b5060e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576132d9615458565b6024356132e46154e4565b9060643567ffffffffffffffff811161281b5761330590369060040161559a565b60843567ffffffffffffffff81116123325761332590369060040161559a565b9561332e6154c1565b60c43567ffffffffffffffff81116136c257906133518a9392369060040161555a565b909261335c8761593a565b98855b8b898b818403613651575050505073ffffffffffffffffffffffffffffffffffffffff82166135e6575b505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000025fc36455aa30d012bbfb86f283975440d7ee8db16803b1561281b57613405938593604051958694859384937f1cff79cd000000000000000000000000000000000000000000000000000000008552600485016159da565b039134905af180156106e7576135d1575b50506134248295949561593a565b9573ffffffffffffffffffffffffffffffffffffffff8516301495885b84810361348e57888a604051918291602083016020845282518091526020604085019301915b818110613475575050500390f35b8251845285945060209384019390920191600101613467565b73ffffffffffffffffffffffffffffffffffffffff6134b161269283888a6159b6565b166135b2576134cd87315b6134c683856159c6565b51906158ae565b6134d7828b6159c6565b526134e2818a6159c6565b516134ee8285876159b6565b351161354157613502908861350757615989565b613441565b61351561269282888a6159b6565b61351f828c6159c6565b51604051918d3090526020528c60405260608d2090815c01905d604052615989565b89939150613581818a9461357a8261357461269273ffffffffffffffffffffffffffffffffffffffff9760649c8e6159b6565b976159c6565b51946159b6565b35927f20768e0800000000000000000000000000000000000000000000000000000000855216600452602452604452fd5b6134cd6135cc886135c7612692858a8c6159b6565b615e01565b6134bc565b816135db9161568f565b61233257865f613416565b8381156135ff576135f8923390615bc7565b5f80613389565b505061360a81615c6f565b90836001831161361d575b5050506135f8565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613649930191615da8565b5f8083613615565b90816136a095969798999a73ffffffffffffffffffffffffffffffffffffffff61368161269288868199986159b6565b16151590506136ac5750509050315b61369a828d6159c6565b52615989565b908c959493929161335f565b6136bd936135c792612692926159b6565b613690565b8980fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103745760043567ffffffffffffffff81116103725761371190369060040161555a565b60206137a561371e6154e4565b9260405183810190602435825273ffffffffffffffffffffffffffffffffffffffff861660408201526040815261375660608261568f565b5190209447916137668330615cd9565b50604051968794859384937fea9384fa0000000000000000000000000000000000000000000000000000000085526040600486015260448501916156d0565b90602483015203916e696760e15f265e828db644a0c242eb5af191821561104b578392613878575b50826e696760e15f265e828db644a0c242eb3b15610374576040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9290921660248301526044820183905281606481836e696760e15f265e828db644a0c242eb5af1801561104b57613863575b602082604051908152f35b61386e83809261568f565b6103725781613858565b9091506020813d6020116138a4575b816138946020938361568f565b810103126101495751905f6137cd565b3d9150613887565b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374578060443560ff8116809103610a5757736b175474e89094c44da98b954eedeac495271d0f3b15610a5757604051907f8fcbaf0c000000000000000000000000000000000000000000000000000000008252336004830152306024830152600435604483015260243560648301526001608483015260a482015260643560c482015260843560e482015281816101048183736b175474e89094c44da98b954eedeac495271d0f5af180156106e7576124085750f35b506101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610374576139bf615458565b6139c761554b565b6139cf615588565b606435908160020b80920361281b576139e661549e565b926139ef6154c1565b9360c43592610104354211612e675787939215929190838381613c18575b50613ba8575b90613ad29562ffffff73ffffffffffffffffffffffffffffffffffffffff9360405196336020890152858c16604089015215606088015216608086015260a08501521660c083015273ffffffffffffffffffffffffffffffffffffffff851660e083015261010082015260e4356101208201526101208152613a976101408261568f565b604051809381927f48c894910000000000000000000000000000000000000000000000000000000083526020600484015260248301906155cb565b0381836e04444c5dc75cb358380d2e3de08a905af1908115611826578491613b30575b5060408180518101031261281f5760606040948560208401519301519386519582526020528086522082815c01905d82845282526020820152f35b9050833d8082843e613b42818461568f565b8201916020818403126103725780519067ffffffffffffffff8211610910570182601f82011215610372578051613b78816158e8565b93613b86604051958661568f565b81855260208284010111610910578060208093018386015e830101525f613af5565b9390929491505073ffffffffffffffffffffffffffffffffffffffff8216155f14613c095734925b8315613be157918793919492613a13565b6004887f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b613c1282615c6f565b92613bd0565b9050155f613a0d565b50346103745760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613c59615458565b50613c6261547b565b5060643567ffffffffffffffff811161037257613c8390369060040161555a565b505060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b506105207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457613ce3615458565b90613cec61554b565b91366101a41161037257366104241161037257366104c411610372576104c435926104e43591610504354211614fb557613d24615765565b91849182805b60058110614f63575b5073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8514851517938897845f14614ed75760018201805b6148245750871515888a8261481a575b50506147f2575b85156147ec5773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2965b613d9d8a8930615c9c565b1561479d575b918992823060601b915b8382111561400a57505050508415998a5f14613ff45782988015159081613fea575b50613fc25760409a5b15613f065750821573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84141715613eba5750613e09915082615b7c565b81613e99575b50613e23575b505082519182526020820152f35b15613e7157504780613e61575b50613e39615c2e565b80613e48575b505b5f80613e15565b80613e55613e5b92615d03565b33615b7c565b5f613e3f565b613e6b9033615b7c565b5f613e30565b613e7a81615c6f565b80613e87575b5050613e41565b613e92913390615da8565b5f80613e80565b73ffffffffffffffffffffffffffffffffffffffff1630141590505f613e0f565b8373ffffffffffffffffffffffffffffffffffffffff81163003613ef657506060908a5193858252602052808b522090815c01905d8752613e09565b9050613f0192615da8565b613e09565b909181613f12916158ae565b91831573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85141715613f5b5750613f3f91925083615b7c565b80613f4b575b50613e09565b613f559033615b7c565b5f613f45565b9073ffffffffffffffffffffffffffffffffffffffff85163003613fb15760608b519286815285602052808d522090815c01905d89525b80613f9f575b5050613e09565b613faa913390615da8565b5f80613f98565b613fbd91508484615da8565b613f92565b6004827f7dd37f70000000000000000000000000000000000000000000000000000000008152fd5b905083105f613dcf565b80919a985082106121e657988960409a98613dd8565b61401b612692600184811b01615726565b61402d6126926001850160011b615726565b9661403f61403a856157a9565b6157bc565b60408101516060820151946008821461466f57801573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8214171561466a575073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b846040518160405289602c526fdd62ed3e000000000000000000000000600c526020806044601c865afa601f3d111660205102906040521561465a575b5050891573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8b141793841561464b5747955b8a6001840361427a575073ffffffffffffffffffffffffffffffffffffffff9250600a036141f657169060208151600f0b910151600f0b90823b156136c2576040517f3df02124000000000000000000000000000000000000000000000000000000008152600f91820b600482015291900b602482015260448101929092525f606483015287908290608490829084905af1801561218d579087916141e1575b50505b156141d357475b818111156141ab570394906001905b0190613dad565b6004867f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b6141dc86615c6f565b614195565b816141eb9161568f565b61218957855f61418b565b16906020815191015191803b156136c2578992918360849260405196879586947f5b41b9080000000000000000000000000000000000000000000000000000000086526004860152602485015260448401528160648401525af1801561218d57908791614265575b505061418e565b8161426f9161568f565b61218957855f61425e565b91926002810361431a5750505073ffffffffffffffffffffffffffffffffffffffff169060208151600f0b910151600f0b90823b156136c2576040517fa6417ed6000000000000000000000000000000000000000000000000000000008152600f91820b600482015291900b602482015260448101929092525f606483015287908290608490829084905af1801561218d5790879161426557505061418e565b9294939192600481036145565750600a81036143f157506040516020936143a8936101249361435c9161010090614351828761568f565b503685375183615876565b528a73ffffffffffffffffffffffffffffffffffffffff60405196879586947f52d7f3170000000000000000000000000000000000000000000000000000000086526004860190615887565b82610104850152165af1801561218d576143c3575b5061418e565b6143e39060203d81116143ea575b6143db818361568f565b810190615808565b505f6143bd565b503d6143d1565b90919060148103614497575060648160209394614473935061442860409687519361441c898661568f565b5087368537518361583e565b528b73ffffffffffffffffffffffffffffffffffffffff865197889586947f0b4c7e4d000000000000000000000000000000000000000000000000000000008652600486019061584f565b826044850152165af190811561448e57506143c3575061418e565b513d89823e3d90fd5b601e1415905061452e576084896020936144c9614515946060604051946144be828761568f565b5036853751836157f7565b528a73ffffffffffffffffffffffffffffffffffffffff60405196879586947f4515cef30000000000000000000000000000000000000000000000000000000086526004860190615817565b826064850152165af1801561218d576143c3575061418e565b6004897f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b9194925090600603611c075760209173ffffffffffffffffffffffffffffffffffffffff91600a036145e85716920151600f0b90823b1561277a5790606489928360405195869485937f1a4d01d2000000000000000000000000000000000000000000000000000000008552600485015260248401528160448401525af1801561218d5790879161426557505061418e565b1692015190823b1561277a5790606489928360405195869485937ff1dc3cc9000000000000000000000000000000000000000000000000000000008552600485015260248401528160448401525af1801561218d5790879161426557505061418e565b6146548b615c6f565b956140eb565b61466391615d2e565b5f846140c5565b614088565b9350505096915073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81148115178061476a575b156146fd575050806146c0575b600173c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2916141a4565b8447106146d5576146d085615a9b565b6146a3565b6004847f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b73ffffffffffffffffffffffffffffffffffffffff1673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2149081614748575b50156146d55761473f85615d03565b600184916141a4565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81149015175f614730565b5073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff831614614696565b86156147e0578934106147b8576147b38a615a9b565b613da3565b6004827f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b6147b38a30338b615bc7565b86613d92565b807f7dd37f700000000000000000000000000000000000000000000000000000000060049252fd5b119050885f613d6e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01614857612692600183811b01615726565b61486361403a836157a9565b604081015160608201519060088103614881575b5050505080613d5e565b939c93600181036149fa5750600a0361494b5780516020918201516040517f67df02ca000000000000000000000000000000000000000000000000000000008152600f92830b6004820152910b60248201526044810193909352908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a918391614917575b50995b5f8080614877565b9150506020813d8211614943575b816149326020938361568f565b81010312610149578990515f61490c565b3d9150614925565b80516020918201516040517f37ed3a7a000000000000000000000000000000000000000000000000000000008152600481019290925260248201526044810193909352908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a9183916149c6575b509961490f565b9150506020813d82116149f2575b816149e16020938361568f565b81010312610149578990515f6149bf565b3d91506149d4565b9193929160028103614ba157505060208351600f0b930151600f0b9084841380614b98575b15614b1d575060058c1015614af0576020917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8092614ad58f614a7d73ffffffffffffffffffffffffffffffffffffffff9160051b61042401615788565b1693604051978896879586957f67df02ca00000000000000000000000000000000000000000000000000000000875201600f0b9101600f0b600485016040919493926060820195600f0b8252600f0b60208201520152565b03915afa9081156106e757908a9183916149c657509961490f565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6040517f0e71d1b9000000000000000000000000000000000000000000000000000000008152600f94850b60048201529190930b60248201526044810191909152906020908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156106e757908a9183916149c657509961490f565b50848213614a1f565b9293919260048103614cc357506020929391600a604492145f14614c295751600f0b9173ffffffffffffffffffffffffffffffffffffffff60405195869485937fcc2b27d700000000000000000000000000000000000000000000000000000000855260048501526024840152165afa9081156106e757908a9183916149c657505b9961490f565b519173ffffffffffffffffffffffffffffffffffffffff60405195869485937f4fb08c5e00000000000000000000000000000000000000000000000000000000855260048501526024840152165afa9081156106e757908a918391614c8f575b50614c23565b9150506020813d8211614cbb575b81614caa6020938361568f565b81010312610149578990515f614c89565b3d9150614c9d565b600603614eaf57600a8103614d6b5750610124614d4a9160209394614cff856101009360405194614cf4818761568f565b368637015183615876565b5273ffffffffffffffffffffffffffffffffffffffff60405195869485937f2f0149080000000000000000000000000000000000000000000000000000000085526004850190615887565b87610104840152165afa9081156106e757908a9183916149c657509961490f565b60148103614e105750614de66064602092604095614d9c85885193614d908a8661568f565b8936863701518361583e565b5273ffffffffffffffffffffffffffffffffffffffff865195869485937fed8e84f3000000000000000000000000000000000000000000000000000000008552600485019061584f565b886044840152165afa918215614e075750908a9183916149c657509961490f565b513d84823e3d90fd5b91929091601e036146d5576084602092614e8f92614e448560609360405194614e39818761568f565b3686370151836157f7565b5273ffffffffffffffffffffffffffffffffffffffff60405195869485937f3883e1190000000000000000000000000000000000000000000000000000000085526004850190615817565b876064840152165afa9081156106e757908a9183916149c657509961490f565b6004857f7c7f7bb9000000000000000000000000000000000000000000000000000000008152fd5b975088614f23578415614f145734975b88613d7557807f7c7f7bb90000000000000000000000000000000000000000000000000000000060049252fd5b614f1d86615c6f565b97614ee7565b88978580614f59575b15613d7557807f85cf0a350000000000000000000000000000000000000000000000000000000060049252fd5b5089341415614f2c565b939073ffffffffffffffffffffffffffffffffffffffff614f8b612692600188811b01615726565b1615614fae575050614fa56126926001850160011b615726565b60018401613d2a565b9093613d33565b6004847f203d82d8000000000000000000000000000000000000000000000000000000008152fd5b5060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261037457615010615458565b34159060443560243583156150fb575b73ffffffffffffffffffffffffffffffffffffffff83169384151590816150f3575b50615054575b61049093503092615ae3565b8061506f57610490935061506a82303386615bc7565b615048565b6040517ffe99049a0000000000000000000000000000000000000000000000000000000081523360048201523060248201526044810182905260648101839052936020908590608490829089905af193841561186357610490946150d4575b50615048565b6150ec9060203d6020116106e0576106d8818361568f565b505f6150ce565b90505f615042565b806151aa5773ffffffffffffffffffffffffffffffffffffffff831673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2810361517057508134036151485761514382615afe565b615020565b6004857f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b6151a457815b3414615020576004857f85cf0a35000000000000000000000000000000000000000000000000000000008152fd5b84615176565b6004857fdfa1a408000000000000000000000000000000000000000000000000000000008152fd5b5060a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014957615205615458565b6024359060843567ffffffffffffffff81116101495761522990369060040161555a565b604051916152368361560e565b73ffffffffffffffffffffffffffffffffffffffff841683528460208401526040519261526284615657565b83526020830192604435845260408101916064358352604051906152858261560e565b3082528760208301526e22d473030f116ddee9f6b43ac78ba33b15610149575f9461533b6153549361530796604051998a9889987f30f28b7a000000000000000000000000000000000000000000000000000000008a5260048a0190516020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b516044880152516064870152805173ffffffffffffffffffffffffffffffffffffffff1660848701526020015160a4860152565b3360c485015261010060e48501526101048401916156d0565b0381836e22d473030f116ddee9f6b43ac78ba35af180156153a15761538c575b50308352602052816040526060822090815c01905d80f35b6153999193505f9061568f565b5f915f615374565b6040513d5f823e3d90fd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610149576153de615458565b6153e661554b565b9073ffffffffffffffffffffffffffffffffffffffff5f541633036100f05773ffffffffffffffffffffffffffffffffffffffff165f52600160205260405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00835416911515161790555f80f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6084359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b60a4359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b6064359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b359073ffffffffffffffffffffffffffffffffffffffff8216820361014957565b60243590811515820361014957565b9181601f840112156101495782359167ffffffffffffffff8311610149576020838186019501011161014957565b6044359062ffffff8216820361014957565b9181601f840112156101495782359167ffffffffffffffff8311610149576020808501948460051b01011161014957565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b6040810190811067ffffffffffffffff82111761562a57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761562a57604052565b60a0810190811067ffffffffffffffff82111761562a57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761562a57604052565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b90816020910312610149575180151581036101495790565b600b8110156157385760051b60440190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60443573ffffffffffffffffffffffffffffffffffffffff811681036101495790565b3573ffffffffffffffffffffffffffffffffffffffff811681036101495790565b60058110156157385760071b6101a40190565b604051906157cb60808361568f565b81608082019136831161014957905b8282106157e75750505090565b81358152602091820191016157da565b9060038110156157385760051b0190565b90816020910312610149575190565b905f905b6003821061582857505050565b602080600192855181520193019101909161581b565b9060028110156157385760051b0190565b905f905b6002821061586057505050565b6020806001928551815201930191019091615853565b9060088110156157385760051b0190565b905f905b6008821061589857505050565b602080600192855181520193019101909161588b565b919082039182116158bb57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff811161562a57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b67ffffffffffffffff811161562a5760051b60200190565b9061594482615922565b615951604051918261568f565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061597f8294615922565b0190602036910137565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146158bb5760010190565b91908110156157385760051b0190565b80518210156157385760209160051b010190565b60409073ffffffffffffffffffffffffffffffffffffffff615a07959316815281602082015201916156d0565b90565b51906dffffffffffffffffffffffffffff8216820361014957565b8115615a2f570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b91908110156157385760061b0190565b3d15615a96573d90615a7d826158e8565b91615a8b604051938461568f565b82523d5f602084013e565b606090565b80615ade5750475b615aac81615afe565b60405190305f5273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26020525f60405260605f2090815c01905d604052565b615aa3565b604051935f5260205260405260605f2090815c01905d604052565b3073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214615b4a575f908180389273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af115615b3d57565b63b12d13eb5f526004601cfd5b6040519073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25f525f6020525f60405260605f2090815c01905d604052565b903073ffffffffffffffffffffffffffffffffffffffff831614615baa57905f80809338935af115615b3d57565b604051915f525f6020525f60405260605f2090815c01905d604052565b916040519360605260405260601b602c526f23b872dd000000000000000000000000600c5260205f6064601c82855af1908160015f51141615615c10575b50505f606052604052565b3b153d171015615c21575f80615c05565b637939f4245f526004601cfd5b306014526f70a082310000000000000000000000005f526020806024601073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25afa601f3d11166020510290565b6020602460108293306014526f70a082310000000000000000000000005f525afa601f3d11166020510290565b9092915f93604051925f526020525f60405260605f2090815c81811015615cc6575b505050604052565b909192945003905d6001915f8080615cbe565b9190915f92604051915f525f6020525f60405260605f2090815c81811015615cc657505050604052565b632e1a7d4d5f526020525f386024601c8373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af150565b906014527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6034526f095ea7b30000000000000000000000005f5260205f6044601082855af1908160015f51141615615d8a575b50505f603452565b3b153d171015615d9b575f80615d82565b633e3f8f735f526004601cfd5b91906014526034526fa9059cbb0000000000000000000000005f5260205f6044601082855af1908160015f51141615615de35750505f603452565b3b153d171015615df4575f80615d82565b6390b8ec185f526004601cfd5b602460106020939284936014526f70a082310000000000000000000000005f525afa601f3d11166020510290565b5f3881808573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1506014526034526fa9059cbb0000000000000000000000005f525f38604460108373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25af1505f603452565b73ffffffffffffffffffffffffffffffffffffffff821673ffffffffffffffffffffffffffffffffffffffff82161090815f14615ec45792565b9192565b606091615ed491615e8a565b9390604051928352602083015260408201522060ff5f537fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b546035527f1f98431c8ad98523631ae4a59f267346ea31f98400000000000000000000000060015260155260555f205f6035529156fea2646970667358221220680d3856dd5dd9a45a7a5d84fcf6d844dbc78e980b32ee2b70e49457f3162b8964736f6c63430008210033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 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.