Source Code
Latest 23 from a total of 23 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Add Liquidity | 50359180 | 2 days ago | IN | 0 MON | 0.4487206 | ||||
| Add Liquidity ET... | 49919869 | 4 days ago | IN | 250,100 MON | 0.15992417 | ||||
| Swap Exact Token... | 49797084 | 4 days ago | IN | 0 MON | 0.16072584 | ||||
| Add Liquidity ET... | 49008610 | 8 days ago | IN | 60,884.65335786 MON | 0.15939356 | ||||
| Add Liquidity ET... | 48782192 | 9 days ago | IN | 63,688.40074244 MON | 0.16006437 | ||||
| Add Liquidity ET... | 48371361 | 11 days ago | IN | 27,615.15531292 MON | 0.159829 | ||||
| Add Liquidity ET... | 48370818 | 11 days ago | IN | 20,040 MON | 0.16247529 | ||||
| Add Liquidity ET... | 47135535 | 17 days ago | IN | 29,786.36974847 MON | 0.13022743 | ||||
| Swap Exact Token... | 47135366 | 17 days ago | IN | 0 MON | 0.12385995 | ||||
| Swap Exact Token... | 47134890 | 17 days ago | IN | 0 MON | 0.12382315 | ||||
| Swap Exact Token... | 47133752 | 17 days ago | IN | 0 MON | 0.12386342 | ||||
| Swap Exact Token... | 47132833 | 17 days ago | IN | 0 MON | 0.12386005 | ||||
| Swap Exact Token... | 47132373 | 17 days ago | IN | 0 MON | 0.12386321 | ||||
| Add Liquidity ET... | 47126843 | 17 days ago | IN | 20,106.5974534 MON | 0.1202211 | ||||
| Add Liquidity ET... | 47104099 | 17 days ago | IN | 10 MON | 0.4451428 | ||||
| Add Liquidity ET... | 47101600 | 17 days ago | IN | 34,360 MON | 0.10659325 | ||||
| Remove Liquidity... | 42448018 | 39 days ago | IN | 0 MON | 0.05584739 | ||||
| Add Liquidity ET... | 41274445 | 44 days ago | IN | 743.22536088 MON | 0.1037111 | ||||
| Add Liquidity ET... | 39548121 | 52 days ago | IN | 1 MON | 0.43884415 | ||||
| Add Liquidity ET... | 39547792 | 52 days ago | IN | 1 MON | 0.53544418 | ||||
| Add Liquidity ET... | 39546469 | 52 days ago | IN | 1 MON | 0.095778 | ||||
| Add Liquidity ET... | 39546449 | 52 days ago | IN | 1 MON | 0.45345395 | ||||
| Deposit Update F... | 39546321 | 52 days ago | IN | 1 MON | 0.00271046 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 50847338 | 3 secs ago | 2 wei | ||||
| 50847338 | 3 secs ago | 2 wei | ||||
| 50847313 | 13 secs ago | 2 wei | ||||
| 50847313 | 13 secs ago | 2 wei | ||||
| 50847307 | 15 secs ago | 2 wei | ||||
| 50847301 | 18 secs ago | 2 wei | ||||
| 50847291 | 22 secs ago | 2 wei | ||||
| 50847262 | 33 secs ago | 2 wei | ||||
| 50847175 | 1 min ago | 2 wei | ||||
| 50847135 | 1 min ago | 2 wei | ||||
| 50847071 | 1 min ago | 2 wei | ||||
| 50847071 | 1 min ago | 2 wei | ||||
| 50847058 | 1 min ago | 2 wei | ||||
| 50847058 | 1 min ago | 2 wei | ||||
| 50847054 | 1 min ago | 2 wei | ||||
| 50847050 | 1 min ago | 2 wei | ||||
| 50847050 | 1 min ago | 2 wei | ||||
| 50847046 | 2 mins ago | 2 wei | ||||
| 50847046 | 2 mins ago | 2 wei | ||||
| 50847043 | 2 mins ago | 2 wei | ||||
| 50847043 | 2 mins ago | 2 wei | ||||
| 50847038 | 2 mins ago | 2 wei | ||||
| 50847038 | 2 mins ago | 2 wei | ||||
| 50847033 | 2 mins ago | 2 wei | ||||
| 50847031 | 2 mins ago | 2 wei |
Loading...
Loading
Contract Name:
BrownFiV2Router
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
import './interfaces/IBrownFiV2Factory.sol';
import '@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol';
import './interfaces/IBrownFiV2Router.sol';
import './libraries/BrownFiV2Library.sol';
import './libraries/SafeMath.sol';
import './interfaces/IWETH.sol';
import './interfaces/IPyth.sol';
import './interfaces/IPriceOracle.sol';
contract BrownFiV2Router is IBrownFiV2Router {
using SafeMath for uint;
address public immutable override factory;
address public immutable override WETH;
address public immutable PYTH;
modifier ensure(uint deadline) {
require(deadline >= block.timestamp, 'BrownFiV2Router: EXPIRED');
_;
}
constructor(address _factory, address _WETH) {
factory = _factory;
WETH = _WETH;
PYTH = IPriceOracle(IBrownFiV2Factory(_factory).priceOracle()).pythContract();
}
receive() external payable {
assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
}
// Function to deposit ETH for price updates
function depositUpdateFeeETH() external payable {
// No additional logic needed, the ETH is stored in the contract's balance
}
function _universalAddLpTransfers(
address tokenA,
address tokenB,
uint amountA,
uint amountB,
address to
) internal returns (uint liquidity) {
address pair = BrownFiV2Library.pairFor(factory, tokenA, tokenB);
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
if(tokenB == WETH) {
IWETH(WETH).deposit{value: amountB}();
assert(IWETH(WETH).transfer(pair, amountB));
// refund dust eth, if any
if (msg.value > amountB) TransferHelper.safeTransferETH(msg.sender, msg.value - amountB);
} else {
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
}
liquidity = IBrownFiV2Pair(pair).mint(to);
}
function _updateTokenPrices(bytes memory updateData) internal {
IPyth pyth = IPyth(PYTH);
bytes[] memory decodedUpdateData = BrownFiV2Library.decodePriceFeedUpdateData(updateData);
if(decodedUpdateData.length > 0) {
uint updateFee = pyth.getUpdateFee(decodedUpdateData);
pyth.updatePriceFeeds{value: updateFee}(decodedUpdateData);
}
}
function _quoteAddLPAmounts(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin
) internal view returns(uint amountA, uint amountB) {
(uint priceA, uint priceB) = BrownFiV2Library.getPrices(factory, tokenA, tokenB);
uint amountBOptimal = BrownFiV2Library.quote(tokenA, tokenB, amountADesired, priceA, priceB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'BrownFiV2Router: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint amountAOptimal = BrownFiV2Library.quote(tokenB, tokenA, amountBDesired, priceB, priceA);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'BrownFiV2Router: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
// **** ADD LIQUIDITY ****
function _addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
bytes memory data
) internal virtual returns (uint amountA, uint amountB) {
(bytes32 priceFeedA, bytes32 priceFeedB, bytes memory updateData) = BrownFiV2Library.extractPriceFeedData(data);
// update token price
_updateTokenPrices(updateData);
// create the pair if it doesn't exist yet
if (IBrownFiV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
IBrownFiV2Factory(factory).createPair(tokenA, tokenB, priceFeedA, priceFeedB);
}
(amountA, amountB) = _quoteAddLPAmounts(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
}
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bytes calldata data
) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
(amountA, amountB) = _addLiquidity(
tokenA,
tokenB,
amountADesired,
amountBDesired,
amountAMin,
amountBMin,
data
);
liquidity = _universalAddLpTransfers(tokenA, tokenB, amountA, amountB, to);
}
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bytes calldata data
) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
(amountToken, amountETH) = _addLiquidity(
token,
WETH,
amountTokenDesired,
msg.value,
amountTokenMin,
amountETHMin,
data
);
liquidity = _universalAddLpTransfers(token, WETH, amountToken, amountETH, to);
}
// **** REMOVE LIQUIDITY ****
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
address pair = BrownFiV2Library.pairFor(factory, tokenA, tokenB);
IBrownFiV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(uint amount0, uint amount1) = IBrownFiV2Pair(pair).burn(to);
(address token0,) = BrownFiV2Library.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'BrownFiV2Router: INSUFFICIENT_A_AMOUNT');
require(amountB >= amountBMin, 'BrownFiV2Router: INSUFFICIENT_B_AMOUNT');
}
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
(amountToken, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, amountToken);
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountA, uint amountB) {
address pair = BrownFiV2Library.pairFor(factory, tokenA, tokenB);
uint value = approveMax ? type(uint256).max : liquidity;
IBrownFiV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountToken, uint amountETH) {
address pair = BrownFiV2Library.pairFor(factory, token, WETH);
uint value = approveMax ? type(uint256).max : liquidity;
IBrownFiV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}
// **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) public virtual override ensure(deadline) returns (uint amountETH) {
(, amountETH) = removeLiquidity(
token,
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external virtual override returns (uint amountETH) {
address pair = BrownFiV2Library.pairFor(factory, token, WETH);
uint value = approveMax ? type(uint256).max : liquidity;
IBrownFiV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
token, liquidity, amountTokenMin, amountETHMin, to, deadline
);
}
// **** SWAP ****
// requires the initial amount to have already been sent to the first pair
function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = BrownFiV2Library.sortTokens(input, output);
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? BrownFiV2Library.pairFor(factory, output, path[i + 2]) : _to;
IBrownFiV2Pair(BrownFiV2Library.pairFor(factory, input, output)).swap(
amount0Out, amount1Out, to, new bytes(0)
);
}
}
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
// update token price
_updateTokenPrices(updateData);
amounts = BrownFiV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'BrownFiV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, BrownFiV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
// update token price
_updateTokenPrices(updateData);
amounts = BrownFiV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'BrownFiV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, BrownFiV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, to);
}
function swapExactETHForTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'BrownFiV2Router: INVALID_PATH');
// update token price
_updateTokenPrices(updateData);
amounts = BrownFiV2Library.getAmountsOut(factory, msg.value, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'BrownFiV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(BrownFiV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
}
function swapTokensForExactETH(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
)
external
virtual
override
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[path.length - 1] == WETH, 'BrownFiV2Router: INVALID_PATH');
// update token price
_updateTokenPrices(updateData);
amounts = BrownFiV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'BrownFiV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, BrownFiV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapExactTokensForETH(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
)
external
virtual
override
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[path.length - 1] == WETH, 'BrownFiV2Router: INVALID_PATH');
// update token price
_updateTokenPrices(updateData);
amounts = BrownFiV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'BrownFiV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, BrownFiV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
function swapETHForExactTokens(
uint amountOut,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'BrownFiV2Router: INVALID_PATH');
// update token price
_updateTokenPrices(updateData);
amounts = BrownFiV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= msg.value, 'BrownFiV2Router: EXCESSIVE_INPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(BrownFiV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
// refund dust eth, if any
if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
}
// **** SWAP (supporting fee-on-transfer tokens) ****
// requires the initial amount to have already been sent to the first pair
function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = BrownFiV2Library.sortTokens(input, output);
IBrownFiV2Pair pair = IBrownFiV2Pair(BrownFiV2Library.pairFor(factory, input, output));
uint amountInput;
uint amountOutput;
{ // scope to avoid stack too deep errors
(uint reserveInput, uint reserveOutput, uint k, uint32 fee, uint64 lambda) = BrownFiV2Library.getReserves(factory, input, output);
(uint priceIn, uint priceOut) = BrownFiV2Library.getPrices(factory, input, output);
(priceIn, priceOut) = BrownFiV2Library.getSkewnessPrice(input, output, reserveInput, reserveOutput, priceIn, priceOut, lambda);
amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput);
amountOutput = BrownFiV2Library.getAmountOut(input, output, amountInput, reserveOutput, priceIn, priceOut, k, fee);
}
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
address to = i < path.length - 2 ? BrownFiV2Library.pairFor(factory, output, path[i + 2]) : _to;
pair.swap(amount0Out, amount1Out, to, new bytes(0));
}
}
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
) external virtual override ensure(deadline) {
// update token price
_updateTokenPrices(updateData);
TransferHelper.safeTransferFrom(
path[0], msg.sender, BrownFiV2Library.pairFor(factory, path[0], path[1]), amountIn
);
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'BrownFiV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
)
external
virtual
override
payable
ensure(deadline)
{
require(path[0] == WETH, 'BrownFiV2Router: INVALID_PATH');
// update token price
_updateTokenPrices(updateData);
uint amountIn = msg.value;
IWETH(WETH).deposit{value: amountIn}();
assert(IWETH(WETH).transfer(BrownFiV2Library.pairFor(factory, path[0], path[1]), amountIn));
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'BrownFiV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
)
external
virtual
override
ensure(deadline)
{
require(path[path.length - 1] == WETH, 'BrownFiV2Router: INVALID_PATH');
// update token price
_updateTokenPrices(updateData);
TransferHelper.safeTransferFrom(
path[0], msg.sender, BrownFiV2Library.pairFor(factory, path[0], path[1]), amountIn
);
_swapSupportingFeeOnTransferTokens(path, address(this));
uint amountOut = IERC20(WETH).balanceOf(address(this));
require(amountOut >= amountOutMin, 'BrownFiV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).withdraw(amountOut);
TransferHelper.safeTransferETH(to, amountOut);
}
// **** LIBRARY FUNCTIONS ****
function quote(address tokenA, address tokenB, uint amountA, uint priceA, uint priceB) public pure virtual override returns (uint amountB) {
return BrownFiV2Library.quote(tokenA, tokenB, amountA, priceA, priceB);
}
function getAmountOut(address tokenIn, address tokenOut, uint amountIn, uint reserveOut, uint priceIn, uint priceOut, uint k, uint32 fee)
public
view
virtual
override
returns (uint amountOut)
{
(uint reserveInput, uint reserveOutput, , , uint64 lambda) = BrownFiV2Library.getReserves(factory, tokenIn, tokenOut);
(priceIn, priceOut) = BrownFiV2Library.getSkewnessPrice(tokenIn, tokenOut, reserveInput, reserveOutput, priceIn, priceOut, lambda);
return BrownFiV2Library.getAmountOut(tokenIn, tokenOut, amountIn, reserveOut, priceIn, priceOut, k, fee);
}
function getAmountIn(address tokenIn, address tokenOut, uint amountOut, uint reserveOut, uint priceIn, uint priceOut, uint k, uint32 fee)
public
view
virtual
override
returns (uint amountIn)
{
(uint reserveInput, uint reserveOutput, , , uint64 lambda) = BrownFiV2Library.getReserves(factory, tokenIn, tokenOut);
(priceIn, priceOut) = BrownFiV2Library.getSkewnessPrice(tokenIn, tokenOut, reserveInput, reserveOutput, priceIn, priceOut, lambda);
return BrownFiV2Library.getAmountIn(tokenIn, tokenOut, amountOut, reserveOut, priceIn, priceOut, k, fee);
}
function getAmountsOut(uint amountIn, address[] calldata path, bytes calldata updateData)
external
virtual
override
returns (uint[] memory amounts)
{
// update token price
_updateTokenPrices(updateData);
return BrownFiV2Library.getAmountsOut(factory, amountIn, path);
}
function getAmountsIn(uint amountOut, address[] calldata path, bytes calldata updateData)
external
virtual
override
returns (uint[] memory amounts)
{
// update token price
_updateTokenPrices(updateData);
return BrownFiV2Library.getAmountsIn(factory, amountOut, path);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `sender` to `recipient`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function mulDiv(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2**256 + prod0
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(a, b, not(0))
prod0 := mul(a, b)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
require(denominator > 0);
assembly {
result := div(prod0, denominator)
}
return result;
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
uint256 remainder;
assembly {
remainder := mulmod(a, b, denominator)
}
// Subtract 256 bit number from 512 bit number
assembly {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
uint256 twos = (0 - denominator) & denominator;
// Divide denominator by power of two
assembly {
denominator := div(denominator, twos)
}
// Divide [prod1 prod0] by the factors of two
assembly {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
// Invert denominator mod 2**256
// Now that denominator is an odd number, it has an inverse
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // inverse mod 2**256
// Because the division is now exact we can divide by multiplying
// with the modular inverse of denominator. This will give us the
// correct result modulo 2**256. Since the precoditions guarantee
// that the outcome is less than 2**256, this is the final result.
// We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inv;
return result;
}
}
/// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
function mulDivRoundingUp(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
result = mulDiv(a, b, denominator);
if (mulmod(a, b, denominator) > 0) {
require(result < type(uint256).max);
result++;
}
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.0;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
library TransferHelper {
/// @notice Transfers tokens from the targeted address to the given destination
/// @notice Errors with 'STF' if transfer fails
/// @param token The contract address of the token to be transferred
/// @param from The originating address from which the tokens will be transferred
/// @param to The destination address of the transfer
/// @param value The amount to be transferred
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)
);
require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');
}
/// @notice Transfers tokens from msg.sender to a recipient
/// @dev Errors with ST if transfer fails
/// @param token The contract address of the token which will be transferred
/// @param to The recipient of the transfer
/// @param value The value of the transfer
function safeTransfer(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');
}
/// @notice Approves the stipulated contract to spend the given allowance in the given token
/// @dev Errors with 'SA' if transfer fails
/// @param token The contract address of the token to be approved
/// @param to The target of the approval
/// @param value The amount of the given token the target will be allowed to spend
function safeApprove(
address token,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'SA');
}
/// @notice Transfers ETH to the recipient address
/// @dev Fails with `STE`
/// @param to The destination of the transfer
/// @param value The value to be transferred
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'STE');
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface IBrownFiV2Callee {
function brownFiV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface IBrownFiV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint totalPair);
event PauseStateChanged(bool paused);
function priceOracle() external view returns (address);
function feeTo() external view returns (address);
function priceOf(address token, uint256 priceAge) external view returns(uint256);
function minPriceAge() external view returns (uint);
function priceFeedIds(address token) external view returns (bytes32);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB, bytes32 priceFeedA, bytes32 priceFeedB) external returns (address pair);
function setPriceOracle(address newOracle) external;
function setFeeTo(address) external;
function setOracleOf(address token, bytes32 priceFeedId) external;
function setMinPriceAge(uint age) external;
function setPaused(bool paused) external;
function isPaused() external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface IBrownFiV2Migrator {
function migrate(address token, uint amountTokenMin, uint amountETHMin, address to, uint deadline) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface IBrownFiV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1, uint price0, uint price1, address indexed to);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
uint price0,
uint price1,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function k() external view returns (uint);
function lambda() external view returns (uint64);
function fee() external view returns (uint32);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function setK(uint _k) external;
function setFee(uint32 _fee) external;
function setLambda(uint64 _lambda) external;
function setProtocolFee(uint32 _protocolFee) external;
function initialize(address, address) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.6.2;
interface IBrownFiV2Router {
function factory() external view returns (address);
function WETH() external view returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bytes calldata data
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bytes calldata data
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline, bytes calldata updateData)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline, bytes calldata updateData)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline, bytes calldata updateData)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline, bytes calldata updateData)
external
payable
returns (uint[] memory amounts);
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline,
bytes calldata updateData
) external;
function quote(address tokenA, address tokenB, uint amountA, uint priceA, uint priceB) external pure returns (uint amountB);
function getAmountOut(address tokenIn, address tokenOut, uint amountIn, uint reserveOut, uint priceIn, uint priceOut, uint k, uint32 fee) external view returns (uint amountOut);
function getAmountIn(address tokenIn, address tokenOut, uint amountOut, uint reserveOut, uint priceIn, uint priceOut, uint k, uint32 fee) external view returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path, bytes calldata updateData) external returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path, bytes calldata updateData) external returns (uint[] memory amounts);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
interface IPriceOracle {
function pythContract() external view returns (address);
// Get price in Q64 format with a maximum age constraint
function getPrice(bytes32 feedId, uint priceAge) external view returns (uint price);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
interface IPyth {
/// @notice Returns the price of a price feed without any sanity checks.
/// @dev This function returns the most recent price update in this contract without any recency checks.
/// This function is unsafe as the returned price update may be arbitrarily far in the past.
///
/// Users of this function should check the `publishTime` in the price to ensure that the returned price is
/// sufficiently recent for their application. If you are considering using this function, it may be
/// safer / easier to use either `getPrice` or `getPriceNoOlderThan`.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceUnsafe(
bytes32 id
) external view returns (int64, uint64, int32, uint);
/// @notice Returns the price that is no older than `age` seconds of the current time.
/// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in
/// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently
/// recently.
/// @return price - please read the documentation of PythStructs.Price to understand how to use this safely.
function getPriceNoOlderThan(
bytes32 id,
uint age
) external view returns (int64, uint64, int32, uint);
/// @notice Returns the required fee to update an array of price updates.
/// @param updateData Array of price update data.
/// @return feeAmount The required fee in Wei.
function getUpdateFee(
bytes[] calldata updateData
) external view returns (uint feeAmount);
/// @notice Update price feeds with given update messages.
/// This method requires the caller to pay a fee in wei; the required fee can be computed by calling
/// `getUpdateFee` with the length of the `updateData` array.
/// Prices will be updated if they are more recent than the current stored prices.
/// The call will succeed even if the update is not the most recent.
/// @dev Reverts if the transferred fee is not sufficient or the updateData is invalid.
/// @param updateData Array of price update data.
function updatePriceFeeds(bytes[] calldata updateData) external payable;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function withdraw(uint) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.5.0;
import '../interfaces/IBrownFiV2Pair.sol';
import '../interfaces/IBrownFiV2Factory.sol';
import './SafeMath.sol';
import '@uniswap/v3-core/contracts/libraries/FullMath.sol';
library BrownFiV2Library {
using SafeMath for uint;
uint256 constant Q64 = 1 << 64;
uint256 constant PRECISION = 10**8;
uint256 constant DECIMALS = 18;
// keccak256(abi.encodePacked("price.feed.suffix"));
bytes32 constant PRICE_FEED_SUFFIX = 0x6c5de8f69b548efcdfceb3079391bd0025f809fcc7a31af0d13c34c032fb078e;
function decodePriceFeedUpdateData(bytes memory data) internal pure returns (bytes[] memory updateData) {
if(data.length > 0) (updateData) = abi.decode(data, (bytes[]));
}
function extractPriceFeedData(bytes memory data) internal pure returns (bytes32 priceFeedA, bytes32 priceFeedB, bytes memory updateData) {
bytes32 suffix;
assembly {
// last 32 bytes
suffix := mload(add(data, mload(data)))
}
if(data.length >= 96 && suffix == PRICE_FEED_SUFFIX) {
assembly {
priceFeedA := mload(add(data, sub(mload(data), 64))) // offset 64 bytes (priceFeedB + suffix)
priceFeedB := mload(add(data, sub(mload(data), 32))) // offset 32 bytes (suffix)
}
if(data.length > 96) {
assembly {
let newLen := sub(mload(data), 96)
updateData := mload(0x40) // Get free memory pointer
mstore(0x40, add(updateData, add(32, newLen))) // Update free memory pointer
mstore(updateData, newLen) // Store length of result
// Copy data (skip first 32 bytes of length, copy len bytes)
let src := add(data, 32)
let dest := add(updateData, 32)
for { let i := 0 } lt(i, newLen) { i := add(i, 32) } {
mstore(add(dest, i), mload(add(src, i)))
}
}
}
} else {
updateData = data;
}
}
/**
* @dev convert raw amount to default decimals amount
*/
function parseRawToDefaultDecimals(address token, uint amount) internal pure returns (uint formattedAmount) {
uint8 tokenDecimals = IBrownFiV2Pair(token).decimals();
formattedAmount = tokenDecimals > DECIMALS ?
amount / 10**uint(tokenDecimals - DECIMALS) : amount * 10**uint(DECIMALS - tokenDecimals);
}
/**
* @dev convert raw amount to default decimals amount
*/
function parseDefaultDecimalsToRaw(address token, uint amount) internal pure returns (uint formattedAmount) {
uint8 tokenDecimals = IBrownFiV2Pair(token).decimals();
formattedAmount = tokenDecimals > DECIMALS ?
amount * 10**uint(tokenDecimals - DECIMALS) : amount / 10**uint(DECIMALS - tokenDecimals);
}
// returns sorted token addresses, used to handle return values from pairs sorted in this order
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
require(tokenA != tokenB, 'BrownFiV2Library: IDENTICAL_ADDRESSES');
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), 'BrownFiV2Library: ZERO_ADDRESS');
}
// calculates the CREATE2 address for a pair without making any external calls
function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(uint160(
uint256(keccak256(abi.encodePacked(
bytes1(0xff),
factory,
keccak256(abi.encodePacked(token0, token1)),
hex'ba3704b080a922b1d5cc299de67778312cff58ab8b1704742d9b0b19c359e228' // init code hash
)))));
}
// fetches and sorts the prices of tokens in a pair
function getPrices(address factory, address tokenA, address tokenB) internal view returns (uint priceA, uint priceB) {
(address _factory, address _tokenA, address _tokenB) = (factory, tokenA, tokenB);
uint256 priceAge = IBrownFiV2Factory(factory).minPriceAge();
priceA = IBrownFiV2Factory(_factory).priceOf(_tokenA, priceAge);
priceB = IBrownFiV2Factory(_factory).priceOf(_tokenB, priceAge);
}
function getSkewnessPrice(address tokenA, address tokenB, uint reserveA, uint reserveB, uint priceA, uint priceB, uint lambda) internal pure returns (uint sPriceA, uint sPriceB) {
if (lambda == 0) {
return (priceA, priceB); // no skewness
}
uint _rA = parseRawToDefaultDecimals(tokenA, reserveA);
uint _rB = parseRawToDefaultDecimals(tokenB, reserveB);
uint reserveAPrice = _rA * priceA;
uint reserveBPrice = _rB * priceB;
uint reservePriceDiff = reserveAPrice >= reserveBPrice ?
reserveAPrice - reserveBPrice :
reserveBPrice - reserveAPrice;
uint reservePriceSum = reserveAPrice + reserveBPrice;
uint s = FullMath.mulDiv(reservePriceDiff, lambda, reservePriceSum);
uint q64PlusS = Q64 + s;
uint q64MinusS = Q64 - s;
if (reserveAPrice >= reserveBPrice) {
return (
FullMath.mulDiv(priceA, q64MinusS, Q64),
FullMath.mulDiv(priceB, q64PlusS, Q64)
);
} else {
return (
FullMath.mulDiv(priceA, q64PlusS, Q64),
FullMath.mulDiv(priceB, q64MinusS, Q64)
);
}
}
// fetches and sorts the reserves for a pair
function getReserves(address factory, address tokenA, address tokenB)
internal
view
returns (uint reserveA, uint reserveB, uint k, uint32 fee, uint64 lambda)
{
(address _factory, address _tokenA, address _tokenB) = (factory, tokenA, tokenB);
(address token0,) = sortTokens(_tokenA, _tokenB);
(uint reserve0, uint reserve1,) = IBrownFiV2Pair(pairFor(_factory, _tokenA, _tokenB)).getReserves();
k = IBrownFiV2Pair(pairFor(_factory, _tokenA, _tokenB)).k();
fee = IBrownFiV2Pair(pairFor(_factory, _tokenA, _tokenB)).fee();
lambda = IBrownFiV2Pair(pairFor(_factory, _tokenA, _tokenB)).lambda();
(reserveA, reserveB) = _tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
// given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
function quote(address tokenA, address tokenB, uint amountA, uint priceA, uint priceB) internal pure returns (uint amountB) {
require(amountA > 0, 'BrownFiV2Library: INSUFFICIENT_AMOUNT');
// parse raw to default decimals
uint parsedAmountA = parseRawToDefaultDecimals(tokenA, amountA);
amountB = FullMath.mulDiv(parsedAmountA, priceA, priceB);
// parse default decimals to raw
amountB = parseDefaultDecimalsToRaw(tokenB, amountB);
}
// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
function getAmountOut(
address tokenIn,
address tokenOut,
uint amountIn,
uint reserveOut,
uint priceIn,
uint priceOut,
uint k,
uint32 fee
) internal pure returns (uint amountOut) {
require(amountIn > 0, "BrownFiV2Library: INSUFFICIENT_INPUT_AMOUNT");
require(reserveOut > 0, "BrownFiV2Library: INSUFFICIENT_LIQUIDITY");
// parse raw to default decimals
uint parsedAmountIn = parseRawToDefaultDecimals(tokenIn, amountIn);
uint parsedReserveOut = parseRawToDefaultDecimals(tokenOut, reserveOut);
uint _amountIn = FullMath.mulDiv(parsedAmountIn, PRECISION, PRECISION + fee);
if (k == 2 * Q64) {
amountOut = FullMath.mulDiv(parsedReserveOut * _amountIn, priceIn, priceOut * parsedReserveOut + _amountIn * priceIn);
} else {
uint leftNumerator = computeLeftNumerator(_amountIn, priceIn, priceOut, parsedReserveOut);
uint leftSqrt = computeLeftSqrt(_amountIn, priceIn, priceOut, parsedReserveOut);
uint rightSqrt = computeRightSqrt(_amountIn, priceIn, priceOut, parsedReserveOut, k);
uint denominator = FullMath.mulDiv(priceOut, uint(2).mul(Q64).sub(k), Q64);
amountOut = (leftNumerator - Q64.mul(SafeMath.sqrt(leftSqrt + rightSqrt))) / denominator;
}
// parse default decimals to raw
amountOut = parseDefaultDecimalsToRaw(tokenOut, amountOut);
// re-verify amount in
getAmountIn(tokenIn, tokenOut, amountOut, parsedReserveOut, priceIn, priceOut, k, fee);
}
// Helper function of getAmountOut
function computeLeftNumerator(
uint amountIn,
uint priceIn,
uint priceOut,
uint reserveOut
) private pure returns (uint) {
return priceOut.mul(reserveOut).add(
priceIn.mul(amountIn)
);
}
// Helper function of getAmountOut
function computeLeftSqrt(
uint amountIn,
uint priceIn,
uint priceOut,
uint reserveOut
) private pure returns (uint) {
uint temp = FullMath.mulDiv(amountIn, priceIn, Q64) > FullMath.mulDiv(reserveOut, priceOut, Q64) ?
FullMath.mulDiv(amountIn, priceIn, Q64).sub(FullMath.mulDiv(reserveOut, priceOut, Q64)) :
FullMath.mulDiv(reserveOut, priceOut, Q64).sub(FullMath.mulDiv(amountIn, priceIn, Q64));
return temp * temp;
}
// Helper function of getAmountOut
function computeRightSqrt(
uint amountIn,
uint priceIn,
uint priceOut,
uint reserveOut,
uint k
) private pure returns (uint) {
return FullMath.mulDiv(priceIn.mul(priceOut), k, Q64 * Q64).mul(
FullMath.mulDiv(reserveOut.mul(amountIn), 2, Q64)
);
}
// given an output amount of an asset and pair reserves, returns a required input amount of the other asset
function getAmountIn(
address tokenIn,
address tokenOut,
uint amountOut,
uint reserveOut,
uint priceIn,
uint priceOut,
uint k,
uint32 fee
) internal pure returns (uint amountIn) {
require(amountOut > 0, 'BrownFiV2Library: INSUFFICIENT_OUTPUT_AMOUNT');
require(reserveOut > 0, 'BrownFiV2Library: INSUFFICIENT_LIQUIDITY');
require(amountOut.mul(10) <= reserveOut.mul(8), 'BrownFiV2Library: MAX_80_PERCENT_OF_RESERVE');
// parse to default decimals
uint parsedAmountOut = parseRawToDefaultDecimals(tokenOut, amountOut);
uint parsedReserveOut = parseRawToDefaultDecimals(tokenOut, reserveOut);
uint256 priceImpact = FullMath.mulDiv(
uint(k).mul(Q64),
parsedAmountOut,
Q64.mul(parsedReserveOut.sub(parsedAmountOut))
);
amountIn = FullMath.mulDiv(
parsedAmountOut,
FullMath.mulDiv(priceOut, priceImpact.add(Q64.mul(2)), priceIn),
Q64.mul(2)
);
amountIn = FullMath.mulDiv(amountIn , uint(PRECISION).add(fee), PRECISION);
// parse default decimals to raw
amountIn = parseDefaultDecimalsToRaw(tokenIn, amountIn);
}
// performs chained getAmountOut calculations on any number of pairs
function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'BrownFiV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[0] = amountIn;
for (uint i; i < path.length - 1; i++) {
(uint reserveIn, uint reserveOut, uint k, uint32 fee, uint64 lambda) = getReserves(factory, path[i], path[i + 1]);
(uint priceIn, uint priceOut) = getPrices(factory, path[i], path[i + 1]);
(priceIn, priceOut) = getSkewnessPrice(path[i], path[i + 1], reserveIn, reserveOut, priceIn, priceOut, lambda);
amounts[i + 1] = getAmountOut(path[i], path[i + 1], amounts[i], reserveOut, priceIn, priceOut, k, fee);
}
}
// performs chained getAmountIn calculations on any number of pairs
function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, 'BrownFiV2Library: INVALID_PATH');
amounts = new uint[](path.length);
amounts[amounts.length - 1] = amountOut;
for (uint i = path.length - 1; i > 0; i--) {
(uint reserveIn, uint reserveOut, uint k, uint32 fee, uint64 lambda) = getReserves(factory, path[i - 1], path[i]);
(uint priceIn, uint priceOut) = getPrices(factory, path[i - 1], path[i]);
(priceIn, priceOut) = getSkewnessPrice(path[i - 1], path[i], reserveIn, reserveOut, priceIn, priceOut, lambda);
amounts[i - 1] = getAmountIn(path[i - 1], path[i], amounts[i], reserveOut, priceIn, priceOut, k, fee);
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
library SafeMath {
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, 'ds-math-add-overflow');
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x, 'ds-math-sub-underflow');
}
function mul(uint x, uint y) internal pure returns (uint z) {
require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
}
// credit for this implementation goes to
// https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol
function sqrt (uint256 x) internal pure returns (uint128) {
if (x == 0) return 0;
else {
uint256 xx = x;
uint256 r = 1;
if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; }
if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; }
if (xx >= 0x100000000) { xx >>= 32; r <<= 16; }
if (xx >= 0x10000) { xx >>= 16; r <<= 8; }
if (xx >= 0x100) { xx >>= 8; r <<= 4; }
if (xx >= 0x10) { xx >>= 4; r <<= 2; }
if (xx >= 0x4) { r <<= 1; }
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1;
r = (r + x / r) >> 1; // Seven iterations should be enough
uint256 r1 = x / r;
return uint128 (r < r1 ? r : r1);
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import '../libraries/SafeMath.sol';
contract ERC20 {
using SafeMath for uint;
string public constant name = 'Test Token';
string public constant symbol = 'TT';
uint8 public decimals;
uint public totalSupply;
mapping(address => uint) public balanceOf;
mapping(address => mapping(address => uint)) public allowance;
bytes32 public DOMAIN_SEPARATOR;
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint) public nonces;
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
constructor(uint _totalSupply, uint8 _decimals) {
uint chainId;
assembly {
chainId := chainid()
}
DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
keccak256(bytes(name)),
keccak256(bytes('1')),
chainId,
address(this)
)
);
decimals = _decimals;
_mint(msg.sender, _totalSupply);
}
function _mint(address to, uint value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(address owner, address spender, uint value) private {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(address from, address to, uint value) private {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint value) external returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function transfer(address to, uint value) external returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(address from, address to, uint value) external returns (bool) {
if (allowance[from][msg.sender] != type(uint).max) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
require(deadline >= block.timestamp, 'EXPIRED');
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'INVALID_SIGNATURE');
_approve(owner, spender, value);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.5.0;
import "../interfaces/IPyth.sol";
contract MockPyth is IPyth {
// default
// int32 _expo = -8;
// int64 _price = 10e8;
struct Price {
// Price
int64 price;
// Confidence interval around the price
uint64 conf;
// Price exponent
int32 expo;
// Unix timestamp describing when the price was published
uint publishTime;
}
mapping(bytes32 => Price) _prices;
function setPrice(bytes32 id, int64 _price) external {
_prices[id].price = _price;
_prices[id].expo = -8;
_prices[id].publishTime = block.timestamp;
}
function getPriceUnsafe(
bytes32 id
) override public view returns (int64, uint64, int32, uint) {
Price memory price = _prices[id];
return (price.price, price.conf, price.expo, price.publishTime);
}
function getPriceNoOlderThan(
bytes32 id,
uint age
) override public view returns (int64, uint64, int32, uint) {
require(_prices[id].publishTime + age >= block.timestamp, "StalePrice");
return getPriceUnsafe(id);
}
function getUpdateFee(
bytes[] memory updateData
) public pure override returns (uint feeAmount) {
feeAmount = updateData.length;
}
function updatePriceFeeds(bytes[] memory updateData) override public payable {
uint requiredFee = getUpdateFee(updateData);
if (msg.value < requiredFee) revert("InsufficientFee");
for (uint i; i < updateData.length; i++) {
(bytes32 id, int64 price, uint64 conf, int32 expo, uint publishTime) = abi.decode(
updateData[i],
(bytes32, int64, uint64, int32, uint256)
);
// uint lastPublishTime = _prices[id].publishTime;
// if (lastPublishTime < publishTime) {
_prices[id].price = price;
_prices[id].conf = conf;
_prices[id].expo = expo;
_prices[id].publishTime = publishTime;
// emit PriceFeedUpdate(
// priceFeed.id,
// uint64(lastPublishTime),
// priceFeed.price.price,
// priceFeed.price.conf
// );
// }
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import '../interfaces/IBrownFiV2Router.sol';
contract RouterEventEmitter {
event Amounts(uint[] amounts);
receive() external payable {}
function swapExactTokensForTokens(
address router,
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external {
(bool success, bytes memory returnData) = router.delegatecall(abi.encodeWithSelector(
IBrownFiV2Router(router).swapExactTokensForTokens.selector, amountIn, amountOutMin, path, to, deadline
));
assert(success);
emit Amounts(abi.decode(returnData, (uint[])));
}
function swapTokensForExactTokens(
address router,
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external {
(bool success, bytes memory returnData) = router.delegatecall(abi.encodeWithSelector(
IBrownFiV2Router(router).swapTokensForExactTokens.selector, amountOut, amountInMax, path, to, deadline
));
assert(success);
emit Amounts(abi.decode(returnData, (uint[])));
}
function swapExactETHForTokens(
address router,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable {
(bool success, bytes memory returnData) = router.delegatecall(abi.encodeWithSelector(
IBrownFiV2Router(router).swapExactETHForTokens.selector, amountOutMin, path, to, deadline
));
assert(success);
emit Amounts(abi.decode(returnData, (uint[])));
}
function swapTokensForExactETH(
address router,
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external {
(bool success, bytes memory returnData) = router.delegatecall(abi.encodeWithSelector(
IBrownFiV2Router(router).swapTokensForExactETH.selector, amountOut, amountInMax, path, to, deadline
));
assert(success);
emit Amounts(abi.decode(returnData, (uint[])));
}
function swapExactTokensForETH(
address router,
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external {
(bool success, bytes memory returnData) = router.delegatecall(abi.encodeWithSelector(
IBrownFiV2Router(router).swapExactTokensForETH.selector, amountIn, amountOutMin, path, to, deadline
));
assert(success);
emit Amounts(abi.decode(returnData, (uint[])));
}
function swapETHForExactTokens(
address router,
uint amountOut,
address[] calldata path,
address to,
uint deadline
) external payable {
(bool success, bytes memory returnData) = router.delegatecall(abi.encodeWithSelector(
IBrownFiV2Router(router).swapETHForExactTokens.selector, amountOut, path, to, deadline
));
assert(success);
emit Amounts(abi.decode(returnData, (uint[])));
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
contract TestERC20 is ERC20 {
uint8 private immutable DECIMALS;
constructor(
string memory name,
string memory symbol,
uint256 initialSupply,
uint8 _decimals
)
ERC20(name, symbol)
{
DECIMALS = _decimals;
_mint(msg.sender, initialSupply * 10 ** DECIMALS);
}
function decimals() public view virtual override returns (uint8) {
return DECIMALS;
}
function mint(address to, uint256 amount) external {
_mint(to, amount);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.28;
contract WETH9 {
string public name = "Wrapped Ether";
string public symbol = "WETH";
uint8 public decimals = 18;
event Approval(address indexed src, address indexed guy, uint256 wad);
event Transfer(address indexed src, address indexed dst, uint256 wad);
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
receive() external payable {
deposit();
}
function deposit() public payable {
balanceOf[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint256 wad) public {
require(balanceOf[msg.sender] >= wad, "");
balanceOf[msg.sender] -= wad;
payable(msg.sender).transfer(wad);
emit Withdrawal(msg.sender, wad);
}
function totalSupply() public view returns (uint256) {
return address(this).balance;
}
function approve(address guy, uint256 wad) public returns (bool) {
allowance[msg.sender][guy] = wad;
emit Approval(msg.sender, guy, wad);
return true;
}
function transfer(address dst, uint256 wad) public returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(
address src,
address dst,
uint256 wad
) public returns (bool) {
require(balanceOf[src] >= wad, "");
if (
src != msg.sender && allowance[src][msg.sender] != type(uint256).max
) {
require(allowance[src][msg.sender] >= wad, "");
allowance[src][msg.sender] -= wad;
}
balanceOf[src] -= wad;
balanceOf[dst] += wad;
emit Transfer(src, dst, wad);
return true;
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"PYTH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"depositUpdateFeeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"},{"internalType":"uint256","name":"priceIn","type":"uint256"},{"internalType":"uint256","name":"priceOut","type":"uint256"},{"internalType":"uint256","name":"k","type":"uint256"},{"internalType":"uint32","name":"fee","type":"uint32"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"},{"internalType":"uint256","name":"priceIn","type":"uint256"},{"internalType":"uint256","name":"priceOut","type":"uint256"},{"internalType":"uint256","name":"k","type":"uint256"},{"internalType":"uint32","name":"fee","type":"uint32"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"priceA","type":"uint256"},{"internalType":"uint256","name":"priceB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"updateData","type":"bytes"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60e060405234801561001057600080fd5b50604051615ab0380380615ab083398101604081905261002f91610135565b6001600160a01b03808316608081905290821660a05260408051632630c12f60e01b81529051632630c12f916004808201926020929091908290030181865afa158015610080573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100a49190610168565b6001600160a01b0316638a32ada06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101059190610168565b6001600160a01b031660c0525061018a9050565b80516001600160a01b038116811461013057600080fd5b919050565b6000806040838503121561014857600080fd5b61015183610119565b915061015f60208401610119565b90509250929050565b60006020828403121561017a57600080fd5b61018382610119565b9392505050565b60805160a05160c051615768610348600039600081816102e301526128e4015260008181610195015281816103ef0152818161058c015281816105db015281816107510152818161080d0152818161088101528181610de901528181611255015281816114080152818161165c01528181611714015281816117ba01528181611b8e01528181611c7a01528181611dcb01528181611e590152818161201f01528181612141015281816121ec0152818161227f015281816123dc0152818161246a015281816125d40152818161263e01528181613ec601528181613eff0152613f940152600081816104830152818161065f015281816108b301528181610bbd01528181610c8301528181610d5401528181610dc701528181610f1301528181611045015281816111cd0152818161131001528181611522015281816115cb015281816118750152818161193501528181611b6c01528181611d3401528181611e8b015281816123390152818161249c01528181612a6401528181612a9c01528181612ad401528181612bc50152818161316e015281816131a101528181613d4801528181613df801528181613e90015261482d01526157686000f3fe6080604052600436106101855760003560e01c8063988f8363116100d1578063c45a01551161008a578063e76c597511610064578063e76c597514610500578063ed16c0b414610513578063ed3b11ce14610533578063f515c1041461054657600080fd5b8063c45a015514610471578063d4141257146104a5578063ded9382a146104e057600080fd5b8063988f83631461039d578063a07ee849146103bd578063ad5c4648146103dd578063af2979eb14610411578063b132b5e114610431578063baa2abde1461045157600080fd5b80635e1d693e1161013e5780637a253b58116101185780637a253b581461031d5780637fe186501461033d5780638af139371461035d5780638d77c6f01461037d57600080fd5b80635e1d693e146102b157806367e406d5146102d157806371e0b951146101c257600080fd5b806302751cec146101c95780632195995c14610203578063274b96a514610223578063323de4ee1461023657806334b5731a146102635780635b0d59841461029157600080fd5b366101c457336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101c2576101c26148ef565b005b600080fd5b3480156101d557600080fd5b506101e96101e436600461491d565b610559565b604080519283526020830191909152015b60405180910390f35b34801561020f57600080fd5b506101e961021e366004614998565b610655565b6101c2610231366004614ace565b61072e565b34801561024257600080fd5b50610256610251366004614b67565b610b56565b6040516101fa9190614c09565b34801561026f57600080fd5b5061028361027e366004614c5e565b610d49565b6040519081526020016101fa565b34801561029d57600080fd5b506102836102ac366004614cda565b610dbf565b3480156102bd57600080fd5b506102566102cc366004614b67565b610eac565b3480156102dd57600080fd5b506103057f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101fa565b34801561032957600080fd5b506101c2610338366004614b67565b610fb4565b34801561034957600080fd5b50610283610358366004614c5e565b6111c2565b34801561036957600080fd5b50610256610378366004614b67565b611228565b34801561038957600080fd5b50610256610398366004614d75565b6114dc565b3480156103a957600080fd5b506102566103b8366004614d75565b611585565b3480156103c957600080fd5b506102836103d8366004614df2565b611624565b3480156103e957600080fd5b506103057f000000000000000000000000000000000000000000000000000000000000000081565b34801561041d57600080fd5b5061028361042c36600461491d565b611633565b34801561043d57600080fd5b5061025661044c366004614b67565b61178d565b34801561045d57600080fd5b506101e961046c366004614e43565b61190a565b34801561047d57600080fd5b506103057f000000000000000000000000000000000000000000000000000000000000000081565b3480156104b157600080fd5b506104c56104c0366004614eb6565b611ad2565b604080519384526020840192909252908201526060016101fa565b3480156104ec57600080fd5b506101e96104fb366004614cda565b611b62565b61025661050e366004614ace565b611c55565b34801561051f57600080fd5b506101c261052e366004614b67565b611ff4565b610256610541366004614ace565b61225a565b6104c5610554366004614f65565b6125a8565b60008082428110156105865760405162461bcd60e51b815260040161057d90614fd3565b60405180910390fd5b6105b5897f00000000000000000000000000000000000000000000000000000000000000008a8a8a308a61190a565b90935091506105c5898685612676565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561062757600080fd5b505af115801561063b573d6000803e3d6000fd5b505050506106498583612776565b50965096945050505050565b60008060006106857f00000000000000000000000000000000000000000000000000000000000000008f8f61281e565b9050600087610694578c610698565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf906106d3903390309086908f908e908e908e9060040161500a565b600060405180830381600087803b1580156106ed57600080fd5b505af1158015610701573d6000803e3d6000fd5b505050506107148f8f8f8f8f8f8f61190a565b809450819550505050509b509b9950505050505050505050565b824281101561074f5760405162461bcd60e51b815260040161057d90614fd3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168787600081811061078c5761078c61504b565b90506020020160208101906107a19190615061565b6001600160a01b0316146107c75760405162461bcd60e51b815260040161057d9061507e565b61080683838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b60003490507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561086657600080fd5b505af115801561087a573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6109277f00000000000000000000000000000000000000000000000000000000000000008b8b60008181106108e5576108e561504b565b90506020020160208101906108fa9190615061565b8c8c600181811061090d5761090d61504b565b90506020020160208101906109229190615061565b61281e565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015610974573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099891906150b5565b6109a4576109a46148ef565b600088886109b36001826150e8565b8181106109c2576109c261504b565b90506020020160208101906109d79190615061565b6040516370a0823160e01b81526001600160a01b03898116600483015291909116906370a0823190602401602060405180830381865afa158015610a1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4391906150fb565b9050610a838989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b92506129ef915050565b89610b2c828b8b610a956001826150e8565b818110610aa457610aa461504b565b9050602002016020810190610ab99190615061565b6040516370a0823160e01b81526001600160a01b038c8116600483015291909116906370a08231906024015b602060405180830381865afa158015610b02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2691906150fb565b90612c97565b1015610b4a5760405162461bcd60e51b815260040161057d90615114565b50505050505050505050565b60608342811015610b795760405162461bcd60e51b815260040161057d90614fd3565b610bb884848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b610c167f00000000000000000000000000000000000000000000000000000000000000008b8a8a80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612cf392505050565b91508882600081518110610c2c57610c2c61504b565b60200260200101511115610c525760405162461bcd60e51b815260040161057d9061515f565b610cfd88886000818110610c6857610c6861504b565b9050602002016020810190610c7d9190615061565b33610cdd7f00000000000000000000000000000000000000000000000000000000000000008c8c6000818110610cb557610cb561504b565b9050602002016020810190610cca9190615061565b8d8d600181811061090d5761090d61504b565b85600081518110610cf057610cf061504b565b6020026020010151612f81565b610d3c828989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b925061308b915050565b5098975050505050505050565b600080600080610d7a7f00000000000000000000000000000000000000000000000000000000000000008d8d61326f565b9450505092509250610d9a8c8c85858c8c876001600160401b0316613492565b9098509650610daf8c8c8c8c8c8c8c8c6135a6565b9c9b505050505050505050505050565b600080610e0d7f00000000000000000000000000000000000000000000000000000000000000008d7f000000000000000000000000000000000000000000000000000000000000000061281e565b9050600086610e1c578b610e20565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90610e5b903390309086908e908d908d908d9060040161500a565b600060405180830381600087803b158015610e7557600080fd5b505af1158015610e89573d6000803e3d6000fd5b50505050610e9b8d8d8d8d8d8d611633565b9d9c50505050505050505050505050565b60608342811015610ecf5760405162461bcd60e51b815260040161057d90614fd3565b610f0e84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b610f6c7f00000000000000000000000000000000000000000000000000000000000000008b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061378192505050565b9150888260018451610f7e91906150e8565b81518110610f8e57610f8e61504b565b60200260200101511015610c525760405162461bcd60e51b815260040161057d90615114565b8242811015610fd55760405162461bcd60e51b815260040161057d90614fd3565b61101483838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b61107d8787600081811061102a5761102a61504b565b905060200201602081019061103f9190615061565b336110777f00000000000000000000000000000000000000000000000000000000000000008b8b60008181106108e5576108e561504b565b8c612f81565b6000878761108c6001826150e8565b81811061109b5761109b61504b565b90506020020160208101906110b09190615061565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa1580156110f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111c91906150fb565b905061115c8888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508a92506129ef915050565b88610b2c828a8a61116e6001826150e8565b81811061117d5761117d61504b565b90506020020160208101906111929190615061565b6040516370a0823160e01b81526001600160a01b038b8116600483015291909116906370a0823190602401610ae5565b6000806000806111f37f00000000000000000000000000000000000000000000000000000000000000008d8d61326f565b94505050925092506112138c8c85858c8c876001600160401b0316613492565b9098509650610daf8c8c8c8c8c8c8c8c6139c7565b6060834281101561124b5760405162461bcd60e51b815260040161057d90614fd3565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001688886112826001826150e8565b8181106112915761129161504b565b90506020020160208101906112a69190615061565b6001600160a01b0316146112cc5760405162461bcd60e51b815260040161057d9061507e565b61130b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b6113697f00000000000000000000000000000000000000000000000000000000000000008b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061378192505050565b915088826001845161137b91906150e8565b8151811061138b5761138b61504b565b602002602001015110156113b15760405162461bcd60e51b815260040161057d90615114565b6113c788886000818110610c6857610c6861504b565b6114068289898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525030925061308b915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632e1a7d4d836001855161144491906150e8565b815181106114545761145461504b565b60200260200101516040518263ffffffff1660e01b815260040161147a91815260200190565b600060405180830381600087803b15801561149457600080fd5b505af11580156114a8573d6000803e3d6000fd5b50505050610d3c8683600185516114bf91906150e8565b815181106114cf576114cf61504b565b6020026020010151612776565b606061151d83838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b61157b7f00000000000000000000000000000000000000000000000000000000000000008787878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061378192505050565b9695505050505050565b60606115c683838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b61157b7f000000000000000000000000000000000000000000000000000000000000000087878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612cf392505050565b600061157b8686868686613b78565b600081428110156116565760405162461bcd60e51b815260040161057d90614fd3565b611685887f0000000000000000000000000000000000000000000000000000000000000000898989308961190a565b6040516370a0823160e01b81523060048201529093506116fe9150899086906001600160a01b038316906370a0823190602401602060405180830381865afa1580156116d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f991906150fb565b612676565b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561176057600080fd5b505af1158015611774573d6000803e3d6000fd5b505050506117828483612776565b509695505050505050565b606083428110156117b05760405162461bcd60e51b815260040161057d90614fd3565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001688886117e76001826150e8565b8181106117f6576117f661504b565b905060200201602081019061180b9190615061565b6001600160a01b0316146118315760405162461bcd60e51b815260040161057d9061507e565b61187084848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b6118ce7f00000000000000000000000000000000000000000000000000000000000000008b8a8a80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612cf392505050565b915088826000815181106118e4576118e461504b565b602002602001015111156113b15760405162461bcd60e51b815260040161057d9061515f565b600080824281101561192e5760405162461bcd60e51b815260040161057d90614fd3565b600061195b7f00000000000000000000000000000000000000000000000000000000000000008c8c61281e565b6040516323b872dd60e01b81523360048201526001600160a01b03821660248201819052604482018c90529192506323b872dd906064016020604051808303816000875af11580156119b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d591906150b5565b5060405163226bf2d160e21b81526001600160a01b03878116600483015260009182918416906389afcb449060240160408051808303816000875af1158015611a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4691906151a6565b915091506000611a568e8e613c07565b509050806001600160a01b03168e6001600160a01b031614611a79578183611a7c565b82825b90975095508a871015611aa15760405162461bcd60e51b815260040161057d906151ca565b89861015611ac15760405162461bcd60e51b815260040161057d90615210565b505050505097509795505050505050565b60008060008542811015611af85760405162461bcd60e51b815260040161057d90614fd3565b611b3d8e8e8e8e8e8e8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613cfe92505050565b9094509250611b4f8e8e86868c613e88565b9150509a509a509a975050505050505050565b6000806000611bb27f00000000000000000000000000000000000000000000000000000000000000008e7f000000000000000000000000000000000000000000000000000000000000000061281e565b9050600087611bc1578c611bc5565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90611c00903390309086908f908e908e908e9060040161500a565b600060405180830381600087803b158015611c1a57600080fd5b505af1158015611c2e573d6000803e3d6000fd5b50505050611c408e8e8e8e8e8e610559565b909f909e509c50505050505050505050505050565b60608342811015611c785760405162461bcd60e51b815260040161057d90614fd3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031688886000818110611cb557611cb561504b565b9050602002016020810190611cca9190615061565b6001600160a01b031614611cf05760405162461bcd60e51b815260040161057d9061507e565b611d2f84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b611d8d7f00000000000000000000000000000000000000000000000000000000000000008a8a8a80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612cf392505050565b91503482600081518110611da357611da361504b565b60200260200101511115611dc95760405162461bcd60e51b815260040161057d9061515f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db083600081518110611e0b57611e0b61504b565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015611e3e57600080fd5b505af1158015611e52573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb611ebd7f00000000000000000000000000000000000000000000000000000000000000008b8b60008181106108e5576108e561504b565b84600081518110611ed057611ed061504b565b60200260200101516040518363ffffffff1660e01b8152600401611f099291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015611f28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4c91906150b5565b611f5857611f586148ef565b611f97828989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b925061308b915050565b81600081518110611faa57611faa61504b565b6020026020010151341115611fe857611fe83383600081518110611fd057611fd061504b565b602002602001015134611fe391906150e8565b612776565b50979650505050505050565b82428110156120155760405162461bcd60e51b815260040161057d90614fd3565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016878761204c6001826150e8565b81811061205b5761205b61504b565b90506020020160208101906120709190615061565b6001600160a01b0316146120965760405162461bcd60e51b815260040161057d9061507e565b6120d583838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b6120eb8787600081811061102a5761102a61504b565b6121298787808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152503092506129ef915050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015612190573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b491906150fb565b9050888110156121d65760405162461bcd60e51b815260040161057d90615114565b604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561223857600080fd5b505af115801561224c573d6000803e3d6000fd5b50505050610b4a8682612776565b6060834281101561227d5760405162461bcd60e51b815260040161057d90614fd3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316888860008181106122ba576122ba61504b565b90506020020160208101906122cf9190615061565b6001600160a01b0316146122f55760405162461bcd60e51b815260040161057d9061507e565b61233484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b6123927f0000000000000000000000000000000000000000000000000000000000000000348a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061378192505050565b91508882600184516123a491906150e8565b815181106123b4576123b461504b565b602002602001015110156123da5760405162461bcd60e51b815260040161057d90615114565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db08360008151811061241c5761241c61504b565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561244f57600080fd5b505af1158015612463573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb6124ce7f00000000000000000000000000000000000000000000000000000000000000008b8b60008181106108e5576108e561504b565b846000815181106124e1576124e161504b565b60200260200101516040518363ffffffff1660e01b815260040161251a9291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015612539573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061255d91906150b5565b612569576125696148ef565b611fe8828989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b925061308b915050565b600080600085428110156125ce5760405162461bcd60e51b815260040161057d90614fd3565b6126338c7f00000000000000000000000000000000000000000000000000000000000000008d348e8e8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613cfe92505050565b90945092506126658c7f000000000000000000000000000000000000000000000000000000000000000086868c613e88565b915050985098509895505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916126d2919061527a565b6000604051808303816000865af19150503d806000811461270f576040519150601f19603f3d011682016040523d82523d6000602084013e612714565b606091505b509150915081801561273e57508051158061273e57508080602001905181019061273e91906150b5565b61276f5760405162461bcd60e51b815260206004820152600260248201526114d560f21b604482015260640161057d565b5050505050565b604080516000808252602082019092526001600160a01b0384169083906040516127a0919061527a565b60006040518083038185875af1925050503d80600081146127dd576040519150601f19603f3d011682016040523d82523d6000602084013e6127e2565b606091505b50509050806128195760405162461bcd60e51b815260206004820152600360248201526253544560e81b604482015260640161057d565b505050565b600080600061282d8585613c07565b604080516bffffffffffffffffffffffff19606085811b821660208085019190915285821b83166034850152845180850360280181526048850190955284519401939093206001600160f81b03196068840152928b901b166069820152607d8101919091527fba3704b080a922b1d5cc299de67778312cff58ab8b1704742d9b0b19c359e228609d820152919350915060bd0160408051601f1981840301815291905280516020909101209695505050505050565b7f0000000000000000000000000000000000000000000000000000000000000000600061290e836140a4565b8051909150156128195760405163d47eed4560e01b81526000906001600160a01b0384169063d47eed45906129479085906004016152d8565b602060405180830381865afa158015612964573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298891906150fb565b9050826001600160a01b031663ef9e5e2882846040518363ffffffff1660e01b81526004016129b791906152d8565b6000604051808303818588803b1580156129d057600080fd5b505af11580156129e4573d6000803e3d6000fd5b505050505050505050565b60005b60018351612a0091906150e8565b81101561281957600080848381518110612a1c57612a1c61504b565b602002602001015185846001612a32919061533d565b81518110612a4257612a4261504b565b6020026020010151915091506000612a5a8383613c07565b5090506000612a8a7f0000000000000000000000000000000000000000000000000000000000000000858561281e565b90506000806000806000806000612ac27f00000000000000000000000000000000000000000000000000000000000000008c8c61326f565b94509450945094509450600080612afa7f00000000000000000000000000000000000000000000000000000000000000008e8e6140ca565b91509150612b168d8d89898686896001600160401b0316613492565b8092508193505050612b5d878e6001600160a01b03166370a082318d6040518263ffffffff1660e01b8152600401610ae591906001600160a01b0391909116815260200190565b9850612b6f8d8d8b8986868b8b6135a6565b975050505050505050600080856001600160a01b0316886001600160a01b031614612b9c57826000612ba0565b6000835b91509150600060028c51612bb491906150e8565b8a10612bc0578a612c0e565b612c0e7f0000000000000000000000000000000000000000000000000000000000000000898e612bf18e600261533d565b81518110612c0157612c0161504b565b602002602001015161281e565b6040805160008152602081019182905263022c0d9f60e01b9091529091506001600160a01b0387169063022c0d9f90612c509086908690869060248101615350565b600060405180830381600087803b158015612c6a57600080fd5b505af1158015612c7e573d6000803e3d6000fd5b50506001909b019a506129f29950505050505050505050565b600082612ca483826150e8565b9150811115612ced5760405162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015260640161057d565b92915050565b6060600282511015612d475760405162461bcd60e51b815260206004820152601e60248201527f42726f776e466956324c6962726172793a20494e56414c49445f504154480000604482015260640161057d565b81516001600160401b03811115612d6057612d60615296565b604051908082528060200260200182016040528015612d89578160200160208202803683370190505b509050828160018351612d9c91906150e8565b81518110612dac57612dac61504b565b602002602001018181525050600060018351612dc891906150e8565b90505b8015612f7957600080808080612e1e8a89612de760018a6150e8565b81518110612df757612df761504b565b60200260200101518a8981518110612e1157612e1161504b565b602002602001015161326f565b94509450945094509450600080612e748c8b60018b612e3d91906150e8565b81518110612e4d57612e4d61504b565b60200260200101518c8b81518110612e6757612e6761504b565b60200260200101516140ca565b9092509050612ecd8a612e8860018b6150e8565b81518110612e9857612e9861504b565b60200260200101518b8a81518110612eb257612eb261504b565b602002602001015189898686896001600160401b0316613492565b9092509050612f378a612ee160018b6150e8565b81518110612ef157612ef161504b565b60200260200101518b8a81518110612f0b57612f0b61504b565b60200260200101518b8b81518110612f2557612f2561504b565b60200260200101518986868b8b6139c7565b89612f4360018b6150e8565b81518110612f5357612f5361504b565b602002602001018181525050505050505050508080612f719061537d565b915050612dcb565b509392505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691612fe5919061527a565b6000604051808303816000865af19150503d8060008114613022576040519150601f19603f3d011682016040523d82523d6000602084013e613027565b606091505b509150915081801561305157508051158061305157508080602001905181019061305191906150b5565b6130835760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b604482015260640161057d565b505050505050565b60005b6001835161309c91906150e8565b811015613269576000808483815181106130b8576130b861504b565b6020026020010151858460016130ce919061533d565b815181106130de576130de61504b565b60200260200101519150915060006130f68383613c07565b50905060008761310786600161533d565b815181106131175761311761504b565b60200260200101519050600080836001600160a01b0316866001600160a01b03161461314557826000613149565b6000835b91509150600060028a5161315d91906150e8565b8810613169578861319a565b61319a7f0000000000000000000000000000000000000000000000000000000000000000878c612bf18c600261533d565b90506131c77f0000000000000000000000000000000000000000000000000000000000000000888861281e565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015613204576020820181803683370190505b506040518563ffffffff1660e01b81526004016132249493929190615350565b600060405180830381600087803b15801561323e57600080fd5b505af1158015613252573d6000803e3d6000fd5b50506001909901985061308e975050505050505050565b50505050565b600080808080878787836132838383613c07565b50905060008061329486868661281e565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156132d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f591906153ab565b506001600160701b031691506001600160701b0316915061331786868661281e565b6001600160a01b031663b4f40c616040518163ffffffff1660e01b8152600401602060405180830381865afa158015613354573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337891906150fb565b985061338586868661281e565b6001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e691906153f2565b97506133f386868661281e565b6001600160a01b031663dad0be616040518163ffffffff1660e01b8152600401602060405180830381865afa158015613430573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613454919061540f565b9650826001600160a01b0316856001600160a01b031614613476578082613479565b81815b809b50819c505050505050505050939792965093509350565b600080826000036134a757508390508261359a565b60006134b38a89614237565b905060006134c18a89614237565b905060006134cf8884615438565b905060006134dd8884615438565b90506000818310156134f8576134f383836150e8565b613502565b61350282846150e8565b90506000613510838561533d565b9050600061351f838b846142fc565b9050600061353182600160401b61533d565b9050600061354383600160401b6150e8565b905085871061357c5761355b8e82600160401b6142fc565b61356a8e84600160401b6142fc565b9a509a5050505050505050505061359a565b61358b8e83600160401b6142fc565b61356a8e83600160401b6142fc565b97509795505050505050565b600080871161360b5760405162461bcd60e51b815260206004820152602b60248201527f42726f776e466956324c6962726172793a20494e53554646494349454e545f4960448201526a1394155517d05353d5539560aa1b606482015260840161057d565b6000861161362b5760405162461bcd60e51b815260040161057d9061544f565b60006136378a89614237565b905060006136458a89614237565b90506000613667836305f5e10061366263ffffffff89168261533d565b6142fc565b9050613678600160401b6002615438565b86036136b1576136aa61368b8284615438565b896136968185615438565b6136a0868c615438565b613662919061533d565b9350613755565b60006136bf828a8a866143af565b905060006136cf838b8b876143d7565b905060006136e0848c8c888d614450565b905060006137058b6136fb8c610b266002600160401b61448c565b600160401b6142fc565b90508061373a61371d613718858761533d565b6144f3565b600160401b906fffffffffffffffffffffffffffffffff1661448c565b61374490866150e8565b61374e9190615497565b9750505050505b61375f8b85614664565b93506137718c8c86858c8c8c8c6139c7565b5050505098975050505050505050565b60606002825110156137d55760405162461bcd60e51b815260206004820152601e60248201527f42726f776e466956324c6962726172793a20494e56414c49445f504154480000604482015260640161057d565b81516001600160401b038111156137ee576137ee615296565b604051908082528060200260200182016040528015613817578160200160208202803683370190505b509050828160008151811061382e5761382e61504b565b60200260200101818152505060005b6001835161384b91906150e8565b811015612f795760008060008060006138968a8988815181106138705761387061504b565b60200260200101518a896001613886919061533d565b81518110612e1157612e1161504b565b945094509450945094506000806138df8c8b8a815181106138b9576138b961504b565b60200260200101518c8b60016138cf919061533d565b81518110612e6757612e6761504b565b9150915061391e8a89815181106138f8576138f861504b565b60200260200101518b8a600161390e919061533d565b81518110612eb257612eb261504b565b809250819350505061398d8a898151811061393b5761393b61504b565b60200260200101518b8a6001613951919061533d565b815181106139615761396161504b565b60200260200101518b8b8151811061397b5761397b61504b565b60200260200101518986868b8b6135a6565b896139998a600161533d565b815181106139a9576139a961504b565b602090810291909101015250506001909501945061383d9350505050565b6000808711613a2d5760405162461bcd60e51b815260206004820152602c60248201527f42726f776e466956324c6962726172793a20494e53554646494349454e545f4f60448201526b155514155517d05353d5539560a21b606482015260840161057d565b60008611613a4d5760405162461bcd60e51b815260040161057d9061544f565b613a5886600861448c565b613a6388600a61448c565b1115613ac55760405162461bcd60e51b815260206004820152602b60248201527f42726f776e466956324c6962726172793a204d41585f38305f50455243454e5460448201526a5f4f465f5245534552564560a81b606482015260840161057d565b6000613ad18989614237565b90506000613adf8a89614237565b90506000613b0d613af487600160401b61448c565b84613662613b028683612c97565b600160401b9061448c565b9050613b4583613b3689613b30613b29600160401b600261448c565b869061471c565b8c6142fc565b613662600160401b600261448c565b9350613b6c84613b626305f5e10063ffffffff808a169061471c16565b6305f5e1006142fc565b9350610daf8c85614664565b6000808411613bd75760405162461bcd60e51b815260206004820152602560248201527f42726f776e466956324c6962726172793a20494e53554646494349454e545f416044820152641353d5539560da1b606482015260840161057d565b6000613be38786614237565b9050613bf08185856142fc565b9150613bfc8683614664565b979650505050505050565b600080826001600160a01b0316846001600160a01b031603613c795760405162461bcd60e51b815260206004820152602560248201527f42726f776e466956324c6962726172793a204944454e544943414c5f41444452604482015264455353455360d81b606482015260840161057d565b826001600160a01b0316846001600160a01b031610613c99578284613c9c565b83835b90925090506001600160a01b038216613cf75760405162461bcd60e51b815260206004820152601e60248201527f42726f776e466956324c6962726172793a205a45524f5f414444524553530000604482015260640161057d565b9250929050565b6000806000806000613d0f86614771565b925092509250613d1e816128e2565b60405163e6a4390560e01b81526001600160a01b038d811660048301528c811660248301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063e6a4390590604401602060405180830381865afa158015613d91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613db591906154b9565b6001600160a01b031603613e675760405163446fc28b60e11b81526001600160a01b038d811660048301528c8116602483015260448201859052606482018490527f000000000000000000000000000000000000000000000000000000000000000016906388df8516906084016020604051808303816000875af1158015613e41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6591906154b9565b505b613e758c8c8c8c8c8c614822565b909d909c509a5050505050505050505050565b600080613eb67f0000000000000000000000000000000000000000000000000000000000000000888861281e565b9050613ec487338388612f81565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316866001600160a01b03160361402c577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015613f5857600080fd5b505af1158015613f6c573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303816000875af1158015613fe1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061400591906150b5565b614011576140116148ef565b833411156140275761402733611fe386346150e8565b614038565b61403886338387612f81565b6040516335313c2160e11b81526001600160a01b038481166004830152821690636a627842906024016020604051808303816000875af1158015614080573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bfc91906150fb565b8051606090156140c557818060200190518101906140c29190615506565b90505b919050565b60008060008060008787879250925092506000886001600160a01b03166367cc34036040518163ffffffff1660e01b8152600401602060405180830381865afa15801561411b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061413f91906150fb565b60405163fc3d545d60e01b81526001600160a01b038581166004830152602482018390529192509085169063fc3d545d90604401602060405180830381865afa158015614190573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141b491906150fb565b60405163fc3d545d60e01b81526001600160a01b038481166004830152602482018490529197509085169063fc3d545d90604401602060405180830381865afa158015614205573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061422991906150fb565b945050505050935093915050565b600080836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015614278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061429c9190615622565b905060128160ff16116142d1576142b760ff821660126150e8565b6142c290600a615726565b6142cc9084615438565b6142f4565b6142df601260ff83166150e8565b6142ea90600a615726565b6142f49084615497565b949350505050565b6000808060001985870985870292508281108382030391505080600003614335576000841161432a57600080fd5b5082900490506143a8565b80841161434157600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b60006143ce6143be858761448c565b6143c8858561448c565b9061471c565b95945050505050565b6000806143e98385600160401b6142fc565b6143f88787600160401b6142fc565b116144235761441e61440f8787600160401b6142fc565b610b268587600160401b6142fc565b614444565b6144446144358486600160401b6142fc565b610b268888600160401b6142fc565b905061157b8180615438565b600061157b61446e614462858961448c565b6002600160401b6142fc565b61448a61447b888861448c565b85613662600160401b80615438565b905b60008115806144b0575082826144a28183615438565b92506144ae9083615497565b145b612ced5760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015260640161057d565b60008160000361450557506000919050565b816001600160801b821061451e5760809190911c9060401b5b600160401b82106145345760409190911c9060201b5b640100000000821061454b5760209190911c9060101b5b6201000082106145605760109190911c9060081b5b61010082106145745760089190911c9060041b5b601082106145875760049190911c9060021b5b600482106145935760011b5b600161459f8286615497565b6145a9908361533d565b901c905060016145b98286615497565b6145c3908361533d565b901c905060016145d38286615497565b6145dd908361533d565b901c905060016145ed8286615497565b6145f7908361533d565b901c905060016146078286615497565b614611908361533d565b901c905060016146218286615497565b61462b908361533d565b901c9050600161463b8286615497565b614645908361533d565b901c905060006146558286615497565b9050808210612f7957806143ce565b600080836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156146a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146c99190615622565b905060128160ff16116146f9576146e460ff821660126150e8565b6146ef90600a615726565b6142cc9084615497565b614707601260ff83166150e8565b61471290600a615726565b6142f49084615438565b600082614729838261533d565b9150811015612ced5760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015260640161057d565b600080606060008451850151905060608551101580156147b057507f6c5de8f69b548efcdfceb3079391bd0025f809fcc7a31af0d13c34c032fb078e81145b156148165760408551038501519350602085510385015192506060855111156148115760608551036040519250806020018301604052808352602086016020840160005b8381101561480c5782810151828201526020016147f4565b505050505b61481a565b8491505b509193909250565b6000806000806148537f00000000000000000000000000000000000000000000000000000000000000008b8b6140ca565b9150915060006148668b8b8b8686613b78565b905087811161489a578581101561488f5760405162461bcd60e51b815260040161057d90615210565b8894509250826148e1565b60006148a98b8d8b8688613b78565b9050898111156148bb576148bb6148ef565b878110156148db5760405162461bcd60e51b815260040161057d906151ca565b94508793505b505050965096945050505050565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b038116811461491a57600080fd5b50565b60008060008060008060c0878903121561493657600080fd5b863561494181614905565b9550602087013594506040870135935060608701359250608087013561496681614905565b9598949750929591949360a090920135925050565b801515811461491a57600080fd5b60ff8116811461491a57600080fd5b60008060008060008060008060008060006101608c8e0312156149ba57600080fd5b8b356149c581614905565b9a5060208c01356149d581614905565b995060408c0135985060608c0135975060808c0135965060a08c01356149fa81614905565b955060c08c0135945060e08c0135614a118161497b565b93506101008c0135614a2281614989565b9a9d999c50979a969995989497509295919493610120830135935061014090920135919050565b60008083601f840112614a5b57600080fd5b5081356001600160401b03811115614a7257600080fd5b6020830191508360208260051b8501011115613cf757600080fd5b60008083601f840112614a9f57600080fd5b5081356001600160401b03811115614ab657600080fd5b602083019150836020828501011115613cf757600080fd5b600080600080600080600060a0888a031215614ae957600080fd5b8735965060208801356001600160401b03811115614b0657600080fd5b614b128a828b01614a49565b9097509550506040880135614b2681614905565b93506060880135925060808801356001600160401b03811115614b4857600080fd5b614b548a828b01614a8d565b989b979a50959850939692959293505050565b60008060008060008060008060c0898b031215614b8357600080fd5b883597506020890135965060408901356001600160401b03811115614ba757600080fd5b614bb38b828c01614a49565b9097509550506060890135614bc781614905565b93506080890135925060a08901356001600160401b03811115614be957600080fd5b614bf58b828c01614a8d565b999c989b5096995094979396929594505050565b602080825282518282018190526000918401906040840190835b81811015614c41578351835260209384019390920191600101614c23565b509095945050505050565b63ffffffff8116811461491a57600080fd5b600080600080600080600080610100898b031215614c7b57600080fd5b8835614c8681614905565b97506020890135614c9681614905565b965060408901359550606089013594506080890135935060a0890135925060c0890135915060e0890135614cc981614c4c565b809150509295985092959890939650565b6000806000806000806000806000806101408b8d031215614cfa57600080fd5b8a35614d0581614905565b995060208b0135985060408b0135975060608b0135965060808b0135614d2a81614905565b955060a08b0135945060c08b0135614d418161497b565b935060e08b0135614d5181614989565b999c989b509699959894979396509194610100810135936101209091013592509050565b600080600080600060608688031215614d8d57600080fd5b8535945060208601356001600160401b03811115614daa57600080fd5b614db688828901614a49565b90955093505060408601356001600160401b03811115614dd557600080fd5b614de188828901614a8d565b969995985093965092949392505050565b600080600080600060a08688031215614e0a57600080fd5b8535614e1581614905565b94506020860135614e2581614905565b94979496505050506040830135926060810135926080909101359150565b600080600080600080600060e0888a031215614e5e57600080fd5b8735614e6981614905565b96506020880135614e7981614905565b955060408801359450606088013593506080880135925060a0880135614e9e81614905565b96999598509396929591949193505060c09091013590565b6000806000806000806000806000806101208b8d031215614ed657600080fd5b8a35614ee181614905565b995060208b0135614ef181614905565b985060408b0135975060608b0135965060808b0135955060a08b0135945060c08b0135614f1d81614905565b935060e08b013592506101008b01356001600160401b03811115614f4057600080fd5b614f4c8d828e01614a8d565b915080935050809150509295989b9194979a5092959850565b60008060008060008060008060e0898b031215614f8157600080fd5b8835614f8c81614905565b97506020890135965060408901359550606089013594506080890135614fb181614905565b935060a0890135925060c08901356001600160401b03811115614be957600080fd5b60208082526018908201527f42726f776e46695632526f757465723a20455850495245440000000000000000604082015260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561507357600080fd5b81356143a881614905565b6020808252601d908201527f42726f776e46695632526f757465723a20494e56414c49445f50415448000000604082015260600190565b6000602082840312156150c757600080fd5b81516143a88161497b565b634e487b7160e01b600052601160045260246000fd5b81810381811115612ced57612ced6150d2565b60006020828403121561510d57600080fd5b5051919050565b6020808252602b908201527f42726f776e46695632526f757465723a20494e53554646494349454e545f4f5560408201526a1514155517d05353d5539560aa1b606082015260800190565b60208082526027908201527f42726f776e46695632526f757465723a204558434553534956455f494e50555460408201526617d05353d5539560ca1b606082015260800190565b600080604083850312156151b957600080fd5b505080516020909101519092909150565b60208082526026908201527f42726f776e46695632526f757465723a20494e53554646494349454e545f415f604082015265105353d5539560d21b606082015260800190565b60208082526026908201527f42726f776e46695632526f757465723a20494e53554646494349454e545f425f604082015265105353d5539560d21b606082015260800190565b60005b83811015615271578181015183820152602001615259565b50506000910152565b6000825161528c818460208701615256565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b600081518084526152c4816020860160208601615256565b601f01601f19169290920160200192915050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b8281101561533157603f1987860301845261531c8583516152ac565b94506020938401939190910190600101615300565b50929695505050505050565b80820180821115612ced57612ced6150d2565b84815283602082015260018060a01b038316604082015260806060820152600061157b60808301846152ac565b60008161538c5761538c6150d2565b506000190190565b80516001600160701b03811681146140c557600080fd5b6000806000606084860312156153c057600080fd5b6153c984615394565b92506153d760208501615394565b915060408401516153e781614c4c565b809150509250925092565b60006020828403121561540457600080fd5b81516143a881614c4c565b60006020828403121561542157600080fd5b81516001600160401b03811681146143a857600080fd5b8082028115828204841417612ced57612ced6150d2565b60208082526028908201527f42726f776e466956324c6962726172793a20494e53554646494349454e545f4c604082015267495155494449545960c01b606082015260800190565b6000826154b457634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156154cb57600080fd5b81516143a881614905565b604051601f8201601f191681016001600160401b03811182821017156154fe576154fe615296565b604052919050565b60006020828403121561551857600080fd5b81516001600160401b0381111561552e57600080fd5b8201601f8101841361553f57600080fd5b80516001600160401b0381111561555857615558615296565b8060051b615568602082016154d6565b9182526020818401810192908101908784111561558457600080fd5b6020850192505b83831015613bfc5782516001600160401b038111156155a957600080fd5b8501603f810189136155ba57600080fd5b60208101516001600160401b038111156155d6576155d6615296565b6155e9601f8201601f19166020016154d6565b8181526040838301018b10156155fe57600080fd5b61560f826020830160408601615256565b845250506020928301929091019061558b565b60006020828403121561563457600080fd5b81516143a881614989565b6001815b600184111561567a5780850481111561565e5761565e6150d2565b600184161561566c57908102905b60019390931c928002615643565b935093915050565b60008261569157506001612ced565b8161569e57506000612ced565b81600181146156b457600281146156be576156da565b6001915050612ced565b60ff8411156156cf576156cf6150d2565b50506001821b612ced565b5060208310610133831016604e8410600b84101617156156fd575081810a612ced565b61570a600019848461563f565b806000190482111561571e5761571e6150d2565b029392505050565b60006143a8838361568256fea26469706673582212204f92baa55ec032e83c4f900cf24a088b452a1f945e170cd0409dc24b88b24b4e64736f6c634300081c003300000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045360000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a
Deployed Bytecode
0x6080604052600436106101855760003560e01c8063988f8363116100d1578063c45a01551161008a578063e76c597511610064578063e76c597514610500578063ed16c0b414610513578063ed3b11ce14610533578063f515c1041461054657600080fd5b8063c45a015514610471578063d4141257146104a5578063ded9382a146104e057600080fd5b8063988f83631461039d578063a07ee849146103bd578063ad5c4648146103dd578063af2979eb14610411578063b132b5e114610431578063baa2abde1461045157600080fd5b80635e1d693e1161013e5780637a253b58116101185780637a253b581461031d5780637fe186501461033d5780638af139371461035d5780638d77c6f01461037d57600080fd5b80635e1d693e146102b157806367e406d5146102d157806371e0b951146101c257600080fd5b806302751cec146101c95780632195995c14610203578063274b96a514610223578063323de4ee1461023657806334b5731a146102635780635b0d59841461029157600080fd5b366101c457336001600160a01b037f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a16146101c2576101c26148ef565b005b600080fd5b3480156101d557600080fd5b506101e96101e436600461491d565b610559565b604080519283526020830191909152015b60405180910390f35b34801561020f57600080fd5b506101e961021e366004614998565b610655565b6101c2610231366004614ace565b61072e565b34801561024257600080fd5b50610256610251366004614b67565b610b56565b6040516101fa9190614c09565b34801561026f57600080fd5b5061028361027e366004614c5e565b610d49565b6040519081526020016101fa565b34801561029d57600080fd5b506102836102ac366004614cda565b610dbf565b3480156102bd57600080fd5b506102566102cc366004614b67565b610eac565b3480156102dd57600080fd5b506103057f0000000000000000000000002880ab155794e7179c9ee2e38200202908c17b4381565b6040516001600160a01b0390911681526020016101fa565b34801561032957600080fd5b506101c2610338366004614b67565b610fb4565b34801561034957600080fd5b50610283610358366004614c5e565b6111c2565b34801561036957600080fd5b50610256610378366004614b67565b611228565b34801561038957600080fd5b50610256610398366004614d75565b6114dc565b3480156103a957600080fd5b506102566103b8366004614d75565b611585565b3480156103c957600080fd5b506102836103d8366004614df2565b611624565b3480156103e957600080fd5b506103057f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a81565b34801561041d57600080fd5b5061028361042c36600461491d565b611633565b34801561043d57600080fd5b5061025661044c366004614b67565b61178d565b34801561045d57600080fd5b506101e961046c366004614e43565b61190a565b34801561047d57600080fd5b506103057f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f830453681565b3480156104b157600080fd5b506104c56104c0366004614eb6565b611ad2565b604080519384526020840192909252908201526060016101fa565b3480156104ec57600080fd5b506101e96104fb366004614cda565b611b62565b61025661050e366004614ace565b611c55565b34801561051f57600080fd5b506101c261052e366004614b67565b611ff4565b610256610541366004614ace565b61225a565b6104c5610554366004614f65565b6125a8565b60008082428110156105865760405162461bcd60e51b815260040161057d90614fd3565b60405180910390fd5b6105b5897f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a8a8a8a308a61190a565b90935091506105c5898685612676565b604051632e1a7d4d60e01b8152600481018390527f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561062757600080fd5b505af115801561063b573d6000803e3d6000fd5b505050506106498583612776565b50965096945050505050565b60008060006106857f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368f8f61281e565b9050600087610694578c610698565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf906106d3903390309086908f908e908e908e9060040161500a565b600060405180830381600087803b1580156106ed57600080fd5b505af1158015610701573d6000803e3d6000fd5b505050506107148f8f8f8f8f8f8f61190a565b809450819550505050509b509b9950505050505050505050565b824281101561074f5760405162461bcd60e51b815260040161057d90614fd3565b7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b03168787600081811061078c5761078c61504b565b90506020020160208101906107a19190615061565b6001600160a01b0316146107c75760405162461bcd60e51b815260040161057d9061507e565b61080683838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b60003490507f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561086657600080fd5b505af115801561087a573d6000803e3d6000fd5b50505050507f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031663a9059cbb6109277f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368b8b60008181106108e5576108e561504b565b90506020020160208101906108fa9190615061565b8c8c600181811061090d5761090d61504b565b90506020020160208101906109229190615061565b61281e565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015610974573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099891906150b5565b6109a4576109a46148ef565b600088886109b36001826150e8565b8181106109c2576109c261504b565b90506020020160208101906109d79190615061565b6040516370a0823160e01b81526001600160a01b03898116600483015291909116906370a0823190602401602060405180830381865afa158015610a1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4391906150fb565b9050610a838989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b92506129ef915050565b89610b2c828b8b610a956001826150e8565b818110610aa457610aa461504b565b9050602002016020810190610ab99190615061565b6040516370a0823160e01b81526001600160a01b038c8116600483015291909116906370a08231906024015b602060405180830381865afa158015610b02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2691906150fb565b90612c97565b1015610b4a5760405162461bcd60e51b815260040161057d90615114565b50505050505050505050565b60608342811015610b795760405162461bcd60e51b815260040161057d90614fd3565b610bb884848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b610c167f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368b8a8a80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612cf392505050565b91508882600081518110610c2c57610c2c61504b565b60200260200101511115610c525760405162461bcd60e51b815260040161057d9061515f565b610cfd88886000818110610c6857610c6861504b565b9050602002016020810190610c7d9190615061565b33610cdd7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368c8c6000818110610cb557610cb561504b565b9050602002016020810190610cca9190615061565b8d8d600181811061090d5761090d61504b565b85600081518110610cf057610cf061504b565b6020026020010151612f81565b610d3c828989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b925061308b915050565b5098975050505050505050565b600080600080610d7a7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368d8d61326f565b9450505092509250610d9a8c8c85858c8c876001600160401b0316613492565b9098509650610daf8c8c8c8c8c8c8c8c6135a6565b9c9b505050505050505050505050565b600080610e0d7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368d7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a61281e565b9050600086610e1c578b610e20565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90610e5b903390309086908e908d908d908d9060040161500a565b600060405180830381600087803b158015610e7557600080fd5b505af1158015610e89573d6000803e3d6000fd5b50505050610e9b8d8d8d8d8d8d611633565b9d9c50505050505050505050505050565b60608342811015610ecf5760405162461bcd60e51b815260040161057d90614fd3565b610f0e84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b610f6c7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061378192505050565b9150888260018451610f7e91906150e8565b81518110610f8e57610f8e61504b565b60200260200101511015610c525760405162461bcd60e51b815260040161057d90615114565b8242811015610fd55760405162461bcd60e51b815260040161057d90614fd3565b61101483838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b61107d8787600081811061102a5761102a61504b565b905060200201602081019061103f9190615061565b336110777f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368b8b60008181106108e5576108e561504b565b8c612f81565b6000878761108c6001826150e8565b81811061109b5761109b61504b565b90506020020160208101906110b09190615061565b6040516370a0823160e01b81526001600160a01b03888116600483015291909116906370a0823190602401602060405180830381865afa1580156110f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061111c91906150fb565b905061115c8888808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508a92506129ef915050565b88610b2c828a8a61116e6001826150e8565b81811061117d5761117d61504b565b90506020020160208101906111929190615061565b6040516370a0823160e01b81526001600160a01b038b8116600483015291909116906370a0823190602401610ae5565b6000806000806111f37f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368d8d61326f565b94505050925092506112138c8c85858c8c876001600160401b0316613492565b9098509650610daf8c8c8c8c8c8c8c8c6139c7565b6060834281101561124b5760405162461bcd60e51b815260040161057d90614fd3565b6001600160a01b037f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a1688886112826001826150e8565b8181106112915761129161504b565b90506020020160208101906112a69190615061565b6001600160a01b0316146112cc5760405162461bcd60e51b815260040161057d9061507e565b61130b84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b6113697f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061378192505050565b915088826001845161137b91906150e8565b8151811061138b5761138b61504b565b602002602001015110156113b15760405162461bcd60e51b815260040161057d90615114565b6113c788886000818110610c6857610c6861504b565b6114068289898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525030925061308b915050565b7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b0316632e1a7d4d836001855161144491906150e8565b815181106114545761145461504b565b60200260200101516040518263ffffffff1660e01b815260040161147a91815260200190565b600060405180830381600087803b15801561149457600080fd5b505af11580156114a8573d6000803e3d6000fd5b50505050610d3c8683600185516114bf91906150e8565b815181106114cf576114cf61504b565b6020026020010151612776565b606061151d83838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b61157b7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368787878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061378192505050565b9695505050505050565b60606115c683838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b61157b7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f830453687878780806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612cf392505050565b600061157b8686868686613b78565b600081428110156116565760405162461bcd60e51b815260040161057d90614fd3565b611685887f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a898989308961190a565b6040516370a0823160e01b81523060048201529093506116fe9150899086906001600160a01b038316906370a0823190602401602060405180830381865afa1580156116d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f991906150fb565b612676565b604051632e1a7d4d60e01b8152600481018390527f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561176057600080fd5b505af1158015611774573d6000803e3d6000fd5b505050506117828483612776565b509695505050505050565b606083428110156117b05760405162461bcd60e51b815260040161057d90614fd3565b6001600160a01b037f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a1688886117e76001826150e8565b8181106117f6576117f661504b565b905060200201602081019061180b9190615061565b6001600160a01b0316146118315760405162461bcd60e51b815260040161057d9061507e565b61187084848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b6118ce7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368b8a8a80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612cf392505050565b915088826000815181106118e4576118e461504b565b602002602001015111156113b15760405162461bcd60e51b815260040161057d9061515f565b600080824281101561192e5760405162461bcd60e51b815260040161057d90614fd3565b600061195b7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368c8c61281e565b6040516323b872dd60e01b81523360048201526001600160a01b03821660248201819052604482018c90529192506323b872dd906064016020604051808303816000875af11580156119b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119d591906150b5565b5060405163226bf2d160e21b81526001600160a01b03878116600483015260009182918416906389afcb449060240160408051808303816000875af1158015611a22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4691906151a6565b915091506000611a568e8e613c07565b509050806001600160a01b03168e6001600160a01b031614611a79578183611a7c565b82825b90975095508a871015611aa15760405162461bcd60e51b815260040161057d906151ca565b89861015611ac15760405162461bcd60e51b815260040161057d90615210565b505050505097509795505050505050565b60008060008542811015611af85760405162461bcd60e51b815260040161057d90614fd3565b611b3d8e8e8e8e8e8e8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613cfe92505050565b9094509250611b4f8e8e86868c613e88565b9150509a509a509a975050505050505050565b6000806000611bb27f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368e7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a61281e565b9050600087611bc1578c611bc5565b6000195b60405163d505accf60e01b81529091506001600160a01b0383169063d505accf90611c00903390309086908f908e908e908e9060040161500a565b600060405180830381600087803b158015611c1a57600080fd5b505af1158015611c2e573d6000803e3d6000fd5b50505050611c408e8e8e8e8e8e610559565b909f909e509c50505050505050505050505050565b60608342811015611c785760405162461bcd60e51b815260040161057d90614fd3565b7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031688886000818110611cb557611cb561504b565b9050602002016020810190611cca9190615061565b6001600160a01b031614611cf05760405162461bcd60e51b815260040161057d9061507e565b611d2f84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b611d8d7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368a8a8a80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612cf392505050565b91503482600081518110611da357611da361504b565b60200260200101511115611dc95760405162461bcd60e51b815260040161057d9061515f565b7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031663d0e30db083600081518110611e0b57611e0b61504b565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b158015611e3e57600080fd5b505af1158015611e52573d6000803e3d6000fd5b50505050507f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031663a9059cbb611ebd7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368b8b60008181106108e5576108e561504b565b84600081518110611ed057611ed061504b565b60200260200101516040518363ffffffff1660e01b8152600401611f099291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015611f28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4c91906150b5565b611f5857611f586148ef565b611f97828989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b925061308b915050565b81600081518110611faa57611faa61504b565b6020026020010151341115611fe857611fe83383600081518110611fd057611fd061504b565b602002602001015134611fe391906150e8565b612776565b50979650505050505050565b82428110156120155760405162461bcd60e51b815260040161057d90614fd3565b6001600160a01b037f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a16878761204c6001826150e8565b81811061205b5761205b61504b565b90506020020160208101906120709190615061565b6001600160a01b0316146120965760405162461bcd60e51b815260040161057d9061507e565b6120d583838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b6120eb8787600081811061102a5761102a61504b565b6121298787808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152503092506129ef915050565b6040516370a0823160e01b81523060048201526000907f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b0316906370a0823190602401602060405180830381865afa158015612190573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b491906150fb565b9050888110156121d65760405162461bcd60e51b815260040161057d90615114565b604051632e1a7d4d60e01b8152600481018290527f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561223857600080fd5b505af115801561224c573d6000803e3d6000fd5b50505050610b4a8682612776565b6060834281101561227d5760405162461bcd60e51b815260040161057d90614fd3565b7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b0316888860008181106122ba576122ba61504b565b90506020020160208101906122cf9190615061565b6001600160a01b0316146122f55760405162461bcd60e51b815260040161057d9061507e565b61233484848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506128e292505050565b6123927f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f8304536348a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525061378192505050565b91508882600184516123a491906150e8565b815181106123b4576123b461504b565b602002602001015110156123da5760405162461bcd60e51b815260040161057d90615114565b7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031663d0e30db08360008151811061241c5761241c61504b565b60200260200101516040518263ffffffff1660e01b81526004016000604051808303818588803b15801561244f57600080fd5b505af1158015612463573d6000803e3d6000fd5b50505050507f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031663a9059cbb6124ce7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368b8b60008181106108e5576108e561504b565b846000815181106124e1576124e161504b565b60200260200101516040518363ffffffff1660e01b815260040161251a9291906001600160a01b03929092168252602082015260400190565b6020604051808303816000875af1158015612539573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061255d91906150b5565b612569576125696148ef565b611fe8828989808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508b925061308b915050565b600080600085428110156125ce5760405162461bcd60e51b815260040161057d90614fd3565b6126338c7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a8d348e8e8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613cfe92505050565b90945092506126658c7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a86868c613e88565b915050985098509895505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916126d2919061527a565b6000604051808303816000865af19150503d806000811461270f576040519150601f19603f3d011682016040523d82523d6000602084013e612714565b606091505b509150915081801561273e57508051158061273e57508080602001905181019061273e91906150b5565b61276f5760405162461bcd60e51b815260206004820152600260248201526114d560f21b604482015260640161057d565b5050505050565b604080516000808252602082019092526001600160a01b0384169083906040516127a0919061527a565b60006040518083038185875af1925050503d80600081146127dd576040519150601f19603f3d011682016040523d82523d6000602084013e6127e2565b606091505b50509050806128195760405162461bcd60e51b815260206004820152600360248201526253544560e81b604482015260640161057d565b505050565b600080600061282d8585613c07565b604080516bffffffffffffffffffffffff19606085811b821660208085019190915285821b83166034850152845180850360280181526048850190955284519401939093206001600160f81b03196068840152928b901b166069820152607d8101919091527fba3704b080a922b1d5cc299de67778312cff58ab8b1704742d9b0b19c359e228609d820152919350915060bd0160408051601f1981840301815291905280516020909101209695505050505050565b7f0000000000000000000000002880ab155794e7179c9ee2e38200202908c17b43600061290e836140a4565b8051909150156128195760405163d47eed4560e01b81526000906001600160a01b0384169063d47eed45906129479085906004016152d8565b602060405180830381865afa158015612964573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298891906150fb565b9050826001600160a01b031663ef9e5e2882846040518363ffffffff1660e01b81526004016129b791906152d8565b6000604051808303818588803b1580156129d057600080fd5b505af11580156129e4573d6000803e3d6000fd5b505050505050505050565b60005b60018351612a0091906150e8565b81101561281957600080848381518110612a1c57612a1c61504b565b602002602001015185846001612a32919061533d565b81518110612a4257612a4261504b565b6020026020010151915091506000612a5a8383613c07565b5090506000612a8a7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f8304536858561281e565b90506000806000806000806000612ac27f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368c8c61326f565b94509450945094509450600080612afa7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368e8e6140ca565b91509150612b168d8d89898686896001600160401b0316613492565b8092508193505050612b5d878e6001600160a01b03166370a082318d6040518263ffffffff1660e01b8152600401610ae591906001600160a01b0391909116815260200190565b9850612b6f8d8d8b8986868b8b6135a6565b975050505050505050600080856001600160a01b0316886001600160a01b031614612b9c57826000612ba0565b6000835b91509150600060028c51612bb491906150e8565b8a10612bc0578a612c0e565b612c0e7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f8304536898e612bf18e600261533d565b81518110612c0157612c0161504b565b602002602001015161281e565b6040805160008152602081019182905263022c0d9f60e01b9091529091506001600160a01b0387169063022c0d9f90612c509086908690869060248101615350565b600060405180830381600087803b158015612c6a57600080fd5b505af1158015612c7e573d6000803e3d6000fd5b50506001909b019a506129f29950505050505050505050565b600082612ca483826150e8565b9150811115612ced5760405162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015260640161057d565b92915050565b6060600282511015612d475760405162461bcd60e51b815260206004820152601e60248201527f42726f776e466956324c6962726172793a20494e56414c49445f504154480000604482015260640161057d565b81516001600160401b03811115612d6057612d60615296565b604051908082528060200260200182016040528015612d89578160200160208202803683370190505b509050828160018351612d9c91906150e8565b81518110612dac57612dac61504b565b602002602001018181525050600060018351612dc891906150e8565b90505b8015612f7957600080808080612e1e8a89612de760018a6150e8565b81518110612df757612df761504b565b60200260200101518a8981518110612e1157612e1161504b565b602002602001015161326f565b94509450945094509450600080612e748c8b60018b612e3d91906150e8565b81518110612e4d57612e4d61504b565b60200260200101518c8b81518110612e6757612e6761504b565b60200260200101516140ca565b9092509050612ecd8a612e8860018b6150e8565b81518110612e9857612e9861504b565b60200260200101518b8a81518110612eb257612eb261504b565b602002602001015189898686896001600160401b0316613492565b9092509050612f378a612ee160018b6150e8565b81518110612ef157612ef161504b565b60200260200101518b8a81518110612f0b57612f0b61504b565b60200260200101518b8b81518110612f2557612f2561504b565b60200260200101518986868b8b6139c7565b89612f4360018b6150e8565b81518110612f5357612f5361504b565b602002602001018181525050505050505050508080612f719061537d565b915050612dcb565b509392505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691612fe5919061527a565b6000604051808303816000865af19150503d8060008114613022576040519150601f19603f3d011682016040523d82523d6000602084013e613027565b606091505b509150915081801561305157508051158061305157508080602001905181019061305191906150b5565b6130835760405162461bcd60e51b815260206004820152600360248201526229aa2360e91b604482015260640161057d565b505050505050565b60005b6001835161309c91906150e8565b811015613269576000808483815181106130b8576130b861504b565b6020026020010151858460016130ce919061533d565b815181106130de576130de61504b565b60200260200101519150915060006130f68383613c07565b50905060008761310786600161533d565b815181106131175761311761504b565b60200260200101519050600080836001600160a01b0316866001600160a01b03161461314557826000613149565b6000835b91509150600060028a5161315d91906150e8565b8810613169578861319a565b61319a7f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f8304536878c612bf18c600261533d565b90506131c77f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f8304536888861281e565b6001600160a01b031663022c0d9f84848460006040519080825280601f01601f191660200182016040528015613204576020820181803683370190505b506040518563ffffffff1660e01b81526004016132249493929190615350565b600060405180830381600087803b15801561323e57600080fd5b505af1158015613252573d6000803e3d6000fd5b50506001909901985061308e975050505050505050565b50505050565b600080808080878787836132838383613c07565b50905060008061329486868661281e565b6001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156132d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132f591906153ab565b506001600160701b031691506001600160701b0316915061331786868661281e565b6001600160a01b031663b4f40c616040518163ffffffff1660e01b8152600401602060405180830381865afa158015613354573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061337891906150fb565b985061338586868661281e565b6001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e691906153f2565b97506133f386868661281e565b6001600160a01b031663dad0be616040518163ffffffff1660e01b8152600401602060405180830381865afa158015613430573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613454919061540f565b9650826001600160a01b0316856001600160a01b031614613476578082613479565b81815b809b50819c505050505050505050939792965093509350565b600080826000036134a757508390508261359a565b60006134b38a89614237565b905060006134c18a89614237565b905060006134cf8884615438565b905060006134dd8884615438565b90506000818310156134f8576134f383836150e8565b613502565b61350282846150e8565b90506000613510838561533d565b9050600061351f838b846142fc565b9050600061353182600160401b61533d565b9050600061354383600160401b6150e8565b905085871061357c5761355b8e82600160401b6142fc565b61356a8e84600160401b6142fc565b9a509a5050505050505050505061359a565b61358b8e83600160401b6142fc565b61356a8e83600160401b6142fc565b97509795505050505050565b600080871161360b5760405162461bcd60e51b815260206004820152602b60248201527f42726f776e466956324c6962726172793a20494e53554646494349454e545f4960448201526a1394155517d05353d5539560aa1b606482015260840161057d565b6000861161362b5760405162461bcd60e51b815260040161057d9061544f565b60006136378a89614237565b905060006136458a89614237565b90506000613667836305f5e10061366263ffffffff89168261533d565b6142fc565b9050613678600160401b6002615438565b86036136b1576136aa61368b8284615438565b896136968185615438565b6136a0868c615438565b613662919061533d565b9350613755565b60006136bf828a8a866143af565b905060006136cf838b8b876143d7565b905060006136e0848c8c888d614450565b905060006137058b6136fb8c610b266002600160401b61448c565b600160401b6142fc565b90508061373a61371d613718858761533d565b6144f3565b600160401b906fffffffffffffffffffffffffffffffff1661448c565b61374490866150e8565b61374e9190615497565b9750505050505b61375f8b85614664565b93506137718c8c86858c8c8c8c6139c7565b5050505098975050505050505050565b60606002825110156137d55760405162461bcd60e51b815260206004820152601e60248201527f42726f776e466956324c6962726172793a20494e56414c49445f504154480000604482015260640161057d565b81516001600160401b038111156137ee576137ee615296565b604051908082528060200260200182016040528015613817578160200160208202803683370190505b509050828160008151811061382e5761382e61504b565b60200260200101818152505060005b6001835161384b91906150e8565b811015612f795760008060008060006138968a8988815181106138705761387061504b565b60200260200101518a896001613886919061533d565b81518110612e1157612e1161504b565b945094509450945094506000806138df8c8b8a815181106138b9576138b961504b565b60200260200101518c8b60016138cf919061533d565b81518110612e6757612e6761504b565b9150915061391e8a89815181106138f8576138f861504b565b60200260200101518b8a600161390e919061533d565b81518110612eb257612eb261504b565b809250819350505061398d8a898151811061393b5761393b61504b565b60200260200101518b8a6001613951919061533d565b815181106139615761396161504b565b60200260200101518b8b8151811061397b5761397b61504b565b60200260200101518986868b8b6135a6565b896139998a600161533d565b815181106139a9576139a961504b565b602090810291909101015250506001909501945061383d9350505050565b6000808711613a2d5760405162461bcd60e51b815260206004820152602c60248201527f42726f776e466956324c6962726172793a20494e53554646494349454e545f4f60448201526b155514155517d05353d5539560a21b606482015260840161057d565b60008611613a4d5760405162461bcd60e51b815260040161057d9061544f565b613a5886600861448c565b613a6388600a61448c565b1115613ac55760405162461bcd60e51b815260206004820152602b60248201527f42726f776e466956324c6962726172793a204d41585f38305f50455243454e5460448201526a5f4f465f5245534552564560a81b606482015260840161057d565b6000613ad18989614237565b90506000613adf8a89614237565b90506000613b0d613af487600160401b61448c565b84613662613b028683612c97565b600160401b9061448c565b9050613b4583613b3689613b30613b29600160401b600261448c565b869061471c565b8c6142fc565b613662600160401b600261448c565b9350613b6c84613b626305f5e10063ffffffff808a169061471c16565b6305f5e1006142fc565b9350610daf8c85614664565b6000808411613bd75760405162461bcd60e51b815260206004820152602560248201527f42726f776e466956324c6962726172793a20494e53554646494349454e545f416044820152641353d5539560da1b606482015260840161057d565b6000613be38786614237565b9050613bf08185856142fc565b9150613bfc8683614664565b979650505050505050565b600080826001600160a01b0316846001600160a01b031603613c795760405162461bcd60e51b815260206004820152602560248201527f42726f776e466956324c6962726172793a204944454e544943414c5f41444452604482015264455353455360d81b606482015260840161057d565b826001600160a01b0316846001600160a01b031610613c99578284613c9c565b83835b90925090506001600160a01b038216613cf75760405162461bcd60e51b815260206004820152601e60248201527f42726f776e466956324c6962726172793a205a45524f5f414444524553530000604482015260640161057d565b9250929050565b6000806000806000613d0f86614771565b925092509250613d1e816128e2565b60405163e6a4390560e01b81526001600160a01b038d811660048301528c811660248301526000917f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045369091169063e6a4390590604401602060405180830381865afa158015613d91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613db591906154b9565b6001600160a01b031603613e675760405163446fc28b60e11b81526001600160a01b038d811660048301528c8116602483015260448201859052606482018490527f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f830453616906388df8516906084016020604051808303816000875af1158015613e41573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6591906154b9565b505b613e758c8c8c8c8c8c614822565b909d909c509a5050505050505050505050565b600080613eb67f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f8304536888861281e565b9050613ec487338388612f81565b7f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b0316866001600160a01b03160361402c577f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a6001600160a01b031663d0e30db0856040518263ffffffff1660e01b81526004016000604051808303818588803b158015613f5857600080fd5b505af1158015613f6c573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018990527f0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a16935063a9059cbb925060440190506020604051808303816000875af1158015613fe1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061400591906150b5565b614011576140116148ef565b833411156140275761402733611fe386346150e8565b614038565b61403886338387612f81565b6040516335313c2160e11b81526001600160a01b038481166004830152821690636a627842906024016020604051808303816000875af1158015614080573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bfc91906150fb565b8051606090156140c557818060200190518101906140c29190615506565b90505b919050565b60008060008060008787879250925092506000886001600160a01b03166367cc34036040518163ffffffff1660e01b8152600401602060405180830381865afa15801561411b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061413f91906150fb565b60405163fc3d545d60e01b81526001600160a01b038581166004830152602482018390529192509085169063fc3d545d90604401602060405180830381865afa158015614190573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141b491906150fb565b60405163fc3d545d60e01b81526001600160a01b038481166004830152602482018490529197509085169063fc3d545d90604401602060405180830381865afa158015614205573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061422991906150fb565b945050505050935093915050565b600080836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015614278573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061429c9190615622565b905060128160ff16116142d1576142b760ff821660126150e8565b6142c290600a615726565b6142cc9084615438565b6142f4565b6142df601260ff83166150e8565b6142ea90600a615726565b6142f49084615497565b949350505050565b6000808060001985870985870292508281108382030391505080600003614335576000841161432a57600080fd5b5082900490506143a8565b80841161434157600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b60006143ce6143be858761448c565b6143c8858561448c565b9061471c565b95945050505050565b6000806143e98385600160401b6142fc565b6143f88787600160401b6142fc565b116144235761441e61440f8787600160401b6142fc565b610b268587600160401b6142fc565b614444565b6144446144358486600160401b6142fc565b610b268888600160401b6142fc565b905061157b8180615438565b600061157b61446e614462858961448c565b6002600160401b6142fc565b61448a61447b888861448c565b85613662600160401b80615438565b905b60008115806144b0575082826144a28183615438565b92506144ae9083615497565b145b612ced5760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604482015260640161057d565b60008160000361450557506000919050565b816001600160801b821061451e5760809190911c9060401b5b600160401b82106145345760409190911c9060201b5b640100000000821061454b5760209190911c9060101b5b6201000082106145605760109190911c9060081b5b61010082106145745760089190911c9060041b5b601082106145875760049190911c9060021b5b600482106145935760011b5b600161459f8286615497565b6145a9908361533d565b901c905060016145b98286615497565b6145c3908361533d565b901c905060016145d38286615497565b6145dd908361533d565b901c905060016145ed8286615497565b6145f7908361533d565b901c905060016146078286615497565b614611908361533d565b901c905060016146218286615497565b61462b908361533d565b901c9050600161463b8286615497565b614645908361533d565b901c905060006146558286615497565b9050808210612f7957806143ce565b600080836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156146a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146c99190615622565b905060128160ff16116146f9576146e460ff821660126150e8565b6146ef90600a615726565b6142cc9084615497565b614707601260ff83166150e8565b61471290600a615726565b6142f49084615438565b600082614729838261533d565b9150811015612ced5760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015260640161057d565b600080606060008451850151905060608551101580156147b057507f6c5de8f69b548efcdfceb3079391bd0025f809fcc7a31af0d13c34c032fb078e81145b156148165760408551038501519350602085510385015192506060855111156148115760608551036040519250806020018301604052808352602086016020840160005b8381101561480c5782810151828201526020016147f4565b505050505b61481a565b8491505b509193909250565b6000806000806148537f00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045368b8b6140ca565b9150915060006148668b8b8b8686613b78565b905087811161489a578581101561488f5760405162461bcd60e51b815260040161057d90615210565b8894509250826148e1565b60006148a98b8d8b8688613b78565b9050898111156148bb576148bb6148ef565b878110156148db5760405162461bcd60e51b815260040161057d906151ca565b94508793505b505050965096945050505050565b634e487b7160e01b600052600160045260246000fd5b6001600160a01b038116811461491a57600080fd5b50565b60008060008060008060c0878903121561493657600080fd5b863561494181614905565b9550602087013594506040870135935060608701359250608087013561496681614905565b9598949750929591949360a090920135925050565b801515811461491a57600080fd5b60ff8116811461491a57600080fd5b60008060008060008060008060008060006101608c8e0312156149ba57600080fd5b8b356149c581614905565b9a5060208c01356149d581614905565b995060408c0135985060608c0135975060808c0135965060a08c01356149fa81614905565b955060c08c0135945060e08c0135614a118161497b565b93506101008c0135614a2281614989565b9a9d999c50979a969995989497509295919493610120830135935061014090920135919050565b60008083601f840112614a5b57600080fd5b5081356001600160401b03811115614a7257600080fd5b6020830191508360208260051b8501011115613cf757600080fd5b60008083601f840112614a9f57600080fd5b5081356001600160401b03811115614ab657600080fd5b602083019150836020828501011115613cf757600080fd5b600080600080600080600060a0888a031215614ae957600080fd5b8735965060208801356001600160401b03811115614b0657600080fd5b614b128a828b01614a49565b9097509550506040880135614b2681614905565b93506060880135925060808801356001600160401b03811115614b4857600080fd5b614b548a828b01614a8d565b989b979a50959850939692959293505050565b60008060008060008060008060c0898b031215614b8357600080fd5b883597506020890135965060408901356001600160401b03811115614ba757600080fd5b614bb38b828c01614a49565b9097509550506060890135614bc781614905565b93506080890135925060a08901356001600160401b03811115614be957600080fd5b614bf58b828c01614a8d565b999c989b5096995094979396929594505050565b602080825282518282018190526000918401906040840190835b81811015614c41578351835260209384019390920191600101614c23565b509095945050505050565b63ffffffff8116811461491a57600080fd5b600080600080600080600080610100898b031215614c7b57600080fd5b8835614c8681614905565b97506020890135614c9681614905565b965060408901359550606089013594506080890135935060a0890135925060c0890135915060e0890135614cc981614c4c565b809150509295985092959890939650565b6000806000806000806000806000806101408b8d031215614cfa57600080fd5b8a35614d0581614905565b995060208b0135985060408b0135975060608b0135965060808b0135614d2a81614905565b955060a08b0135945060c08b0135614d418161497b565b935060e08b0135614d5181614989565b999c989b509699959894979396509194610100810135936101209091013592509050565b600080600080600060608688031215614d8d57600080fd5b8535945060208601356001600160401b03811115614daa57600080fd5b614db688828901614a49565b90955093505060408601356001600160401b03811115614dd557600080fd5b614de188828901614a8d565b969995985093965092949392505050565b600080600080600060a08688031215614e0a57600080fd5b8535614e1581614905565b94506020860135614e2581614905565b94979496505050506040830135926060810135926080909101359150565b600080600080600080600060e0888a031215614e5e57600080fd5b8735614e6981614905565b96506020880135614e7981614905565b955060408801359450606088013593506080880135925060a0880135614e9e81614905565b96999598509396929591949193505060c09091013590565b6000806000806000806000806000806101208b8d031215614ed657600080fd5b8a35614ee181614905565b995060208b0135614ef181614905565b985060408b0135975060608b0135965060808b0135955060a08b0135945060c08b0135614f1d81614905565b935060e08b013592506101008b01356001600160401b03811115614f4057600080fd5b614f4c8d828e01614a8d565b915080935050809150509295989b9194979a5092959850565b60008060008060008060008060e0898b031215614f8157600080fd5b8835614f8c81614905565b97506020890135965060408901359550606089013594506080890135614fb181614905565b935060a0890135925060c08901356001600160401b03811115614be957600080fd5b60208082526018908201527f42726f776e46695632526f757465723a20455850495245440000000000000000604082015260600190565b6001600160a01b0397881681529590961660208601526040850193909352606084019190915260ff16608083015260a082015260c081019190915260e00190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561507357600080fd5b81356143a881614905565b6020808252601d908201527f42726f776e46695632526f757465723a20494e56414c49445f50415448000000604082015260600190565b6000602082840312156150c757600080fd5b81516143a88161497b565b634e487b7160e01b600052601160045260246000fd5b81810381811115612ced57612ced6150d2565b60006020828403121561510d57600080fd5b5051919050565b6020808252602b908201527f42726f776e46695632526f757465723a20494e53554646494349454e545f4f5560408201526a1514155517d05353d5539560aa1b606082015260800190565b60208082526027908201527f42726f776e46695632526f757465723a204558434553534956455f494e50555460408201526617d05353d5539560ca1b606082015260800190565b600080604083850312156151b957600080fd5b505080516020909101519092909150565b60208082526026908201527f42726f776e46695632526f757465723a20494e53554646494349454e545f415f604082015265105353d5539560d21b606082015260800190565b60208082526026908201527f42726f776e46695632526f757465723a20494e53554646494349454e545f425f604082015265105353d5539560d21b606082015260800190565b60005b83811015615271578181015183820152602001615259565b50506000910152565b6000825161528c818460208701615256565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b600081518084526152c4816020860160208601615256565b601f01601f19169290920160200192915050565b6000602082016020835280845180835260408501915060408160051b86010192506020860160005b8281101561533157603f1987860301845261531c8583516152ac565b94506020938401939190910190600101615300565b50929695505050505050565b80820180821115612ced57612ced6150d2565b84815283602082015260018060a01b038316604082015260806060820152600061157b60808301846152ac565b60008161538c5761538c6150d2565b506000190190565b80516001600160701b03811681146140c557600080fd5b6000806000606084860312156153c057600080fd5b6153c984615394565b92506153d760208501615394565b915060408401516153e781614c4c565b809150509250925092565b60006020828403121561540457600080fd5b81516143a881614c4c565b60006020828403121561542157600080fd5b81516001600160401b03811681146143a857600080fd5b8082028115828204841417612ced57612ced6150d2565b60208082526028908201527f42726f776e466956324c6962726172793a20494e53554646494349454e545f4c604082015267495155494449545960c01b606082015260800190565b6000826154b457634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156154cb57600080fd5b81516143a881614905565b604051601f8201601f191681016001600160401b03811182821017156154fe576154fe615296565b604052919050565b60006020828403121561551857600080fd5b81516001600160401b0381111561552e57600080fd5b8201601f8101841361553f57600080fd5b80516001600160401b0381111561555857615558615296565b8060051b615568602082016154d6565b9182526020818401810192908101908784111561558457600080fd5b6020850192505b83831015613bfc5782516001600160401b038111156155a957600080fd5b8501603f810189136155ba57600080fd5b60208101516001600160401b038111156155d6576155d6615296565b6155e9601f8201601f19166020016154d6565b8181526040838301018b10156155fe57600080fd5b61560f826020830160408601615256565b845250506020928301929091019061558b565b60006020828403121561563457600080fd5b81516143a881614989565b6001815b600184111561567a5780850481111561565e5761565e6150d2565b600184161561566c57908102905b60019390931c928002615643565b935093915050565b60008261569157506001612ced565b8161569e57506000612ced565b81600181146156b457600281146156be576156da565b6001915050612ced565b60ff8411156156cf576156cf6150d2565b50506001821b612ced565b5060208310610133831016604e8410600b84101617156156fd575081810a612ced565b61570a600019848461563f565b806000190482111561571e5761571e6150d2565b029392505050565b60006143a8838361568256fea26469706673582212204f92baa55ec032e83c4f900cf24a088b452a1f945e170cd0409dc24b88b24b4e64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f83045360000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a
-----Decoded View---------------
Arg [0] : _factory (address): 0x68bc42F886ddf6a4b0B90a9496493dA1f8304536
Arg [1] : _WETH (address): 0x3bd359C1119dA7Da1D913D1C4D2B7c461115433A
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000068bc42f886ddf6a4b0b90a9496493da1f8304536
Arg [1] : 0000000000000000000000003bd359c1119da7da1d913d1c4d2b7c461115433a
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.11
Net Worth in MON
Token Allocations
BNB
82.63%
MON
17.37%
Multichain Portfolio | 35 Chains
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.