Polygon Sponsored slots available. Book your slot here!
Source Code
Latest 25 from a total of 12,214 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Swap Tokens To T... | 50506015 | 788 days ago | IN | 0 POL | 0.11622849 | ||||
| Swap Tokens To T... | 50503103 | 788 days ago | IN | 0 POL | 0.0249968 | ||||
| Swap Tokens To T... | 50383624 | 791 days ago | IN | 0.1 POL | 0.0187973 | ||||
| Swap Tokens To T... | 50244994 | 794 days ago | IN | 0 POL | 0.00698523 | ||||
| Swap Tokens To T... | 50242210 | 794 days ago | IN | 0 POL | 0.00990992 | ||||
| Swap Tokens To T... | 50176666 | 796 days ago | IN | 0 POL | 0.04205571 | ||||
| Swap Tokens To T... | 50076096 | 799 days ago | IN | 3 POL | 0.01062267 | ||||
| Swap Tokens To T... | 50074868 | 799 days ago | IN | 0 POL | 0.01662978 | ||||
| Swap Tokens To T... | 49931680 | 802 days ago | IN | 0 POL | 0.07976947 | ||||
| Swap Tokens To T... | 49857518 | 804 days ago | IN | 0 POL | 0.03231778 | ||||
| Swap Tokens To T... | 49847872 | 804 days ago | IN | 0 POL | 0.0804347 | ||||
| Swap Tokens To T... | 49738158 | 807 days ago | IN | 0 POL | 0.10186044 | ||||
| Swap Tokens To T... | 49725921 | 807 days ago | IN | 0 POL | 0.04688941 | ||||
| Swap Tokens To T... | 49725695 | 807 days ago | IN | 0 POL | 0.05655213 | ||||
| Swap Tokens To T... | 49705569 | 808 days ago | IN | 0 POL | 0.07265469 | ||||
| Swap Tokens To T... | 49670629 | 809 days ago | IN | 16 POL | 0.04301912 | ||||
| Swap Tokens To T... | 49490186 | 813 days ago | IN | 0 POL | 0.0234673 | ||||
| Swap Tokens To T... | 49385192 | 816 days ago | IN | 0 POL | 0.03268787 | ||||
| Swap Tokens To T... | 49385105 | 816 days ago | IN | 2 POL | 0.03725107 | ||||
| Swap Tokens To T... | 49385054 | 816 days ago | IN | 0 POL | 0.06830923 | ||||
| Swap Tokens To T... | 49384638 | 816 days ago | IN | 2 POL | 0.07290604 | ||||
| Swap Tokens To T... | 49384579 | 816 days ago | IN | 0 POL | 0.0438068 | ||||
| Swap Tokens To T... | 49384524 | 816 days ago | IN | 3 POL | 0.02560564 | ||||
| Swap Tokens To T... | 49384488 | 816 days ago | IN | 0 POL | 0.05635603 | ||||
| Swap Tokens To T... | 49384428 | 816 days ago | IN | 3 POL | 0.05575131 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 50503103 | 788 days ago | 104.28938899 POL | ||||
| 50503103 | 788 days ago | 104.28938899 POL | ||||
| 50383624 | 791 days ago | 0.1 POL | ||||
| 50244994 | 794 days ago | 0.07414772 POL | ||||
| 50244994 | 794 days ago | 0.07414772 POL | ||||
| 50242210 | 794 days ago | 0.74342091 POL | ||||
| 50242210 | 794 days ago | 0.74342091 POL | ||||
| 50076096 | 799 days ago | 3 POL | ||||
| 50074868 | 799 days ago | 4.39340998 POL | ||||
| 50074868 | 799 days ago | 4.39340998 POL | ||||
| 49931680 | 802 days ago | 1.8 POL | ||||
| 49931680 | 802 days ago | 1.8 POL | ||||
| 49931680 | 802 days ago | 0.46645177 POL | ||||
| 49931680 | 802 days ago | 0.46645177 POL | ||||
| 49931680 | 802 days ago | 0.64917961 POL | ||||
| 49931680 | 802 days ago | 0.64917961 POL | ||||
| 49857518 | 804 days ago | 13.59709496 POL | ||||
| 49857518 | 804 days ago | 13.59709496 POL | ||||
| 49738158 | 807 days ago | 7.17843461 POL | ||||
| 49738158 | 807 days ago | 7.17843461 POL | ||||
| 49725921 | 807 days ago | 1.84884767 POL | ||||
| 49725921 | 807 days ago | 1.84884767 POL | ||||
| 49725695 | 807 days ago | 30.88118941 POL | ||||
| 49725695 | 807 days ago | 30.88118941 POL | ||||
| 49670629 | 809 days ago | 16 POL |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DZapAggregator
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 300 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
/*
Copyright 2022 https://www.dzap.io
SPDX-License-Identifier: MIT
*/
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./SwapHandler.sol";
import "./FeeModule.sol";
import "../interfaces/IDZapAggregator.sol";
contract DZapAggregator is SwapHandler, IDZapAggregator {
using SafeERC20 for IERC20;
constructor(
uint256[3] memory fees_,
address[] memory routers_,
Router[] memory routerDetails_,
address governor_,
address aggregationRouter_,
address wNative_,
address protocolFeeVault_,
address feeDiscountNft_
)
SwapHandler(routers_, routerDetails_, aggregationRouter_, wNative_)
FeeModule(fees_, governor_, protocolFeeVault_, feeDiscountNft_)
{}
function rescueFunds(
IERC20 token_,
address to_,
uint256 amount_
) external onlyGovernance {
require(to_ != address(0), "DZ001");
if (_isNative(token_)) {
_safeNativeTransfer(to_, amount_);
} else {
token_.safeTransfer(to_, amount_);
}
emit TokensRescued(to_, address(token_), amount_);
}
receive() external payable {}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "./ISwapHandler.sol";
interface IDZapAggregator is ISwapHandler {
/* ========= EVENTS ========= */
event TokensRescued(address indexed to, address indexed token, uint256 amount);
/* ========= RESTRICTED ========= */
function rescueFunds(
IERC20 token_,
address to_,
uint256 amount_
) external;
}/*
Copyright 2022 https://www.dzap.io
SPDX-License-Identifier: MIT
*/
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Router, FeeType } from "../common/Types.sol";
import "../utils/Governable.sol";
import "../tokens/DZapDiscountNft.sol";
import "../interfaces/IFeeModule.sol";
abstract contract FeeModule is Governable, IFeeModule {
address public protocolFeeVault;
uint256 public nextProjectId;
DZapDiscountNft public feeDiscountNft;
mapping(FeeType => uint256) public protocolFeeBps;
mapping(uint256 => mapping(FeeType => uint256)) public projectFeeBps; // projectId -> FeeBps
mapping(uint256 => address) public projectFeeVault; // projectId -> fee vault
uint256 public constant MAX_FEE = 5000; // 5%, max project fee
uint256 public constant BPS_DENOMINATOR = 10000;
/* ========= CONSTRUCTOR ========= */
constructor(
uint256[3] memory fees_,
address governor_,
address protocolFeeVault_,
address feeDiscountNft_
) Governable(governor_) {
require(protocolFeeVault_ != address(0) && feeDiscountNft_ != address(0), "DZF001");
protocolFeeVault = protocolFeeVault_;
feeDiscountNft = DZapDiscountNft(feeDiscountNft_);
protocolFeeBps[FeeType.BATCH_SWAP] = fees_[0];
protocolFeeBps[FeeType.BATCH_SWAP_LP] = fees_[1];
protocolFeeBps[FeeType.BATCH_TRANSFER] = fees_[2];
}
/* ========= RESTRICTED ========= */
function updateProtocolFee(FeeType[] calldata feeTypes_, uint256[] calldata fees_) external onlyGovernance {
for (uint256 i; i < feeTypes_.length; i++) {
protocolFeeBps[feeTypes_[i]] = fees_[i];
}
emit ProtocolFeeUpdated();
}
function updateProtocolFeeVault(address newProtocolFeeVault_) external onlyGovernance {
require(newProtocolFeeVault_ != address(0), "DZF001");
protocolFeeVault = newProtocolFeeVault_;
emit ProtocolFeeVaultUpdated();
}
function addProject(uint256[3] calldata fees_, address feeVault_) external onlyGovernance {
require(feeVault_ != address(0), "DZF001");
require(fees_[0] <= MAX_FEE && fees_[1] <= MAX_FEE && fees_[2] <= MAX_FEE, "DZF002");
projectFeeBps[nextProjectId][FeeType.BATCH_SWAP] = fees_[0];
projectFeeBps[nextProjectId][FeeType.BATCH_SWAP_LP] = fees_[1];
projectFeeBps[nextProjectId][FeeType.BATCH_TRANSFER] = fees_[2];
projectFeeVault[nextProjectId] = feeVault_;
emit ProjectAdded(nextProjectId++);
}
// make fee vault 0
function disableProject(uint256 projectId_) external onlyGovernance {
require(projectId_ < nextProjectId, "DZF003");
require(projectFeeVault[projectId_] != address(0), "DZF004");
projectFeeVault[projectId_] = address(0);
emit ProjectStatusDisabled(projectId_);
}
function updateProjectFee(
uint256 projectId_,
FeeType[] memory feeTypes_,
uint256[] memory fees_
) external onlyGovernance {
require(projectId_ < nextProjectId, "DZF003");
for (uint256 i; i < feeTypes_.length; i++) {
projectFeeBps[projectId_][feeTypes_[i]] = fees_[i];
}
emit ProjectFeeUpdated(projectId_);
}
// enable a disabled project
// update vault
function updateProjectFeeVault(uint256 projectId_, address feeVault_) external onlyGovernance {
require(projectId_ < nextProjectId, "DZF003");
require(feeVault_ != address(0), "DZF001");
projectFeeVault[projectId_] = feeVault_;
emit ProjectFeeVaultUpdated(projectId_);
}
/* ========= internal ========= */
function _getFeeDetail(
uint256 projectId_,
uint256 nftId_,
FeeType feeType_
)
internal
view
returns (
uint256, // protocolFeeBps
uint256, // projectFeeBps
address // projectFeeVault
)
{
require(projectId_ < nextProjectId && projectFeeVault[projectId_] != address(0), "DZF003");
uint256 protocolFee = protocolFeeBps[feeType_];
if (nftId_ == 0 || protocolFee == 0) {
return (protocolFee, projectFeeBps[projectId_][feeType_], projectFeeVault[projectId_]);
}
require(feeDiscountNft.balanceOf(_msgSender(), nftId_) > 0, "DZF005");
(uint256 discountedFeeBps, uint256 expiry) = feeDiscountNft.discountDetails(nftId_);
if (block.timestamp < expiry) {
protocolFee -= ((protocolFee * discountedFeeBps) / BPS_DENOMINATOR);
}
// require(block.timestamp < expiry, "Expired");
// protocolFee -= ((protocolFee * discountedFeeBps) / BPS_DENOMINATOR);
return (protocolFee, projectFeeBps[projectId_][feeType_], projectFeeVault[projectId_]);
}
function _calculateFeeAmount(
uint256 amount_,
uint256 protocolFeeBps_,
uint256 projectFeeBps_
)
internal
pure
returns (
uint256, // returnAmount
uint256, // protocolFee
uint256 // projectFee
)
{
uint256 protocolFee = (amount_ * protocolFeeBps_) / BPS_DENOMINATOR;
uint256 projectFee = (amount_ * projectFeeBps_) / BPS_DENOMINATOR;
return (amount_ - (protocolFee + projectFee), protocolFee, projectFee);
}
}/*
Copyright 2022 https://www.dzap.io
SPDX-License-Identifier: MIT
*/
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/IAggregationRouterV4.sol";
import "../interfaces/IWNATIVE.sol";
import "../interfaces/IUniswapV2Router02.sol";
import "../interfaces/IUniswapV2Pair.sol";
import "./FeeModule.sol";
import "../utils/Permitable.sol";
import "../libraries/Math.sol";
import "../interfaces/ISwapHandler.sol";
import { Router, FeeType, Token, SwapInfo, SwapDescription, SwapDetails, TransferDetails, TransferInfo, LpSwapDetails, WNativeSwapDetails, LPSwapInfo, OutputLp, UnoSwapDetails, InputTokenData } from "../common/Types.sol";
abstract contract SwapHandler is FeeModule, Permitable, ISwapHandler {
using SafeERC20 for IERC20;
mapping(address => Router) public routers;
address public immutable wNative;
address public immutable AGGREGATION_ROUTER;
IERC20 private constant _ZERO_ADDRESS = IERC20(address(0));
IERC20 private constant _ETH_ADDRESS = IERC20(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
uint256 private constant _PARTIAL_FILL = 1 << 0;
/* ========= CONSTRUCTOR ========= */
constructor(
address[] memory routers_,
Router[] memory routerDetails_,
address aggregationRouter_,
address wNative_
) {
require(wNative_ != address(0) && aggregationRouter_ != address(0), "DZS0015");
AGGREGATION_ROUTER = aggregationRouter_;
wNative = wNative_;
for (uint256 i; i < routers_.length; ++i) {
address router = routers_[i];
require(router != address(0), "DZS0016");
routers[router] = routerDetails_[i];
}
}
/* ========= VIEWS ========= */
function calculateOptimalSwapAmount(
uint256 amountA_,
uint256 amountB_,
uint256 reserveA_,
uint256 reserveB_,
address router_
) public view returns (uint256) {
require(amountA_ * reserveB_ >= amountB_ * reserveA_, "DZS0014");
uint256 routerFeeBps = routers[router_].fees;
uint256 a = BPS_DENOMINATOR - routerFeeBps;
uint256 b = (((BPS_DENOMINATOR * 2) - routerFeeBps)) * reserveA_;
uint256 _c = (amountA_ * reserveB_) - (amountB_ * reserveA_);
uint256 c = ((_c * BPS_DENOMINATOR) / (amountB_ + reserveB_)) * reserveA_;
uint256 d = a * c * 4;
uint256 e = Math.sqrt((b * b) + d);
uint256 numerator = e - b;
uint256 denominator = a * 2;
return numerator / denominator;
}
/* ========= RESTRICTED ========= */
function updateRouters(address[] calldata routers_, Router[] calldata routerDetails_) external onlyGovernance {
for (uint256 i; i < routers_.length; ++i) {
address router = routers_[i];
require(router != address(0), "DZS0016");
routers[router] = routerDetails_[i];
}
emit RoutersUpdated(routers_, routerDetails_);
}
/* ========= PUBLIC ========= */
// can return both native and wNative
function swapTokensToTokens(
SwapDetails[] calldata data_,
address recipient_,
uint256 projectId_,
uint256 nftId_
) external payable {
require(recipient_ != address(0), "DZS001");
SwapInfo[] memory swapInfo = new SwapInfo[](data_.length);
(uint256 tempProtocolFeeBps, uint256 tempProjectFeeBps, address projectFeeVault) = _getFeeDetail(
projectId_,
nftId_,
FeeType.BATCH_SWAP
);
for (uint256 i; i < data_.length; ++i) {
SwapDetails memory data = data_[i];
require(data.desc.dstReceiver == address(0), "DZS002");
require(data.desc.flags & _PARTIAL_FILL == 0, "DZS003");
uint256 value;
if (_isNative(data.desc.srcToken)) {
value = data.desc.amount;
} else {
_transferAndApprove(data.permit, data.desc.srcToken, AGGREGATION_ROUTER, data.desc.amount);
}
try
IAggregationRouterV4(AGGREGATION_ROUTER).swap{ value: value }(data.executor, data.desc, data.routeData)
returns (uint256 returnAmount, uint256) {
require(returnAmount >= data.desc.minReturnAmount, "DZS004");
swapInfo[i] = SwapInfo(data.desc.srcToken, data.desc.dstToken, data.desc.amount, returnAmount);
_swapTransferDstTokens(
data.desc.dstToken,
recipient_,
projectFeeVault,
returnAmount,
tempProtocolFeeBps,
tempProjectFeeBps
);
} catch Error(string memory) {
swapInfo[i] = SwapInfo(data.desc.srcToken, data.desc.dstToken, data.desc.amount, 0);
if (_isNative(data.desc.srcToken)) {
_safeNativeTransfer(_msgSender(), data.desc.amount);
} else {
data.desc.srcToken.safeApprove(AGGREGATION_ROUTER, 0);
data.desc.srcToken.safeTransfer(_msgSender(), data.desc.amount);
}
}
}
emit TokensSwapped(_msgSender(), recipient_, swapInfo, [tempProtocolFeeBps, tempProjectFeeBps]);
}
// can return only native when dest is wNative
function unoSwapTokensToTokens(
UnoSwapDetails[] calldata swapData_,
address recipient_,
uint256 projectId_,
uint256 nftId_
) external payable {
require(recipient_ != address(0), "DZS001");
SwapInfo[] memory swapInfo = new SwapInfo[](swapData_.length);
(uint256 tempProtocolFeeBps, uint256 tempProjectFeeBps, address projectFeeVault) = _getFeeDetail(
projectId_,
nftId_,
FeeType.BATCH_SWAP
);
_nativeDeposit();
// lp swap
for (uint256 i; i < swapData_.length; ++i) {
UnoSwapDetails memory data = swapData_[i];
IERC20 srcToken = IERC20(data.path[0]);
IERC20 dstToken = IERC20(data.path[data.path.length - 1]);
require(!_isNative(dstToken), "DZS008");
if (_isNative(srcToken)) {
data.path[0] = wNative;
IWNATIVE(wNative).approve(data.router, data.amount);
} else {
_transferAndApprove(data.permit, srcToken, data.router, data.amount);
}
try
IUniswapV2Router02(data.router).swapExactTokensForTokens(
data.amount,
data.minReturnAmount,
data.path,
address(this),
block.timestamp + 60
)
returns (uint256[] memory amountOuts) {
uint256 returnAmount = amountOuts[amountOuts.length - 1];
require(returnAmount >= data.minReturnAmount, "DZS004");
swapInfo[i] = SwapInfo(srcToken, dstToken, data.amount, returnAmount);
_unoSwapTransferDstTokens(
dstToken,
recipient_,
projectFeeVault,
returnAmount,
tempProtocolFeeBps,
tempProjectFeeBps
);
} catch Error(string memory) {
swapInfo[i] = SwapInfo(srcToken, dstToken, data.amount, 0);
if (_isNative(srcToken)) {
IWNATIVE(wNative).withdraw(data.amount);
_safeNativeTransfer(_msgSender(), data.amount);
} else {
srcToken.safeApprove(data.router, 0);
srcToken.safeTransfer(_msgSender(), data.amount);
}
}
}
emit TokensSwapped(_msgSender(), recipient_, swapInfo, [tempProtocolFeeBps, tempProjectFeeBps]);
}
// can return both native and wNative
function swapLpToTokens(
LpSwapDetails[] calldata lpSwapDetails_,
WNativeSwapDetails[] calldata wEthSwapDetails_,
address recipient_,
uint256 projectId_,
uint256 nftId_
) external {
require(recipient_ != address(0), "DZS001");
require(wEthSwapDetails_.length > 0, "DZS009");
// as in the final swap all the wNative tokens are considered
// require(IWNATIVE(wNative).balanceOf(address(this)) == 0, "DZS0010");
LPSwapInfo memory swapInfo;
swapInfo.lpInput = new Token[](lpSwapDetails_.length);
swapInfo.lpOutput = new Token[](wEthSwapDetails_.length + 1);
(uint256 tempProtocolFeeBps, uint256 tempProjectFeeBps, address projectFeeVault) = _getFeeDetail(
projectId_,
nftId_,
FeeType.BATCH_SWAP_LP
);
// swap lp to weth
swapInfo.lpInput = _swapLpToWNative(lpSwapDetails_);
// swap weth to tokens
swapInfo.lpOutput = _swapWNativeToDstTokens(
wEthSwapDetails_,
recipient_,
projectFeeVault,
IWNATIVE(wNative).balanceOf(address(this)),
tempProtocolFeeBps,
tempProjectFeeBps
);
emit LpSwapped(_msgSender(), recipient_, swapInfo, [tempProtocolFeeBps, tempProjectFeeBps]);
}
function swapTokensToLp(
SwapDetails[] calldata data_,
LpSwapDetails[] calldata lpSwapDetails_,
OutputLp calldata outputLpDetails_,
address recipient_,
uint256 projectId_,
uint256 nftId_
) public payable {
require(recipient_ != address(0), "DZS001");
require(routers[outputLpDetails_.router].isSupported, "DZS005");
Token[] memory input = new Token[](data_.length + lpSwapDetails_.length + 1);
(uint256 tempProtocolFeeBps, uint256 tempProjectFeeBps, address projectFeeVault) = _getFeeDetail(
projectId_,
nftId_,
FeeType.BATCH_SWAP_LP
);
address token0 = IUniswapV2Pair(outputLpDetails_.lpToken).token0();
address token1 = IUniswapV2Pair(outputLpDetails_.lpToken).token1();
uint256 i;
// native to wNative
if (msg.value > 0) {
IWNATIVE(wNative).deposit{ value: msg.value }();
input[input.length - 1] = Token(address(0), msg.value);
}
// erc to wNative
for (i; i < data_.length; ++i) {
SwapDetails memory data = data_[i];
address srcToken = address(data.desc.srcToken);
if (srcToken != wNative && srcToken != token0 && srcToken != token1) {
require(data.desc.dstReceiver == address(0), "DZS002");
require(data.desc.flags & _PARTIAL_FILL == 0, "DZS003"); // partial fill not allowed
require(!_isNative(data.desc.srcToken), "DZS0011"); // src cant be native
require(data.desc.dstToken == IERC20(wNative), "DZS0012");
_transferAndApprove(data.permit, data.desc.srcToken, AGGREGATION_ROUTER, data.desc.amount);
(uint256 returnAmount, ) = IAggregationRouterV4(AGGREGATION_ROUTER).swap(
data.executor,
data.desc,
data.routeData
);
require(returnAmount > data.desc.minReturnAmount, "DZS004");
} else {
_permit(srcToken, data.permit);
data.desc.srcToken.safeTransferFrom(_msgSender(), address(this), data.desc.amount);
}
input[i] = Token(srcToken, data.desc.amount);
}
// lp to wNative
for (uint256 j; j < lpSwapDetails_.length; ++j) {
LpSwapDetails memory details = lpSwapDetails_[j];
require(routers[details.router].isSupported, "DZS0013");
// require(outputLpDetails_.lpToken != details.token, "DZS0014");
address tokenA = IUniswapV2Pair(details.token).token0();
address tokenB = IUniswapV2Pair(details.token).token1();
(uint256 amountA, uint256 amountB) = _removeLiquidity(details, tokenA, tokenB, details.router);
_swapExactTokensForTokens(
tokenA,
amountA,
details.tokenAToPath,
tokenA != wNative && tokenA != token0 && tokenA != token1,
details.router
);
_swapExactTokensForTokens(
tokenB,
amountB,
details.tokenBToPath,
tokenB != wNative && tokenB != token0 && tokenB != token1,
details.router
);
input[i + j] = Token(details.token, details.amount);
}
uint256[3] memory returnAmounts = _addOptimalLiquidity(outputLpDetails_, token0, token1);
require(returnAmounts[0] >= outputLpDetails_.minReturnAmount, "DZS004");
_transferOutputLP(
IERC20(outputLpDetails_.lpToken),
recipient_,
projectFeeVault,
returnAmounts[0],
tempProtocolFeeBps,
tempProjectFeeBps
);
// Transfer dust
if (returnAmounts[1] > 0) {
IERC20(token0).safeTransfer(_msgSender(), returnAmounts[1]);
}
if (returnAmounts[2] > 0) {
IERC20(token1).safeTransfer(_msgSender(), returnAmounts[2]);
}
emit LiquidityAdded(
_msgSender(),
recipient_,
input,
outputLpDetails_.lpToken,
returnAmounts,
[tempProtocolFeeBps, tempProjectFeeBps]
);
}
function batchTransfer(
TransferDetails[] calldata data_,
uint256 projectId_,
uint256 nftId_
) external payable {
TransferInfo[] memory transferInfo = new TransferInfo[](data_.length);
(uint256 tempProtocolFeeBps, uint256 tempProjectFeeBps, address projectFeeVault) = _getFeeDetail(
projectId_,
nftId_,
FeeType.BATCH_TRANSFER
);
uint256 availableBalance = msg.value;
for (uint256 i; i < data_.length; ++i) {
TransferDetails memory details = data_[i];
require(details.recipient != address(0), "DZS001");
Token[] memory tokenInfo = new Token[](details.data.length);
for (uint256 j; j < details.data.length; ++j) {
InputTokenData memory data = details.data[j];
(uint256 amountAfterFee, uint256 protocolFee, uint256 projectFee) = _calculateFeeAmount(
data.amount,
tempProtocolFeeBps,
tempProjectFeeBps
);
tokenInfo[j] = Token(address(data.token), data.amount);
if (_isNative(data.token)) {
require(availableBalance >= data.amount, "DZS003");
availableBalance -= data.amount;
_safeNativeTransfer(details.recipient, amountAfterFee);
if (protocolFee > 0) _safeNativeTransfer(protocolFeeVault, protocolFee);
if (projectFee > 0) _safeNativeTransfer(projectFeeVault, projectFee);
} else {
_permit(address(data.token), data.permit);
data.token.safeTransferFrom(_msgSender(), details.recipient, amountAfterFee);
if (protocolFee > 0) data.token.safeTransferFrom(_msgSender(), protocolFeeVault, protocolFee);
if (projectFee > 0) data.token.safeTransferFrom(_msgSender(), projectFeeVault, projectFee);
}
}
transferInfo[i] = TransferInfo(details.recipient, tokenInfo);
}
require(availableBalance == 0, "DZS006");
emit TokensTransferred(_msgSender(), transferInfo, [tempProtocolFeeBps, tempProjectFeeBps]);
}
/* ========= INTERNAL/PRIVATE ========= */
function _isNative(IERC20 token_) internal pure returns (bool) {
return (token_ == _ZERO_ADDRESS || token_ == _ETH_ADDRESS);
}
function _safeNativeTransfer(address to_, uint256 amount_) internal {
(bool sent, ) = to_.call{ value: amount_ }(new bytes(0));
require(sent, "DZS007");
}
function _nativeDeposit() private {
if (msg.value > 0) {
IWNATIVE(wNative).deposit{ value: msg.value }();
}
}
function _transferAndApprove(
bytes memory permit_,
IERC20 srcToken_,
address router_,
uint256 amount_
) private {
_permit(address(srcToken_), permit_);
srcToken_.safeTransferFrom(_msgSender(), address(this), amount_);
srcToken_.safeApprove(router_, amount_);
}
function _swapTransferDstTokens(
IERC20 token_,
address recipient_,
address projectFeeVault,
uint256 returnAmount,
uint256 tempProtocolFeeBps,
uint256 tempProjectFeeBps
) private {
(uint256 amountAfterFee, uint256 protocolFee, uint256 projectFee) = _calculateFeeAmount(
returnAmount,
tempProtocolFeeBps,
tempProjectFeeBps
);
if (_isNative(token_)) {
_safeNativeTransfer(recipient_, amountAfterFee);
if (protocolFee > 0) _safeNativeTransfer(protocolFeeVault, protocolFee);
if (projectFee > 0) _safeNativeTransfer(projectFeeVault, projectFee);
} else {
token_.safeTransfer(recipient_, amountAfterFee);
if (protocolFee > 0) token_.safeTransfer(protocolFeeVault, protocolFee);
if (projectFee > 0) token_.safeTransfer(projectFeeVault, projectFee);
}
}
function _unoSwapTransferDstTokens(
IERC20 token_,
address recipient_,
address projectFeeVault,
uint256 returnAmount,
uint256 tempProtocolFeeBps,
uint256 tempProjectFeeBps
) private {
(uint256 amountAfterFee, uint256 protocolFee, uint256 projectFee) = _calculateFeeAmount(
returnAmount,
tempProtocolFeeBps,
tempProjectFeeBps
);
if (address(token_) == wNative) {
IWNATIVE(wNative).withdraw(returnAmount);
_safeNativeTransfer(recipient_, amountAfterFee);
if (protocolFee > 0) _safeNativeTransfer(protocolFeeVault, protocolFee);
if (projectFee > 0) _safeNativeTransfer(projectFeeVault, projectFee);
} else {
token_.safeTransfer(recipient_, amountAfterFee);
if (protocolFee > 0) token_.safeTransfer(protocolFeeVault, protocolFee);
if (projectFee > 0) token_.safeTransfer(projectFeeVault, projectFee);
}
}
function _transferOutputLP(
IERC20 lpToken,
address recipient_,
address projectFeeVault,
uint256 returnAmount,
uint256 tempProtocolFeeBps,
uint256 tempProjectFeeBps
) private {
(uint256 amountAfterFee, uint256 protocolFee, uint256 projectFee) = _calculateFeeAmount(
returnAmount,
tempProtocolFeeBps,
tempProjectFeeBps
);
lpToken.safeTransfer(recipient_, amountAfterFee);
if (protocolFee > 0) lpToken.safeTransfer(protocolFeeVault, protocolFee);
if (projectFee > 0) lpToken.safeTransfer(projectFeeVault, projectFee);
}
function _swapWNativeForToken(
uint256 amount_,
address[] memory path_,
address router_
) private returns (uint256) {
IWNATIVE(wNative).approve(router_, amount_);
uint256[] memory amountOuts = IUniswapV2Router02(router_).swapExactTokensForTokens(
amount_,
0,
path_,
address(this),
block.timestamp + 60
);
return amountOuts[amountOuts.length - 1];
}
function _swapExactTokensForTokens(
address token_,
uint256 amount_,
address[] memory path_,
bool executeSwap_,
address router_
) private {
if (executeSwap_) {
IERC20(token_).approve(router_, amount_);
IUniswapV2Router02(router_).swapExactTokensForTokens(
amount_,
0,
path_,
address(this),
block.timestamp + 60
);
}
}
// used in swapLpToTokens
function _swapLpToWNative(LpSwapDetails[] calldata lpSwapDetails_) internal returns (Token[] memory) {
Token[] memory swapInfo = new Token[](lpSwapDetails_.length);
for (uint256 i; i < lpSwapDetails_.length; ++i) {
LpSwapDetails memory details = lpSwapDetails_[i];
require(routers[details.router].isSupported, "DZS005");
address tokenA = IUniswapV2Pair(details.token).token0();
address tokenB = IUniswapV2Pair(details.token).token1();
(uint256 amountA, uint256 amountB) = _removeLiquidity(details, tokenA, tokenB, details.router);
_swapExactTokensForTokens(tokenA, amountA, details.tokenAToPath, tokenA != wNative, details.router);
_swapExactTokensForTokens(tokenB, amountB, details.tokenBToPath, tokenB != wNative, details.router);
swapInfo[i] = Token(details.token, details.amount);
}
return swapInfo;
}
// used in swapLpToTokens
function _swapWNativeToDstTokens(
WNativeSwapDetails[] calldata wEthSwapDetails_,
address recipient_,
address projectFeeVault,
uint256 wNativeBalance,
uint256 tempProtocolFeeBps,
uint256 tempProjectFeeBps
) private returns (Token[] memory) {
Token[] memory swapInfo = new Token[](wEthSwapDetails_.length);
// swap weth to tokens
// for last swap all the leftOver tokens are considered
for (uint256 i; i < wEthSwapDetails_.length; ++i) {
WNativeSwapDetails memory details = wEthSwapDetails_[i];
uint256 wNativeAmount = i != wEthSwapDetails_.length - 1
? (wNativeBalance * details.sizeBps) / BPS_DENOMINATOR
: IWNATIVE(wNative).balanceOf(address(this));
if (details.nativeToOutputPath.length == 0) {
// native
require(wNativeAmount >= details.minReturnAmount, "DZS004");
(uint256 amountAfterFee, uint256 protocolFee, uint256 projectFee) = _calculateFeeAmount(
wNativeAmount,
tempProtocolFeeBps,
tempProjectFeeBps
);
IWNATIVE(wNative).withdraw(wNativeAmount);
_safeNativeTransfer(recipient_, amountAfterFee);
if (protocolFee > 0) _safeNativeTransfer(protocolFeeVault, protocolFee);
if (projectFee > 0) _safeNativeTransfer(projectFeeVault, projectFee);
swapInfo[i] = Token(address(0), wNativeAmount);
} else {
// wNative and others
address destToken = details.nativeToOutputPath[details.nativeToOutputPath.length - 1];
uint256 amountOut = wNativeAmount;
if (destToken != wNative) {
require(routers[details.router].isSupported, "DZS005");
amountOut = _swapWNativeForToken(wNativeAmount, details.nativeToOutputPath, details.router);
}
require(amountOut >= details.minReturnAmount, "DZS004");
(uint256 amountAfterFee, uint256 protocolFee, uint256 projectFee) = _calculateFeeAmount(
amountOut,
tempProtocolFeeBps,
tempProjectFeeBps
);
IERC20(destToken).safeTransfer(recipient_, amountAfterFee);
if (protocolFee > 0) IERC20(destToken).safeTransfer(protocolFeeVault, protocolFee);
if (projectFee > 0) IERC20(destToken).safeTransfer(projectFeeVault, projectFee);
swapInfo[i] = Token(destToken, amountOut);
}
}
return swapInfo;
}
function _removeLiquidity(
LpSwapDetails memory details_,
address tokenA_,
address tokenB_,
address router_
) private returns (uint256 amountA, uint256 amountB) {
_transferAndApprove(details_.permit, IERC20(details_.token), router_, details_.amount);
(amountA, amountB) = IUniswapV2Router02(router_).removeLiquidity(
tokenA_,
tokenB_,
details_.amount,
0,
0,
address(this),
block.timestamp + 60
);
}
function _addOptimalLiquidity(
OutputLp calldata lpDetails_,
address tokenA_,
address tokenB_
) private returns (uint256[3] memory) {
uint256 wNativeBalance = IWNATIVE(wNative).balanceOf(address(this));
// swap 50-50
if (wNativeBalance > 0) {
if (tokenA_ != wNative)
_swapWNativeForToken(wNativeBalance / 2, lpDetails_.nativeToToken0, lpDetails_.router);
if (tokenB_ != wNative)
_swapWNativeForToken(
wNativeBalance - (wNativeBalance / 2),
lpDetails_.nativeToToken1,
lpDetails_.router
);
}
// do optimal swap
(uint256 amountA, uint256 amountB) = _optimalSwapForAddingLiquidity(
lpDetails_.lpToken,
tokenA_,
tokenB_,
IERC20(tokenA_).balanceOf(address(this)),
IERC20(tokenB_).balanceOf(address(this)),
lpDetails_.router
);
IERC20(tokenA_).approve(lpDetails_.router, amountA);
IERC20(tokenB_).approve(lpDetails_.router, amountB);
// add liquidity
(uint256 addedToken0, uint256 addedToken1, uint256 lpAmount) = IUniswapV2Router02(lpDetails_.router)
.addLiquidity(tokenA_, tokenB_, amountA, amountB, 0, 0, address(this), block.timestamp + 60);
return ([lpAmount, amountA - addedToken0, amountB - addedToken1]);
}
function _optimalSwapForAddingLiquidity(
address lp,
address tokenA_,
address tokenB_,
uint256 amountA_,
uint256 amountB_,
address router_
) private returns (uint256, uint256) {
(uint256 reserveA, uint256 reserveB, ) = IUniswapV2Pair(lp).getReserves();
if (reserveA * amountB_ == reserveB * amountA_) {
return (amountA_, amountB_);
}
bool reverse = reserveA * amountB_ > reserveB * amountA_;
uint256 optimalSwapAmount = reverse
? calculateOptimalSwapAmount(amountB_, amountA_, reserveB, reserveA, router_)
: calculateOptimalSwapAmount(amountA_, amountB_, reserveA, reserveB, router_);
address[] memory path = new address[](2);
(path[0], path[1]) = reverse ? (tokenB_, tokenA_) : (tokenA_, tokenB_);
if (optimalSwapAmount > 0) {
IERC20(path[0]).approve(router_, optimalSwapAmount);
uint256[] memory amountOuts = IUniswapV2Router02(router_).swapExactTokensForTokens(
optimalSwapAmount,
0,
path,
address(this),
block.timestamp + 60
);
if (reverse) {
amountA_ += amountOuts[amountOuts.length - 1];
amountB_ -= optimalSwapAmount;
} else {
amountA_ -= optimalSwapAmount;
amountB_ += amountOuts[amountOuts.length - 1];
}
}
return (amountA_, amountB_);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { SwapInfo, LPSwapInfo, Token, TransferInfo, Router, SwapDetails, UnoSwapDetails, LpSwapDetails, WNativeSwapDetails, OutputLp, TransferDetails } from "../common/Types.sol";
import "./IFeeModule.sol";
interface ISwapHandler is IFeeModule {
/* ========= EVENTS ========= */
event RoutersUpdated(address[] routers, Router[] details);
event TokensSwapped(address indexed sender, address indexed recipient, SwapInfo[] swapInfo, uint256[2] feeBps); // protocolFeeBps, projectFeeBPS
event LpSwapped(address indexed sender, address indexed recipient, LPSwapInfo swapInfo, uint256[2] feeBps);
event LiquidityAdded(
address indexed sender,
address indexed recipient,
Token[] inputTokens, // both erc20 and lp
address outputLp,
uint256[3] returnAmounts, // outputLP, unspentAmount0, unspentAmount1
uint256[2] feeBps
);
event TokensTransferred(address indexed sender, TransferInfo[] details, uint256[2] feeBps);
/* ========= VIEWS ========= */
function calculateOptimalSwapAmount(
uint256 amountA_,
uint256 amountB_,
uint256 reserveA_,
uint256 reserveB_,
address router_
) external view returns (uint256);
/* ========= RESTRICTED ========= */
function updateRouters(address[] calldata routers_, Router[] calldata routerDetails_) external;
/* ========= PUBLIC ========= */
function swapTokensToTokens(
SwapDetails[] calldata data_,
address recipient_,
uint256 projectId_,
uint256 nftId_
) external payable;
function unoSwapTokensToTokens(
UnoSwapDetails[] calldata swapData_,
address recipient_,
uint256 projectId_,
uint256 nftId_
) external payable;
function swapLpToTokens(
LpSwapDetails[] calldata lpSwapDetails_,
WNativeSwapDetails[] calldata wEthSwapDetails_,
address recipient_,
uint256 projectId_,
uint256 nftId_
) external;
function swapTokensToLp(
SwapDetails[] calldata data_,
LpSwapDetails[] calldata lpSwapDetails_,
OutputLp calldata outputLpDetails_,
address recipient_,
uint256 projectId_,
uint256 nftId_
) external payable;
function batchTransfer(
TransferDetails[] calldata data_,
uint256 projectId_,
uint256 nftId_
) external payable;
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
/*
Copyright 2022 https://www.dzap.io
SPDX-License-Identifier: MIT
*/
pragma solidity 0.8.17;
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "../interfaces/IAggregationExecutor.sol";
enum FeeType {
BATCH_SWAP,
BATCH_SWAP_LP,
BATCH_TRANSFER
}
struct SwapDescription {
IERC20 srcToken;
IERC20 dstToken;
address payable srcReceiver;
address payable dstReceiver;
uint256 amount;
uint256 minReturnAmount;
uint256 flags;
bytes permit;
}
struct LpSwapDetails {
address router;
address token;
uint256 amount;
bytes permit;
address[] tokenAToPath;
address[] tokenBToPath;
}
struct WNativeSwapDetails {
address router;
uint256 sizeBps; // weth %
uint256 minReturnAmount;
address[] nativeToOutputPath;
}
// erc + native
struct SwapDetails {
IAggregationExecutor executor;
SwapDescription desc;
bytes routeData;
bytes permit;
}
// for direct swap using uniswap v2 forks
// even for wNative refund is in native
// even if dstToken is wNative, native token is given
struct UnoSwapDetails {
address router;
uint256 amount;
uint256 minReturnAmount;
address[] path;
bytes permit;
}
struct OutputLp {
address router;
address lpToken;
uint256 minReturnAmount;
address[] nativeToToken0;
address[] nativeToToken1;
}
struct TransferDetails {
address recipient;
InputTokenData[] data;
}
struct Token {
address token;
uint256 amount;
}
struct InputTokenData {
IERC20 token;
uint256 amount;
bytes permit;
}
// logs swapTokensToTokens unoSwapTokensToTokens
struct SwapInfo {
IERC20 srcToken;
IERC20 dstToken;
uint256 amount;
uint256 returnAmount;
}
// logs swapLpToTokens
struct LPSwapInfo {
Token[] lpInput; // srcToken, amount
Token[] lpOutput; // dstToken, returnAmount
}
// logs batchTransfer
struct TransferInfo {
address recipient;
Token[] data;
}
struct Router {
bool isSupported;
uint256 fees;
}
struct NftData {
uint256 discountedFeeBps;
uint256 expiry;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { FeeType } from "../common/Types.sol";
interface IFeeModule {
/* ========= EVENTS ========= */
event ProtocolFeeVaultUpdated();
event ProtocolFeeUpdated();
event ProjectAdded(uint256 indexed id);
event ProjectStatusDisabled(uint256 indexed id);
event ProjectFeeUpdated(uint256 indexed id);
event ProjectFeeVaultUpdated(uint256 indexed id);
/* ========= RESTRICTED ========= */
function updateProtocolFee(FeeType[] calldata feeTypes_, uint256[] calldata fees_) external;
function updateProtocolFeeVault(address newProtocolFeeVault_) external;
function addProject(uint256[3] calldata fees_, address feeVault_) external;
function disableProject(uint256 projectId_) external;
function updateProjectFee(
uint256 projectId_,
FeeType[] memory feeTypes_,
uint256[] memory fees_
) external;
function updateProjectFeeVault(uint256 projectId_, address feeVault_) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IAggregationExecutor {
/// @notice Make calls on `msgSender` with specified data
function callBytes(address msgSender, bytes calldata data) external payable; // 0x2636f7f8
}// 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);
}/*
Copyright 2022 https://www.dzap.io
SPDX-License-Identifier: MIT
*/
pragma solidity 0.8.17;
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
abstract contract Governable is Context {
address private _governance;
event GovernanceChanged(address indexed formerGov, address indexed newGov);
/**
* @dev Throws if called by any account other than the governance.
*/
modifier onlyGovernance() {
require(governance() == _msgSender(), "DZG001");
_;
}
/**
* @dev Initializes the contract setting the deployer as the initial governance.
*/
constructor(address governance_) {
require(governance_ != address(0), "DZG002");
_governance = governance_;
emit GovernanceChanged(address(0), governance_);
}
/**
* @dev Returns the address of the current governance.
*/
function governance() public view virtual returns (address) {
return _governance;
}
/**
* @dev Transfers ownership of the contract to a new account (`newGov_`).
* Can only be called by the current governance.
*/
function changeGovernance(address newGov_) public virtual onlyGovernance {
require(newGov_ != address(0), "DZG002");
emit GovernanceChanged(_governance, newGov_);
_governance = newGov_;
}
}/*
Copyright 2022 https://www.dzap.io
SPDX-License-Identifier: MIT
*/
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./../interfaces/IDZapDiscountNft.sol";
import { NftData } from "./../common/Types.sol";
contract DZapDiscountNft is ERC1155, Ownable, ERC1155Burnable, ERC1155Supply, IDZapDiscountNft {
string public contractUri;
mapping(uint256 => NftData) public discountDetails;
mapping(address => mapping(uint256 => uint256)) public minters;
uint256 public nextId = 1;
uint256 private constant _BPS_MULTIPLIER = 100;
/* ========= CONSTRUCTOR ========= */
constructor(string memory baseUri_, string memory contractUri_) ERC1155(baseUri_) {
contractUri = contractUri_;
}
/* ========= VIEWS ========= */
function contractURI() public view returns (string memory) {
return contractUri;
}
function tokenURI(uint256 tokenId_) public view returns (string memory) {
return string(abi.encodePacked(uri(0), Strings.toString(tokenId_), ".json"));
}
/* ========= FUNCTIONS ========= */
function setBaseURI(string memory newUri_) public onlyOwner {
_setURI(newUri_);
}
function setContractURI(string memory newContractUri_) public onlyOwner {
contractUri = newContractUri_;
}
function createNfts(NftData[] calldata nftData_) public onlyOwner {
uint256 startingId = nextId;
for (uint256 i; i < nftData_.length; ++i) {
NftData memory data = nftData_[i];
require(data.discountedFeeBps > 0 && data.discountedFeeBps <= 100 * _BPS_MULTIPLIER, "DZN002");
require(data.expiry > block.timestamp, "DZN003");
discountDetails[nextId++] = data;
}
emit Created(startingId, nftData_.length);
}
function createAndMint(
NftData[] calldata nftData_,
address[] calldata to_,
uint256[] calldata ids_,
uint256[] calldata amounts_
) public onlyOwner {
createNfts(nftData_);
for (uint256 i; i < to_.length; ++i) {
uint256 id = ids_[i];
_isValidNft(id);
_mint(to_[i], id, amounts_[i], "0x");
}
emit Minted(to_, ids_, amounts_);
}
function approveMinter(
address[] calldata minters_,
uint256[] calldata ids_,
uint256[] calldata amounts_
) public onlyOwner {
for (uint256 i; i < minters_.length; ++i) {
_isValidNft(ids_[i]);
minters[minters_[i]][ids_[i]] += amounts_[i];
}
emit MintersApproved(minters_, ids_, amounts_);
}
function revokeMinter(address[] calldata minters_, uint256[] calldata ids_) public onlyOwner {
for (uint256 i; i < minters_.length; ++i) {
_isValidNft(ids_[i]);
minters[minters_[i]][ids_[i]] = 0;
}
emit MintersRevoked(minters_, ids_);
}
function mint(
address[] calldata to_,
uint256[] calldata ids_,
uint256[] calldata amounts_
) public {
for (uint256 i; i < to_.length; ++i) {
uint256 id = ids_[i];
_isValidNft(id);
if (_msgSender() != owner()) {
require(minters[_msgSender()][id] >= amounts_[i], "DZN001");
minters[_msgSender()][id] -= amounts_[i];
}
_mint(to_[i], id, amounts_[i], "0x");
}
emit Minted(to_, ids_, amounts_);
}
function mintBatch(
address to_,
uint256[] calldata ids_,
uint256[] calldata amounts_,
bytes calldata data_
) public onlyOwner {
for (uint256 i; i < ids_.length; ++i) {
_isValidNft(ids_[i]);
}
_mintBatch(to_, ids_, amounts_, data_);
emit BatchMinted(to_, ids_, amounts_);
}
/* ========= INTERNAL/PRIVATE ========= */
function _isValidNft(uint256 id_) private view {
require(id_ != 0 && id_ < nextId, "DZN004");
}
// The following functions are overrides required by Solidity.
function _beforeTokenTransfer(
address operator_,
address from,
address to_,
uint256[] memory ids_,
uint256[] memory amounts_,
bytes memory data_
) internal override(ERC1155, ERC1155Supply) {
super._beforeTokenTransfer(operator_, from, to_, ids_, amounts_, data_);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import { NftData } from "./../common/Types.sol";
interface IDZapDiscountNft {
/* ========= EVENTS ========= */
event Created(uint256 starringId, uint256 noCreated);
event MintersApproved(address[] minters, uint256[] ids, uint256[] amounts);
event MintersRevoked(address[] minters, uint256[] ids);
event Minted(address[] to, uint256[] ids, uint256[] amounts);
event BatchMinted(address to, uint256[] ids, uint256[] amounts);
/* ========= VIEWS ========= */
function contractURI() external view returns (string memory);
function tokenURI(uint256 tokenId_) external view returns (string memory);
/* ========= FUNCTIONS ========= */
function setBaseURI(string memory newUri_) external;
function setContractURI(string memory newContractUri_) external;
function createNfts(NftData[] calldata nftData_) external;
function approveMinter(
address[] calldata minters_,
uint256[] calldata ids_,
uint256[] calldata amounts_
) external;
function mint(
address[] calldata to_,
uint256[] calldata ids_,
uint256[] calldata amounts_
) external;
function mintBatch(
address to_,
uint256[] calldata ids_,
uint256[] calldata amounts_,
bytes calldata data_
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.0;
import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./extensions/IERC1155MetadataURI.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*
* _Available since v3.1._
*/
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
using Address for address;
// Mapping from token ID to account balances
mapping(uint256 => mapping(address => uint256)) private _balances;
// Mapping from account to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string private _uri;
/**
* @dev See {_setURI}.
*/
constructor(string memory uri_) {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256) public view virtual override returns (string memory) {
return _uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
require(account != address(0), "ERC1155: address zero is not a valid owner");
return _balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
public
view
virtual
override
returns (uint256[] memory)
{
require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts[i], ids[i]);
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
return _operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner nor approved"
);
_safeTransferFrom(from, to, id, amount, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual override {
require(
from == _msgSender() || isApprovedForAll(from, _msgSender()),
"ERC1155: caller is not token owner nor approved"
);
_safeBatchTransferFrom(from, to, ids, amounts, data);
}
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
emit TransferSingle(operator, from, to, id, amount);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
require(to != address(0), "ERC1155: transfer to the zero address");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
unchecked {
_balances[id][from] = fromBalance - amount;
}
_balances[id][to] += amount;
}
emit TransferBatch(operator, from, to, ids, amounts);
_afterTokenTransfer(operator, from, to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the amounts in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
_uri = newuri;
}
/**
* @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
_balances[id][to] += amount;
emit TransferSingle(operator, address(0), to, id, amount);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
require(to != address(0), "ERC1155: mint to the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);
for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
}
emit TransferBatch(operator, address(0), to, ids, amounts);
_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);
}
/**
* @dev Destroys `amount` tokens of token type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `amount` tokens of token type `id`.
*/
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
address operator = _msgSender();
uint256[] memory ids = _asSingletonArray(id);
uint256[] memory amounts = _asSingletonArray(amount);
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
emit TransferSingle(operator, from, address(0), id, amount);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
*/
function _burnBatch(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
require(from != address(0), "ERC1155: burn from the zero address");
require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
address operator = _msgSender();
_beforeTokenTransfer(operator, from, address(0), ids, amounts, "");
for (uint256 i = 0; i < ids.length; i++) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 fromBalance = _balances[id][from];
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
}
}
emit TransferBatch(operator, from, address(0), ids, amounts);
_afterTokenTransfer(operator, from, address(0), ids, amounts, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC1155: setting approval status for self");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Hook that is called before any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `ids` and `amounts` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
/**
* @dev Hook that is called after any token transfer. This includes minting
* and burning, as well as batched variants.
*
* The same hook is called on both single and batched variants. For single
* transfers, the length of the `id` and `amount` arrays will be 1.
*
* Calling conditions (for each `id` and `amount` pair):
*
* - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* of token type `id` will be transferred to `to`.
* - When `from` is zero, `amount` tokens of token type `id` will be minted
* for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
* will be burned.
* - `from` and `to` are never both zero.
* - `ids` and `amounts` have the same, non-zero length.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non ERC1155Receiver implementer");
}
}
}
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
if (to.isContract()) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
revert("ERC1155: ERC1155Receiver rejected tokens");
}
} catch Error(string memory reason) {
revert(reason);
} catch {
revert("ERC1155: transfer to non ERC1155Receiver implementer");
}
}
}
function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
uint256[] memory array = new uint256[](1);
array[0] = element;
return array;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/extensions/ERC1155Supply.sol)
pragma solidity ^0.8.0;
import "../ERC1155.sol";
/**
* @dev Extension of ERC1155 that adds tracking of total supply per id.
*
* Useful for scenarios where Fungible and Non-fungible tokens have to be
* clearly identified. Note: While a totalSupply of 1 might mean the
* corresponding is an NFT, there is no guarantees that no other token with the
* same id are not going to be minted.
*/
abstract contract ERC1155Supply is ERC1155 {
mapping(uint256 => uint256) private _totalSupply;
/**
* @dev Total amount of tokens in with a given id.
*/
function totalSupply(uint256 id) public view virtual returns (uint256) {
return _totalSupply[id];
}
/**
* @dev Indicates whether any token exist with a given id, or not.
*/
function exists(uint256 id) public view virtual returns (bool) {
return ERC1155Supply.totalSupply(id) > 0;
}
/**
* @dev See {ERC1155-_beforeTokenTransfer}.
*/
function _beforeTokenTransfer(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual override {
super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
if (from == address(0)) {
for (uint256 i = 0; i < ids.length; ++i) {
_totalSupply[ids[i]] += amounts[i];
}
}
if (to == address(0)) {
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 amount = amounts[i];
uint256 supply = _totalSupply[id];
require(supply >= amount, "ERC1155: burn amount exceeds totalSupply");
unchecked {
_totalSupply[id] = supply - amount;
}
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/extensions/ERC1155Burnable.sol)
pragma solidity ^0.8.0;
import "../ERC1155.sol";
/**
* @dev Extension of {ERC1155} that allows token holders to destroy both their
* own tokens and those that they have been approved to use.
*
* _Available since v3.1._
*/
abstract contract ERC1155Burnable is ERC1155 {
function burn(
address account,
uint256 id,
uint256 value
) public virtual {
require(
account == _msgSender() || isApprovedForAll(account, _msgSender()),
"ERC1155: caller is not token owner nor approved"
);
_burn(account, id, value);
}
function burnBatch(
address account,
uint256[] memory ids,
uint256[] memory values
) public virtual {
require(
account == _msgSender() || isApprovedForAll(account, _msgSender()),
"ERC1155: caller is not token owner nor approved"
);
_burnBatch(account, ids, values);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)
pragma solidity ^0.8.0;
import "../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*
* _Available since v3.1._
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "./IAggregationExecutor.sol";
import { SwapDescription } from "./../common/Types.sol";
interface IAggregationRouterV4 {
function swap(
IAggregationExecutor caller,
SwapDescription calldata desc,
bytes calldata data
) external payable returns (uint256 returnAmount, uint256 gasLeft);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "@openzeppelin/contracts/interfaces/IERC20.sol";
interface IWNATIVE is IERC20 {
function deposit() external payable;
function withdraw(uint256) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IUniswapV2Router02 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
)
external
returns (
uint256 amountA,
uint256 amountB,
uint256 liquidity
);
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (
uint256 amountToken,
uint256 amountETH,
uint256 liquidity
);
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountToken, uint256 amountETH);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) external pure returns (uint256 amountB);
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountOut);
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountIn);
function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts);
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 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 (uint256);
function balanceOf(address owner) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(
address from,
address to,
uint256 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 (uint256);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
event Mint(address indexed sender, uint256 amount0, uint256 amount1);
event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint256);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
);
function price0CumulativeLast() external view returns (uint256);
function price1CumulativeLast() external view returns (uint256);
function kLast() external view returns (uint256);
function mint(address to) external returns (uint256 liquidity);
function burn(address to) external returns (uint256 amount0, uint256 amount1);
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}/*
Copyright 2022 https://www.dzap.io
SPDX-License-Identifier: MIT
*/
pragma solidity 0.8.17;
import "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "../interfaces/IDaiLikePermit.sol";
abstract contract Permitable {
function _permit(address token_, bytes memory permit_) internal {
if (permit_.length > 0) {
bool success;
bytes memory result;
if (permit_.length == 32 * 7) {
// solhint-disable-next-line avoid-low-level-calls
(success, result) = token_.call(abi.encodePacked(IERC20Permit.permit.selector, permit_));
} else if (permit_.length == 32 * 8) {
// solhint-disable-next-line avoid-low-level-calls
(success, result) = token_.call(abi.encodePacked(IDaiLikePermit.permit.selector, permit_));
} else {
revert("DZP001");
}
require(success, "DZP002");
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
// a library for performing various math operations
library Math {
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x < y ? x : y;
}
// babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
interface IDaiLikePermit {
function permit(
address holder,
address spender,
uint256 nonce,
uint256 expiry,
bool allowed,
uint8 v,
bytes32 r,
bytes32 s
) external;
}{
"optimizer": {
"enabled": true,
"runs": 300
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256[3]","name":"fees_","type":"uint256[3]"},{"internalType":"address[]","name":"routers_","type":"address[]"},{"components":[{"internalType":"bool","name":"isSupported","type":"bool"},{"internalType":"uint256","name":"fees","type":"uint256"}],"internalType":"struct Router[]","name":"routerDetails_","type":"tuple[]"},{"internalType":"address","name":"governor_","type":"address"},{"internalType":"address","name":"aggregationRouter_","type":"address"},{"internalType":"address","name":"wNative_","type":"address"},{"internalType":"address","name":"protocolFeeVault_","type":"address"},{"internalType":"address","name":"feeDiscountNft_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"formerGov","type":"address"},{"indexed":true,"internalType":"address","name":"newGov","type":"address"}],"name":"GovernanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct Token[]","name":"inputTokens","type":"tuple[]"},{"indexed":false,"internalType":"address","name":"outputLp","type":"address"},{"indexed":false,"internalType":"uint256[3]","name":"returnAmounts","type":"uint256[3]"},{"indexed":false,"internalType":"uint256[2]","name":"feeBps","type":"uint256[2]"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Token[]","name":"lpInput","type":"tuple[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Token[]","name":"lpOutput","type":"tuple[]"}],"indexed":false,"internalType":"struct LPSwapInfo","name":"swapInfo","type":"tuple"},{"indexed":false,"internalType":"uint256[2]","name":"feeBps","type":"uint256[2]"}],"name":"LpSwapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"ProjectAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"ProjectFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"ProjectFeeVaultUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"ProjectStatusDisabled","type":"event"},{"anonymous":false,"inputs":[],"name":"ProtocolFeeUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"ProtocolFeeVaultUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"routers","type":"address[]"},{"components":[{"internalType":"bool","name":"isSupported","type":"bool"},{"internalType":"uint256","name":"fees","type":"uint256"}],"indexed":false,"internalType":"struct Router[]","name":"details","type":"tuple[]"}],"name":"RoutersUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensRescued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"contract IERC20","name":"dstToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"indexed":false,"internalType":"struct SwapInfo[]","name":"swapInfo","type":"tuple[]"},{"indexed":false,"internalType":"uint256[2]","name":"feeBps","type":"uint256[2]"}],"name":"TokensSwapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Token[]","name":"data","type":"tuple[]"}],"indexed":false,"internalType":"struct TransferInfo[]","name":"details","type":"tuple[]"},{"indexed":false,"internalType":"uint256[2]","name":"feeBps","type":"uint256[2]"}],"name":"TokensTransferred","type":"event"},{"inputs":[],"name":"AGGREGATION_ROUTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BPS_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[3]","name":"fees_","type":"uint256[3]"},{"internalType":"address","name":"feeVault_","type":"address"}],"name":"addProject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"permit","type":"bytes"}],"internalType":"struct InputTokenData[]","name":"data","type":"tuple[]"}],"internalType":"struct TransferDetails[]","name":"data_","type":"tuple[]"},{"internalType":"uint256","name":"projectId_","type":"uint256"},{"internalType":"uint256","name":"nftId_","type":"uint256"}],"name":"batchTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA_","type":"uint256"},{"internalType":"uint256","name":"amountB_","type":"uint256"},{"internalType":"uint256","name":"reserveA_","type":"uint256"},{"internalType":"uint256","name":"reserveB_","type":"uint256"},{"internalType":"address","name":"router_","type":"address"}],"name":"calculateOptimalSwapAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newGov_","type":"address"}],"name":"changeGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId_","type":"uint256"}],"name":"disableProject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeDiscountNft","outputs":[{"internalType":"contract DZapDiscountNft","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextProjectId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"enum FeeType","name":"","type":"uint8"}],"name":"projectFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"projectFeeVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum FeeType","name":"","type":"uint8"}],"name":"protocolFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"rescueFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"routers","outputs":[{"internalType":"bool","name":"isSupported","type":"bool"},{"internalType":"uint256","name":"fees","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"permit","type":"bytes"},{"internalType":"address[]","name":"tokenAToPath","type":"address[]"},{"internalType":"address[]","name":"tokenBToPath","type":"address[]"}],"internalType":"struct LpSwapDetails[]","name":"lpSwapDetails_","type":"tuple[]"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"sizeBps","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"address[]","name":"nativeToOutputPath","type":"address[]"}],"internalType":"struct WNativeSwapDetails[]","name":"wEthSwapDetails_","type":"tuple[]"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"uint256","name":"projectId_","type":"uint256"},{"internalType":"uint256","name":"nftId_","type":"uint256"}],"name":"swapLpToTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IAggregationExecutor","name":"executor","type":"address"},{"components":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"contract IERC20","name":"dstToken","type":"address"},{"internalType":"address payable","name":"srcReceiver","type":"address"},{"internalType":"address payable","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"},{"internalType":"bytes","name":"permit","type":"bytes"}],"internalType":"struct SwapDescription","name":"desc","type":"tuple"},{"internalType":"bytes","name":"routeData","type":"bytes"},{"internalType":"bytes","name":"permit","type":"bytes"}],"internalType":"struct SwapDetails[]","name":"data_","type":"tuple[]"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"permit","type":"bytes"},{"internalType":"address[]","name":"tokenAToPath","type":"address[]"},{"internalType":"address[]","name":"tokenBToPath","type":"address[]"}],"internalType":"struct LpSwapDetails[]","name":"lpSwapDetails_","type":"tuple[]"},{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"lpToken","type":"address"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"address[]","name":"nativeToToken0","type":"address[]"},{"internalType":"address[]","name":"nativeToToken1","type":"address[]"}],"internalType":"struct OutputLp","name":"outputLpDetails_","type":"tuple"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"uint256","name":"projectId_","type":"uint256"},{"internalType":"uint256","name":"nftId_","type":"uint256"}],"name":"swapTokensToLp","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IAggregationExecutor","name":"executor","type":"address"},{"components":[{"internalType":"contract IERC20","name":"srcToken","type":"address"},{"internalType":"contract IERC20","name":"dstToken","type":"address"},{"internalType":"address payable","name":"srcReceiver","type":"address"},{"internalType":"address payable","name":"dstReceiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"},{"internalType":"bytes","name":"permit","type":"bytes"}],"internalType":"struct SwapDescription","name":"desc","type":"tuple"},{"internalType":"bytes","name":"routeData","type":"bytes"},{"internalType":"bytes","name":"permit","type":"bytes"}],"internalType":"struct SwapDetails[]","name":"data_","type":"tuple[]"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"uint256","name":"projectId_","type":"uint256"},{"internalType":"uint256","name":"nftId_","type":"uint256"}],"name":"swapTokensToTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minReturnAmount","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"bytes","name":"permit","type":"bytes"}],"internalType":"struct UnoSwapDetails[]","name":"swapData_","type":"tuple[]"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"uint256","name":"projectId_","type":"uint256"},{"internalType":"uint256","name":"nftId_","type":"uint256"}],"name":"unoSwapTokensToTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId_","type":"uint256"},{"internalType":"enum FeeType[]","name":"feeTypes_","type":"uint8[]"},{"internalType":"uint256[]","name":"fees_","type":"uint256[]"}],"name":"updateProjectFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectId_","type":"uint256"},{"internalType":"address","name":"feeVault_","type":"address"}],"name":"updateProjectFeeVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum FeeType[]","name":"feeTypes_","type":"uint8[]"},{"internalType":"uint256[]","name":"fees_","type":"uint256[]"}],"name":"updateProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newProtocolFeeVault_","type":"address"}],"name":"updateProtocolFeeVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"routers_","type":"address[]"},{"components":[{"internalType":"bool","name":"isSupported","type":"bool"},{"internalType":"uint256","name":"fees","type":"uint256"}],"internalType":"struct Router[]","name":"routerDetails_","type":"tuple[]"}],"name":"updateRouters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wNative","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60c06040523480156200001157600080fd5b506040516200674e3803806200674e83398101604081905262000034916200052a565b868685858b898787826001600160a01b038116620000825760405162461bcd60e51b8152602060048201526006602482015265222d2398181960d11b60448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040519091907f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd2908290a3506001600160a01b03821615801590620000ec57506001600160a01b03811615155b620001235760405162461bcd60e51b8152602060048201526006602482015265445a4630303160d01b604482015260640162000079565b600180546001600160a01b03199081166001600160a01b03948516178255600380549091169284169290921790915583516000808052600460209081527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec92909255908501519181527fabd6e7cb50984ff9c2f3e18a2660c3353dadf4e3291deeb275dae2cd1e44fe059190915560409093015160029093527f91da3fd0782e51c6b3986e9e672fd566868e71f3dbc2d6c2cd6fbb3e361af2a79290925550811615801590620001fb57506001600160a01b03821615155b620002335760405162461bcd60e51b8152602060048201526007602482015266445a533030313560c81b604482015260640162000079565b6001600160a01b0380831660a052811660805260005b8451811015620003265760008582815181106200026a576200026a62000644565b6020026020010151905060006001600160a01b0316816001600160a01b031603620002c25760405162461bcd60e51b8152602060048201526007602482015266222d299818189b60c91b604482015260640162000079565b848281518110620002d757620002d762000644565b6020908102919091018101516001600160a01b0392909216600090815260078252604090208251815460ff19169015151781559101516001909101556200031e816200065a565b905062000249565b5050505050505050505050505062000682565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b038111828210171562000374576200037462000339565b60405290565b604051606081016001600160401b038111828210171562000374576200037462000339565b604051601f8201601f191681016001600160401b0381118282101715620003ca57620003ca62000339565b604052919050565b60006001600160401b03821115620003ee57620003ee62000339565b5060051b60200190565b80516001600160a01b03811681146200041057600080fd5b919050565b600082601f8301126200042757600080fd5b81516020620004406200043a83620003d2565b6200039f565b82815260059290921b840181019181810190868411156200046057600080fd5b8286015b8481101562000486576200047881620003f8565b835291830191830162000464565b509695505050505050565b600082601f830112620004a357600080fd5b81516020620004b66200043a83620003d2565b82815260069290921b84018101918181019086841115620004d657600080fd5b8286015b84811015620004865760408189031215620004f55760008081fd5b620004ff6200034f565b81518015158114620005115760008081fd5b81528185015185820152835291830191604001620004da565b600080600080600080600080610140898b0312156200054857600080fd5b89601f8a01126200055857600080fd5b620005626200037a565b8060608b018c8111156200057557600080fd5b8b5b818110156200059157805184526020938401930162000577565b505190995090506001600160401b0380821115620005ae57600080fd5b620005bc8c838d0162000415565b985060808b0151915080821115620005d357600080fd5b50620005e28b828c0162000491565b965050620005f360a08a01620003f8565b94506200060360c08a01620003f8565b93506200061360e08a01620003f8565b9250620006246101008a01620003f8565b9150620006356101208a01620003f8565b90509295985092959890939650565b634e487b7160e01b600052603260045260246000fd5b6000600182016200067b57634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a051615ff06200075e600039600081816101f001528181610c9f01528181610cee01528181610e33015281816125e4015261263601526000818161029c0152818161132a0152818161139c0152818161156301528181611ee0015281816123200152818161241e015281816125600152818161290101528181612984015281816131d801528181613265015281816132b20152818161374601528181613790015281816138f701528181613a0e01528181613b1c01528181613ed401528181613f5101528181613feb01526144a20152615ff06000f3fe6080604052600436106101b05760003560e01c806380dd9a1f116100ec578063e2edbb671161008a578063f50b44a211610064578063f50b44a214610516578063f5422efd14610536578063f568859a14610556578063fd4a9c0d1461057657600080fd5b8063e2edbb67146104cd578063e935b7b1146104e0578063f1ac7ffc146104f657600080fd5b80639efff690116100c65780639efff69014610449578063af1af3b914610481578063bc063e1a146104a1578063e1a45218146104b757600080fd5b806380dd9a1f146103c557806399572d6f146104165780639ca072d01461043657600080fd5b806348c545a3116101595780636bb14547116101335780636bb145471461033c5780636ccae0541461034f578063760615041461036f578063770d88d11461038f57600080fd5b806348c545a3146102de5780635aa6e675146102fe5780635b1f47651461031c57600080fd5b806328394f911161018a57806328394f911461024f5780632d68efc91461028a57806342c039af146102be57600080fd5b806305cda745146101bc5780630621153b146101de57806319f6c38c1461022f57600080fd5b366101b757005b600080fd5b3480156101c857600080fd5b506101dc6101d7366004614ade565b610589565b005b3480156101ea57600080fd5b506102127f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561023b57600080fd5b506101dc61024a366004614b49565b610680565b34801561025b57600080fd5b5061027c61026a366004614bf1565b60046020526000908152604090205481565b604051908152602001610226565b34801561029657600080fd5b506102127f000000000000000000000000000000000000000000000000000000000000000081565b3480156102ca57600080fd5b506101dc6102d9366004614c2f565b6107b8565b3480156102ea57600080fd5b506101dc6102f9366004614c6b565b610934565b34801561030a57600080fd5b506000546001600160a01b0316610212565b34801561032857600080fd5b506101dc610337366004614c88565b6109e4565b6101dc61034a366004614cad565b610ad9565b34801561035b57600080fd5b506101dc61036a366004614d13565b610fcd565b34801561037b57600080fd5b50600354610212906001600160a01b031681565b34801561039b57600080fd5b506102126103aa366004614d54565b6006602052600090815260409020546001600160a01b031681565b3480156103d157600080fd5b506103ff6103e0366004614c6b565b6007602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610226565b34801561042257600080fd5b506101dc610431366004614c6b565b6110b8565b6101dc610444366004614cad565b61117c565b34801561045557600080fd5b5061027c610464366004614d6d565b600560209081526000928352604080842090915290825290205481565b34801561048d57600080fd5b50600154610212906001600160a01b031681565b3480156104ad57600080fd5b5061027c61138881565b3480156104c357600080fd5b5061027c61271081565b6101dc6104db366004614d99565b6116f9565b3480156104ec57600080fd5b5061027c60025481565b34801561050257600080fd5b506101dc610511366004614d54565b611ae9565b34801561052257600080fd5b5061027c610531366004614de9565b611be0565b34801561054257600080fd5b506101dc610551366004614e36565b611d47565b34801561056257600080fd5b506101dc61057136600461504f565b611fcd565b6101dc610584366004615124565b6120fc565b6000546001600160a01b031633146105bc5760405162461bcd60e51b81526004016105b3906151e1565b60405180910390fd5b60005b83811015610650578282828181106105d9576105d9615201565b90506020020135600460008787858181106105f6576105f6615201565b905060200201602081019061060b9190614bf1565b600281111561061c5761061c615217565b600281111561062d5761062d615217565b81526020810191909152604001600020558061064881615243565b9150506105bf565b506040517f023f6f64c24d183eaafe34dcf00b3c910b235bd19e113cc08903bec4d284652f90600090a150505050565b6000546001600160a01b031633146106aa5760405162461bcd60e51b81526004016105b3906151e1565b60005b838110156107745760008585838181106106c9576106c9615201565b90506020020160208101906106de9190614c6b565b90506001600160a01b0381166107205760405162461bcd60e51b8152602060048201526007602482015266222d299818189b60c91b60448201526064016105b3565b83838381811061073257610732615201565b6001600160a01b0384166000908152600760205260409081902091029290920191905061075f828261526a565b905050508061076d90615243565b90506106ad565b507f101b604ed068a7688b1d926dc5891e4b37f9ac9f133bd36f6500c60dfd5104e0848484846040516107aa9493929190615295565b60405180910390a150505050565b6000546001600160a01b031633146107e25760405162461bcd60e51b81526004016105b3906151e1565b6001600160a01b0381166108215760405162461bcd60e51b8152602060048201526006602482015265445a4630303160d01b60448201526064016105b3565b61138882351180159061083a5750611388602083013511155b801561084c5750611388604083013511155b6108815760405162461bcd60e51b8152602060048201526006602482015265222d2318181960d11b60448201526064016105b3565b600280546000908152600560208181526040808420848052825280842087359055845484528282528084206001855282528084208783013590558454845291815281832084845281528183208683013590558354835260069052812080546001600160a01b0319166001600160a01b0385161790558154919061090383615243565b909155506040517f7048f4116e78f3e5e51282b26fe38719c961b8ca5b63fb602278562ca629a14b90600090a25050565b6000546001600160a01b0316331461095e5760405162461bcd60e51b81526004016105b3906151e1565b6001600160a01b03811661099d5760405162461bcd60e51b8152602060048201526006602482015265445a4630303160d01b60448201526064016105b3565b600180546001600160a01b0319166001600160a01b0383161790556040517fb46ce5ba362e5bea9bdeefea05b72620f6d64e553f8a04e96678bb555b50299290600090a150565b6000546001600160a01b03163314610a0e5760405162461bcd60e51b81526004016105b3906151e1565b6002548210610a485760405162461bcd60e51b8152602060048201526006602482015265445a4630303360d01b60448201526064016105b3565b6001600160a01b038116610a875760405162461bcd60e51b8152602060048201526006602482015265445a4630303160d01b60448201526064016105b3565b60008281526006602052604080822080546001600160a01b0319166001600160a01b0385161790555183917fb799f1a20f2b0b7dde2e06abfe87cf23a21999428ff97fe111e210fd04f6e16091a25050565b6001600160a01b038316610b185760405162461bcd60e51b8152602060048201526006602482015265445a5330303160d01b60448201526064016105b3565b6000846001600160401b03811115610b3257610b32614ecb565b604051908082528060200260200182016040528015610b8457816020015b604080516080810182526000808252602080830182905292820181905260608201528252600019909201910181610b505790505b5090506000806000610b9886866000612b9a565b92509250925060005b88811015610f605760008a8a83818110610bbd57610bbd615201565b9050602002810190610bcf9190615330565b610bd89061546d565b6020810151606001519091506001600160a01b031615610c235760405162461bcd60e51b8152602060048201526006602482015265222d2998181960d11b60448201526064016105b3565b602081015160c0015160011615610c655760405162461bcd60e51b8152602060048201526006602482015265445a5330303360d01b60448201526064016105b3565b6000610c78826020015160000151612e7b565b15610c8c5750602081015160800151610ccc565b610ccc82606001518360200151600001517f0000000000000000000000000000000000000000000000000000000000000000856020015160800151612eb5565b815160208301516040808501519051623e012960e91b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693637c025200938693610d2393600401615565565b604080518083038185885af193505050508015610d5d575060408051601f3d908101601f19168201909252610d5a91810190615627565b60015b610e8b57610d6961564b565b806308c379a003610e7f5750610d7d615667565b80610d885750610e81565b60405180608001604052808460200151600001516001600160a01b031681526020018460200151602001516001600160a01b0316815260200184602001516080015181526020016000815250888581518110610de657610de6615201565b6020026020010181905250610e02836020015160000151612e7b565b15610e1e57610e1933846020015160800151612eee565b610e79565b602083015151610e59906001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006000612f99565b610e79336020850151608081015190516001600160a01b031691906130e8565b50610f4d565b505b3d6000803e3d6000fd5b836020015160a00151821015610ecc5760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b60405180608001604052808560200151600001516001600160a01b031681526020018560200151602001516001600160a01b03168152602001856020015160800151815260200183815250898681518110610f2957610f29615201565b6020026020010181905250610f4a8460200151602001518d88858c8c613118565b50505b505080610f5990615243565b9050610ba1565b506001600160a01b038716336001600160a01b03167f81c190be312be4e4c986228937957a7fe3dab07e6e2c8e5bf8068154044117b986604051806040016040528088815260200187815250604051610fba929190615713565b60405180910390a3505050505050505050565b6000546001600160a01b03163314610ff75760405162461bcd60e51b81526004016105b3906151e1565b6001600160a01b0382166110355760405162461bcd60e51b8152602060048201526005602482015264445a30303160d81b60448201526064016105b3565b61103e83612e7b565b156110525761104d8282612eee565b611066565b6110666001600160a01b03841683836130e8565b826001600160a01b0316826001600160a01b03167f77023e19c7343ad491fd706c36335ca0e738340a91f29b1fd81e2673d44896c4836040516110ab91815260200190565b60405180910390a3505050565b6000546001600160a01b031633146110e25760405162461bcd60e51b81526004016105b3906151e1565b6001600160a01b0381166111215760405162461bcd60e51b8152602060048201526006602482015265222d2398181960d11b60448201526064016105b3565b600080546040516001600160a01b03808516939216917f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd291a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0383166111bb5760405162461bcd60e51b8152602060048201526006602482015265445a5330303160d01b60448201526064016105b3565b6000846001600160401b038111156111d5576111d5614ecb565b60405190808252806020026020018201604052801561122757816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816111f35790505b509050600080600061123b86866000612b9a565b9250925092506112496131d0565b60005b88811015610f605760008a8a8381811061126857611268615201565b905060200281019061127a9190615792565b61128390615817565b90506000816060015160008151811061129e5761129e615201565b602002602001015190506000826060015160018460600151516112c191906158c6565b815181106112d1576112d1615201565b602002602001015190506112e481612e7b565b1561131a5760405162461bcd60e51b8152602060048201526006602482015265088b4a66060760d31b60448201526064016105b3565b61132382612e7b565b15611411577f0000000000000000000000000000000000000000000000000000000000000000836060015160008151811061136057611360615201565b6001600160a01b0392831660209182029290920181019190915284519085015160405163095ea7b360e01b8152918316600483015260248201527f00000000000000000000000000000000000000000000000000000000000000009091169063095ea7b3906044016020604051808303816000875af11580156113e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140b91906158d9565b50611429565b61142983608001518385600001518660200151612eb5565b82600001516001600160a01b03166338ed17398460200151856040015186606001513042603c61145991906158f6565b6040518663ffffffff1660e01b815260040161147995949392919061594d565b6000604051808303816000875af19250505080156114b957506040513d6000823e601f3d908101601f191682016040526114b69190810190615989565b60015b611618576114c561564b565b806308c379a003610e7f57506114d9615667565b806114e45750610e81565b6040518060800160405280846001600160a01b03168152602001836001600160a01b0316815260200185602001518152602001600081525089868151811061152e5761152e615201565b602002602001018190525061154283612e7b565b156115e0576020840151604051632e1a7d4d60e01b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156115af57600080fd5b505af11580156115c3573d6000803e3d6000fd5b505050506115db6115d13390565b8560200151612eee565b611612565b83516115f8906001600160a01b038516906000612f99565b6116123360208601516001600160a01b03861691906130e8565b506116e5565b6000816001835161162991906158c6565b8151811061163957611639615201565b6020026020010151905084604001518110156116805760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b6040518060800160405280856001600160a01b03168152602001846001600160a01b0316815260200186602001518152602001828152508a87815181106116c9576116c9615201565b60200260200101819052506116e2838e89848d8d61324d565b50505b505050806116f290615243565b905061124c565b6000836001600160401b0381111561171357611713614ecb565b60405190808252806020026020018201604052801561175957816020015b6040805180820190915260008152606060208201528152602001906001900390816117315790505b509050600080600061176d86866002612b9a565b919450925090503460005b88811015611a5a5760008a8a8381811061179457611794615201565b90506020028101906117a69190615a19565b6117af90615a2f565b80519091506001600160a01b03166117f25760405162461bcd60e51b8152602060048201526006602482015265445a5330303160d01b60448201526064016105b3565b60008160200151516001600160401b0381111561181157611811614ecb565b60405190808252806020026020018201604052801561185657816020015b604080518082019091526000808252602082015281526020019060019003908161182f5790505b50905060005b826020015151811015611a075760008360200151828151811061188157611881615201565b60200260200101519050600080600061189f84602001518d8d613320565b925092509250604051806040016040528085600001516001600160a01b0316815260200185602001518152508686815181106118dd576118dd615201565b60200260200101819052506118f58460000151612e7b565b156119875783602001518910156119375760405162461bcd60e51b8152602060048201526006602482015265445a5330303360d01b60448201526064016105b3565b6020840151611946908a6158c6565b9850611956876000015184612eee565b811561197257600154611972906001600160a01b031683612eee565b8015611982576119828a82612eee565b6119f2565b6119998460000151856040015161337a565b6119b233885186516001600160a01b03169190866134b4565b81156119d5576119d53360015486516001600160a01b03908116929116856134b4565b80156119f2576119f23385516001600160a01b0316908c846134b4565b5050505080611a0090615243565b905061185c565b50604051806040016040528083600001516001600160a01b0316815260200182815250888481518110611a3c57611a3c615201565b6020026020010181905250505080611a5390615243565b9050611778565b508015611a925760405162461bcd60e51b8152602060048201526006602482015265222d2998181b60d11b60448201526064016105b3565b60408051808201825285815260208101859052905133917fd3b45d0daff5a08d16c97b882a9056c67b55f8d36f4d3c00c7b6a1c8a8d8de9591611ad6918991615ba2565b60405180910390a2505050505050505050565b6000546001600160a01b03163314611b135760405162461bcd60e51b81526004016105b3906151e1565b6002548110611b4d5760405162461bcd60e51b8152602060048201526006602482015265445a4630303360d01b60448201526064016105b3565b6000818152600660205260409020546001600160a01b0316611b9a5760405162461bcd60e51b81526020600482015260066024820152651116918c0c0d60d21b60448201526064016105b3565b60008181526006602052604080822080546001600160a01b03191690555182917fcc5a352d2149d712d03e00be4696d621598de55d2f46c41d6c671524f51b072591a250565b6000611bec8486615c32565b611bf68488615c32565b1015611c2e5760405162461bcd60e51b8152602060048201526007602482015266111694cc0c0c4d60ca1b60448201526064016105b3565b6001600160a01b03821660009081526007602052604081206001015490611c57826127106158c6565b905060008683611c6a6127106002615c32565b611c7491906158c6565b611c7e9190615c32565b90506000611c8c888a615c32565b611c96888c615c32565b611ca091906158c6565b9050600088611caf898c6158f6565b611cbb61271085615c32565b611cc59190615c49565b611ccf9190615c32565b90506000611cdd8286615c32565b611ce8906004615c32565b90506000611d0982611cfa8780615c32565b611d0491906158f6565b6134ec565b90506000611d1786836158c6565b90506000611d26886002615c32565b9050611d328183615c49565b99505050505050505050505b95945050505050565b6001600160a01b038316611d865760405162461bcd60e51b8152602060048201526006602482015265445a5330303160d01b60448201526064016105b3565b83611dbc5760405162461bcd60e51b8152602060048201526006602482015265445a5330303960d01b60448201526064016105b3565b6040805180820190915260608082526020820152866001600160401b03811115611de857611de8614ecb565b604051908082528060200260200182016040528015611e2d57816020015b6040805180820190915260008082526020820152815260200190600190039081611e065790505b508152611e3b8560016158f6565b6001600160401b03811115611e5257611e52614ecb565b604051908082528060200260200182016040528015611e9757816020015b6040805180820190915260008082526020820152815260200190600190039081611e705790505b50602082015260008080611ead86866001612b9a565b925092509250611ebd8b8b61355c565b84526040516370a0823160e01b8152306004820152611f5a908a908a908a9085907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611f2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f539190615c6b565b888861382f565b60208501526001600160a01b038716336001600160a01b03167f1c2a63767d9cdc877fc97d92e65e9bb79e8502ec148af3f7bf7b4292ceb416b986604051806040016040528088815260200187815250604051611fb8929190615c84565b60405180910390a35050505050505050505050565b6000546001600160a01b03163314611ff75760405162461bcd60e51b81526004016105b3906151e1565b60025483106120315760405162461bcd60e51b8152602060048201526006602482015265445a4630303360d01b60448201526064016105b3565b60005b82518110156120cb5781818151811061204f5761204f615201565b602002602001015160056000868152602001908152602001600020600085848151811061207e5761207e615201565b6020026020010151600281111561209757612097615217565b60028111156120a8576120a8615217565b8152602081019190915260400160002055806120c381615243565b915050612034565b5060405183907fbed46add49f1852fbdc678819bb401f7f59ac14a61bbfa2bb5a9ed73f788bcbd90600090a2505050565b6001600160a01b03831661213b5760405162461bcd60e51b8152602060048201526006602482015265445a5330303160d01b60448201526064016105b3565b6007600061214c6020870187614c6b565b6001600160a01b0316815260208101919091526040016000205460ff1661219e5760405162461bcd60e51b8152602060048201526006602482015265445a5330303560d01b60448201526064016105b3565b60006121aa86896158f6565b6121b59060016158f6565b6001600160401b038111156121cc576121cc614ecb565b60405190808252806020026020018201604052801561221157816020015b60408051808201909152600080825260208201528152602001906001900390816121ea5790505b509050600080600061222586866001612b9a565b91945092509050600061223e60408a0160208b01614c6b565b6001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561227b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229f9190615cce565b905060006122b360408b0160208c01614c6b565b6001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123149190615cce565b9050600034156123dc577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561237957600080fd5b505af115801561238d573d6000803e3d6000fd5b5050505050604051806040016040528060006001600160a01b031681526020013481525087600189516123c091906158c6565b815181106123d0576123d0615201565b60200260200101819052505b8d81101561277a5760008f8f838181106123f8576123f8615201565b905060200281019061240a9190615330565b6124139061546d565b6020810151519091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169082161480159061246b5750846001600160a01b0316816001600160a01b031614155b80156124895750836001600160a01b0316816001600160a01b031614155b156126f4576020820151606001516001600160a01b0316156124d65760405162461bcd60e51b8152602060048201526006602482015265222d2998181960d11b60448201526064016105b3565b602082015160c00151600116156125185760405162461bcd60e51b8152602060048201526006602482015265445a5330303360d01b60448201526064016105b3565b60208201515161252790612e7b565b1561255e5760405162461bcd60e51b8152602060048201526007602482015266445a533030313160c81b60448201526064016105b3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168260200151602001516001600160a01b0316146125d15760405162461bcd60e51b8152602060048201526007602482015266222d299818189960c91b60448201526064016105b3565b61261182606001518360200151600001517f0000000000000000000000000000000000000000000000000000000000000000856020015160800151612eb5565b815160208301516040808501519051623e012960e91b81526000936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693637c0252009361266993600401615565565b60408051808303816000875af1158015612687573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ab9190615627565b509050826020015160a0015181116126ee5760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b50612724565b61270281836060015161337a565b612724336020840151608081015190516001600160a01b0316919030906134b4565b6040518060400160405280826001600160a01b0316815260200183602001516080015181525089848151811061275c5761275c615201565b602002602001018190525050508061277390615243565b90506123dc565b60005b8c811015612a5e5760008e8e8381811061279957612799615201565b90506020028101906127ab9190615ceb565b6127b490615d01565b80516001600160a01b031660009081526007602052604090205490915060ff1661280a5760405162461bcd60e51b8152602060048201526007602482015266445a533030313360c81b60448201526064016105b3565b600081602001516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561284e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128729190615cce565b9050600082602001516001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128dc9190615cce565b90506000806128f18585858860000151613cc7565b91509150612978848387608001517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b03161415801561295357508c6001600160a01b0316886001600160a01b031614155b801561297157508b6001600160a01b0316886001600160a01b031614155b8951613dac565b6129fa83828760a001517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b0316141580156129d657508c6001600160a01b0316876001600160a01b031614155b801561297157508b6001600160a01b0316876001600160a01b031614158951613dac565b604051806040016040528086602001516001600160a01b0316815260200186604001518152508d8789612a2d91906158f6565b81518110612a3d57612a3d615201565b6020026020010181905250505050505080612a5790615243565b905061277d565b506000612a6c8c8585613eb4565b805190915060408d01351115612aad5760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b612acd612ac060408e0160208f01614c6b565b82518d9088908b8b61437c565b602081015115612af157612af13360208301516001600160a01b03871691906130e8565b604081015115612b1557612b153360408301516001600160a01b03861691906130e8565b6001600160a01b038b16336001600160a01b03167f5bf5b0a8ee8b7b80862a13ba8a4c617db5a2e2a415b9189f9e5d5e852e9115278a8f6020016020810190612b5e9190614c6b565b6040805180820182528d8152602081018d90529051612b809392918891615dbe565b60405180910390a350505050505050505050505050505050565b600080600060025486108015612bc657506000868152600660205260409020546001600160a01b031615155b612bfb5760405162461bcd60e51b8152602060048201526006602482015265445a4630303360d01b60448201526064016105b3565b600060046000866002811115612c1357612c13615217565b6002811115612c2457612c24615217565b81526020019081526020016000205490508560001480612c42575080155b15612cb15760008781526005602052604081208291876002811115612c6957612c69615217565b6002811115612c7a57612c7a615217565b815260208082019290925260409081016000908120548b82526006909352205491955093506001600160a01b03169150612e729050565b6003546000906001600160a01b031662fdd58e336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018a9052604401602060405180830381865afa158015612d10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d349190615c6b565b11612d6a5760405162461bcd60e51b8152602060048201526006602482015265445a4630303560d01b60448201526064016105b3565b6003546040516306e1dd2f60e11b81526004810188905260009182916001600160a01b0390911690630dc3ba5e906024016040805180830381865afa158015612db7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddb9190615627565b9150915080421015612e0b57612710612df48385615c32565b612dfe9190615c49565b612e0890846158c6565b92505b60008981526005602052604081208491896002811115612e2d57612e2d615217565b6002811115612e3e57612e3e615217565b815260208082019290925260409081016000908120548d82526006909352205491975095506001600160a01b031693505050505b93509350939050565b60006001600160a01b0382161580612eaf57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b92915050565b612ebf838561337a565b612ed46001600160a01b0384163330846134b4565b612ee86001600160a01b0384168383612f99565b50505050565b604080516000808252602082019092526001600160a01b038416908390604051612f189190615e19565b60006040518083038185875af1925050503d8060008114612f55576040519150601f19603f3d011682016040523d82523d6000602084013e612f5a565b606091505b5050905080612f945760405162461bcd60e51b8152602060048201526006602482015265445a5330303760d01b60448201526064016105b3565b505050565b8015806130135750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612fed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130119190615c6b565b155b6130855760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084016105b3565b6040516001600160a01b038316602482015260448101829052612f9490849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526143a7565b6040516001600160a01b038316602482015260448101829052612f9490849063a9059cbb60e01b906064016130b1565b6000806000613128868686613320565b92509250925061313789612e7b565b15613177576131468884612eee565b811561316257600154613162906001600160a01b031683612eee565b8015613172576131728782612eee565b6131c5565b61318b6001600160a01b038a1689856130e8565b81156131ab576001546131ab906001600160a01b038b81169116846130e8565b80156131c5576131c56001600160a01b038a1688836130e8565b505050505050505050565b341561324b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561323157600080fd5b505af1158015613245573d6000803e3d6000fd5b50505050505b565b600080600061325d868686613320565b9250925092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316896001600160a01b03160361317757604051632e1a7d4d60e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156132fe57600080fd5b505af1158015613312573d6000803e3d6000fd5b505050506131468884612eee565b60008080806127106133328789615c32565b61333c9190615c49565b9050600061271061334d878a615c32565b6133579190615c49565b905061336381836158f6565b61336d90896158c6565b9891975095509350505050565b8051156134b05760006060825160e00361341a576040516001600160a01b038516906133b39063d505accf60e01b908690602001615e2b565b60408051601f19818403018152908290526133cd91615e19565b6000604051808303816000865af19150503d806000811461340a576040519150601f19603f3d011682016040523d82523d6000602084013e61340f565b606091505b50909250905061347a565b825161010003613449576040516001600160a01b038516906133b3906323f2ebc360e21b908690602001615e2b565b60405162461bcd60e51b8152602060048201526006602482015265445a5030303160d01b60448201526064016105b3565b81612ee85760405162461bcd60e51b8152602060048201526006602482015265222d2818181960d11b60448201526064016105b3565b5050565b6040516001600160a01b0380851660248301528316604482015260648101829052612ee89085906323b872dd60e01b906084016130b1565b6000600382111561354d5750806000613506600283615c49565b6135119060016158f6565b90505b818110156135475790508060028161352c8186615c49565b61353691906158f6565b6135409190615c49565b9050613514565b50919050565b8115613557575060015b919050565b60606000826001600160401b0381111561357857613578614ecb565b6040519080825280602002602001820160405280156135bd57816020015b60408051808201909152600080825260208201528152602001906001900390816135965790505b50905060005b838110156138275760008585838181106135df576135df615201565b90506020028101906135f19190615ceb565b6135fa90615d01565b80516001600160a01b031660009081526007602052604090205490915060ff1661364f5760405162461bcd60e51b8152602060048201526006602482015265445a5330303560d01b60448201526064016105b3565b600081602001516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015613693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136b79190615cce565b9050600082602001516001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156136fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137219190615cce565b90506000806137368585858860000151613cc7565b91509150613784848387608001517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b031614158960000151613dac565b6137ce83828760a001517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b031614158960000151613dac565b604051806040016040528086602001516001600160a01b03168152602001866040015181525087878151811061380657613806615201565b602002602001018190525050505050508061382090615243565b90506135c3565b509392505050565b60606000876001600160401b0381111561384b5761384b614ecb565b60405190808252806020026020018201604052801561389057816020015b60408051808201909152600080825260208201528152602001906001900390816138695790505b50905060005b88811015613cba5760008a8a838181106138b2576138b2615201565b90506020028101906138c49190615330565b6138cd90615e5c565b905060006138dc60018c6158c6565b830361396f576040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015613946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061396a9190615c6b565b61398c565b6127108260200151896139829190615c32565b61398c9190615c49565b9050816060015151600003613ae45781604001518110156139d85760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b60008060006139e8848b8b613320565b604051632e1a7d4d60e01b81526004810188905292955090935091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d90602401600060405180830381600087803b158015613a5257600080fd5b505af1158015613a66573d6000803e3d6000fd5b50505050613a748d84612eee565b8115613a9057600154613a90906001600160a01b031683612eee565b8015613aa057613aa08c82612eee565b604051806040016040528060006001600160a01b0316815260200185815250878781518110613ad157613ad1615201565b6020026020010181905250505050613ca7565b6060820151805160009190613afb906001906158c6565b81518110613b0b57613b0b615201565b6020026020010151905060008290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613bbb5783516001600160a01b031660009081526007602052604090205460ff16613ba55760405162461bcd60e51b8152602060048201526006602482015265445a5330303560d01b60448201526064016105b3565b613bb88385606001518660000151614479565b90505b8360400151811015613bf85760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b6000806000613c08848d8d613320565b925092509250613c2c8f84876001600160a01b03166130e89092919063ffffffff16565b8115613c4c57600154613c4c906001600160a01b038781169116846130e8565b8015613c6657613c666001600160a01b0386168f836130e8565b6040518060400160405280866001600160a01b0316815260200185815250898981518110613c9657613c96615201565b602002602001018190525050505050505b505080613cb390615243565b9050613896565b5098975050505050505050565b600080613ce286606001518760200151858960400151612eb5565b826001600160a01b031663baa2abde868689604001516000803042603c613d0991906158f6565b60405160e089901b6001600160e01b03191681526001600160a01b039788166004820152958716602487015260448601949094526064850192909252608484015290921660a482015260c481019190915260e40160408051808303816000875af1158015613d7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d9f9190615627565b9097909650945050505050565b81156132455760405163095ea7b360e01b81526001600160a01b0382811660048301526024820186905286169063095ea7b3906044016020604051808303816000875af1158015613e01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e2591906158d9565b506001600160a01b0381166338ed17398560008630613e4542603c6158f6565b6040518663ffffffff1660e01b8152600401613e6595949392919061594d565b6000604051808303816000875af1158015613e84573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613eac9190810190615989565b505050505050565b613ebc614a75565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015613f23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f479190615c6b565b90508015614049577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614613fe957613fe7613f96600283615c49565b613fa36060880188615ec2565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613fe2925050506020890189614c6b565b614479565b505b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161461404957614047614030600283615c49565b61403a90836158c6565b613fa36080880188615ec2565b505b60008061414561405f6040890160208a01614c6b565b6040516370a0823160e01b8152306004820152889088906001600160a01b038316906370a0823190602401602060405180830381865afa1580156140a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140cb9190615c6b565b6040516370a0823160e01b81523060048201526001600160a01b038b16906370a0823190602401602060405180830381865afa15801561410f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141339190615c6b565b61414060208e018e614c6b565b6145cc565b90925090506001600160a01b03861663095ea7b361416660208a018a614c6b565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018590526044016020604051808303816000875af11580156141b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141d791906158d9565b506001600160a01b03851663095ea7b36141f460208a018a614c6b565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015614241573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061426591906158d9565b506000808061427760208b018b614c6b565b6001600160a01b031663e8e337008a8a88886000803061429842603c6158f6565b60405160e08a901b6001600160e01b03191681526001600160a01b039889166004820152968816602488015260448701959095526064860193909352608485019190915260a484015290921660c482015260e4810191909152610104016060604051808303816000875af1158015614314573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143389190615f0b565b9250925092506040518060600160405280828152602001848761435b91906158c6565b815260200161436a84876158c6565b905296505050505050505b9392505050565b600080600061438c868686613320565b9194509250905061318b6001600160a01b038a1689856130e8565b60006143fc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166148f49092919063ffffffff16565b805190915015612f94578080602001905181019061441a91906158d9565b612f945760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105b3565b60405163095ea7b360e01b81526001600160a01b038281166004830152602482018590526000917f00000000000000000000000000000000000000000000000000000000000000009091169063095ea7b3906044016020604051808303816000875af11580156144ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061451191906158d9565b5060006001600160a01b0383166338ed17398683873061453242603c6158f6565b6040518663ffffffff1660e01b815260040161455295949392919061594d565b6000604051808303816000875af1158015614571573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526145999190810190615989565b905080600182516145aa91906158c6565b815181106145ba576145ba615201565b60200260200101519150509392505050565b600080600080896001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015614610573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146349190615f57565b506dffffffffffffffffffffffffffff91821693501690506146568782615c32565b6146608784615c32565b036146725786869350935050506148e9565b600061467e8883615c32565b6146888885615c32565b1190506000816146a45761469f898986868b611be0565b6146b1565b6146b1888a85878b611be0565b6040805160028082526060820183529293506000929091602083019080368337019050509050826146e3578b8b6146e6565b8a8c5b826000815181106146f9576146f9615201565b602002602001018360018151811061471357614713615201565b6001600160a01b0393841660209182029290920101529116905281156148dd578060008151811061474657614746615201565b602090810291909101015160405163095ea7b360e01b81526001600160a01b038a81166004830152602482018590529091169063095ea7b3906044016020604051808303816000875af11580156147a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147c591906158d9565b5060006001600160a01b0389166338ed1739848385306147e642603c6158f6565b6040518663ffffffff1660e01b815260040161480695949392919061594d565b6000604051808303816000875af1158015614825573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261484d9190810190615989565b9050831561489a57806001825161486491906158c6565b8151811061487457614874615201565b60200260200101518b61488791906158f6565b9a50614893838b6158c6565b99506148db565b6148a4838c6158c6565b9a5080600182516148b591906158c6565b815181106148c5576148c5615201565b60200260200101518a6148d891906158f6565b99505b505b89899650965050505050505b965096945050505050565b6060614903848460008561490b565b949350505050565b60608247101561496c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105b3565b6001600160a01b0385163b6149c35760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105b3565b600080866001600160a01b031685876040516149df9190615e19565b60006040518083038185875af1925050503d8060008114614a1c576040519150601f19603f3d011682016040523d82523d6000602084013e614a21565b606091505b5091509150614a31828286614a3c565b979650505050505050565b60608315614a4b575081614375565b825115614a5b5782518084602001fd5b8160405162461bcd60e51b81526004016105b39190615fa7565b60405180606001604052806003906020820280368337509192915050565b60008083601f840112614aa557600080fd5b5081356001600160401b03811115614abc57600080fd5b6020830191508360208260051b8501011115614ad757600080fd5b9250929050565b60008060008060408587031215614af457600080fd5b84356001600160401b0380821115614b0b57600080fd5b614b1788838901614a93565b90965094506020870135915080821115614b3057600080fd5b50614b3d87828801614a93565b95989497509550505050565b60008060008060408587031215614b5f57600080fd5b84356001600160401b0380821115614b7657600080fd5b614b8288838901614a93565b90965094506020870135915080821115614b9b57600080fd5b818701915087601f830112614baf57600080fd5b813581811115614bbe57600080fd5b8860208260061b8501011115614bd357600080fd5b95989497505060200194505050565b80356003811061355757600080fd5b600060208284031215614c0357600080fd5b61437582614be2565b6001600160a01b0381168114614c2157600080fd5b50565b803561355781614c0c565b60008060808385031215614c4257600080fd5b6060830184811115614c5357600080fd5b83925035614c6081614c0c565b809150509250929050565b600060208284031215614c7d57600080fd5b813561437581614c0c565b60008060408385031215614c9b57600080fd5b823591506020830135614c6081614c0c565b600080600080600060808688031215614cc557600080fd5b85356001600160401b03811115614cdb57600080fd5b614ce788828901614a93565b9096509450506020860135614cfb81614c0c565b94979396509394604081013594506060013592915050565b600080600060608486031215614d2857600080fd5b8335614d3381614c0c565b92506020840135614d4381614c0c565b929592945050506040919091013590565b600060208284031215614d6657600080fd5b5035919050565b60008060408385031215614d8057600080fd5b82359150614d9060208401614be2565b90509250929050565b60008060008060608587031215614daf57600080fd5b84356001600160401b03811115614dc557600080fd5b614dd187828801614a93565b90989097506020870135966040013595509350505050565b600080600080600060a08688031215614e0157600080fd5b853594506020860135935060408601359250606086013591506080860135614e2881614c0c565b809150509295509295909350565b600080600080600080600060a0888a031215614e5157600080fd5b87356001600160401b0380821115614e6857600080fd5b614e748b838c01614a93565b909950975060208a0135915080821115614e8d57600080fd5b50614e9a8a828b01614a93565b9096509450506040880135614eae81614c0c565b969995985093969295946060840135945060809093013592915050565b634e487b7160e01b600052604160045260246000fd5b608081018181106001600160401b0382111715614f0057614f00614ecb565b60405250565b604081018181106001600160401b0382111715614f0057614f00614ecb565b606081018181106001600160401b0382111715614f0057614f00614ecb565b601f8201601f191681016001600160401b0381118282101715614f6957614f69614ecb565b6040525050565b60405161010081016001600160401b0381118282101715614f9357614f93614ecb565b60405290565b60405160c081016001600160401b0381118282101715614f9357614f93614ecb565b60006001600160401b03821115614fd457614fd4614ecb565b5060051b60200190565b600082601f830112614fef57600080fd5b81356020614ffc82614fbb565b6040516150098282614f44565b83815260059390931b850182019282810191508684111561502957600080fd5b8286015b84811015615044578035835291830191830161502d565b509695505050505050565b60008060006060848603121561506457600080fd5b833592506020808501356001600160401b038082111561508357600080fd5b818701915087601f83011261509757600080fd5b81356150a281614fbb565b6040516150af8282614f44565b82815260059290921b840185019185810191508a8311156150cf57600080fd5b938501935b828510156150f4576150e585614be2565b825293850193908501906150d4565b96505050604087013592508083111561510c57600080fd5b505061511a86828701614fde565b9150509250925092565b60008060008060008060008060c0898b03121561514057600080fd5b88356001600160401b038082111561515757600080fd5b6151638c838d01614a93565b909a50985060208b013591508082111561517c57600080fd5b6151888c838d01614a93565b909850965060408b01359150808211156151a157600080fd5b50890160a0818c0312156151b457600080fd5b935060608901356151c481614c0c565b979a969950949793969295929450505060808201359160a0013590565b602080825260069082015265445a4730303160d01b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016152555761525561522d565b5060010190565b8015158114614c2157600080fd5b81356152758161525c565b60ff1982541660ff82151516811783555050602082013560018201555050565b60408082528181018590526000908660608401835b888110156152da5782356152bd81614c0c565b6001600160a01b03168252602092830192909101906001016152aa565b5084810360208681019190915286825291508690820160005b878110156153225782356153068161525c565b15158252828401358483015291840191908401906001016152f3565b509998505050505050505050565b60008235607e1983360301811261534657600080fd5b9190910192915050565b600082601f83011261536157600080fd5b81356001600160401b0381111561537a5761537a614ecb565b604051615391601f8301601f191660200182614f44565b8181528460208386010111156153a657600080fd5b816020850160208301376000918101602001919091529392505050565b600061010082840312156153d657600080fd5b6153de614f70565b90506153e982614c24565b81526153f760208301614c24565b602082015261540860408301614c24565b604082015261541960608301614c24565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e08201356001600160401b0381111561545557600080fd5b61546184828501615350565b60e08301525092915050565b60006080823603121561547f57600080fd5b60405161548b81614ee1565b823561549681614c0c565b815260208301356001600160401b03808211156154b257600080fd5b6154be368387016153c3565b602084015260408501359150808211156154d757600080fd5b6154e336838701615350565b604084015260608501359150808211156154fc57600080fd5b5061550936828601615350565b60608301525092915050565b60005b83811015615530578181015183820152602001615518565b50506000910152565b60008151808452615551816020860160208601615515565b601f01601f19169290920160200192915050565b60006001600160a01b0380861683526060602084015280855116606084015250602084015161559f60808401826001600160a01b03169052565b5060408401516001600160a01b03811660a08401525060608401516001600160a01b03811660c084015250608084015160e083015260a0840151610100818185015260c086015161012085015260e086015191508061014085015250615609610160840182615539565b9050828103604084015261561d8185615539565b9695505050505050565b6000806040838503121561563a57600080fd5b505080516020909101519092909150565b600060033d11156156645760046000803e5060005160e01c5b90565b600060443d10156156755790565b6040516003193d81016004833e81513d6001600160401b0381602484011181841117156156a457505050505090565b82850191508151818111156156bc5750505050505090565b843d87010160208285010111156156d65750505050505090565b6156e560208286010187614f44565b509095945050505050565b8060005b6002811015612ee85781518452602093840193909101906001016156f4565b6060808252835182820181905260009190608090818501906020808901865b8381101561577557815180516001600160a01b03908116875284820151168487015260408082015190870152870151878601529385019390820190600101615732565b5050829550615786818801896156f0565b50505050509392505050565b60008235609e1983360301811261534657600080fd5b600082601f8301126157b957600080fd5b813560206157c682614fbb565b6040516157d38282614f44565b83815260059390931b85018201928281019150868411156157f357600080fd5b8286015b8481101561504457803561580a81614c0c565b83529183019183016157f7565b600060a0823603121561582957600080fd5b60405160a081016001600160401b03828210818311171561584c5761584c614ecb565b816040528435915061585d82614c0c565b8183526020850135602084015260408501356040840152606085013591508082111561588857600080fd5b615894368387016157a8565b606084015260808501359150808211156158ad57600080fd5b506158ba36828601615350565b60808301525092915050565b81810381811115612eaf57612eaf61522d565b6000602082840312156158eb57600080fd5b81516143758161525c565b80820180821115612eaf57612eaf61522d565b600081518084526020808501945080840160005b838110156159425781516001600160a01b03168752958201959082019060010161591d565b509495945050505050565b85815284602082015260a06040820152600061596c60a0830186615909565b6001600160a01b0394909416606083015250608001529392505050565b6000602080838503121561599c57600080fd5b82516001600160401b038111156159b257600080fd5b8301601f810185136159c357600080fd5b80516159ce81614fbb565b6040516159db8282614f44565b82815260059290921b83018401918481019150878311156159fb57600080fd5b928401925b82841015614a3157835182529284019290840190615a00565b60008235603e1983360301811261534657600080fd5b60006040808336031215615a4257600080fd5b8051615a4d81614f06565b8335615a5881614c0c565b81526020848101356001600160401b0380821115615a7557600080fd5b9086019036601f830112615a8857600080fd5b8135615a9381614fbb565b8651615a9f8282614f44565b82815260059290921b8401850191858101915036831115615abf57600080fd5b8585015b83811015615b4a57803585811115615adb5760008081fd5b8601606036829003601f1901811315615af45760008081fd5b8a51615aff81614f25565b89830135615b0c81614c0c565b8152828c01358a820152908201359087821115615b295760008081fd5b615b37368b84860101615350565b818d015285525050918601918601615ac3565b509486019490945250929695505050505050565b600081518084526020808501945080840160005b8381101561594257815180516001600160a01b031688528301518388015260409096019590820190600101615b72565b6000606082016060835280855180835260808501915060808160051b8601019250602080880160005b83811015615c1657878603607f19018552815180516001600160a01b031687528301516040848801819052615c0281890183615b5e565b975050509382019390820190600101615bcb565b5050839450615c27818701886156f0565b505050509392505050565b8082028115828204841417612eaf57612eaf61522d565b600082615c6657634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615c7d57600080fd5b5051919050565b606081526000835160406060840152615ca060a0840182615b5e565b90506020850151605f19848303016080850152615cbd8282615b5e565b9250505061437560208301846156f0565b600060208284031215615ce057600080fd5b815161437581614c0c565b6000823560be1983360301811261534657600080fd5b600060c08236031215615d1357600080fd5b615d1b614f99565b615d2483614c24565b8152615d3260208401614c24565b60208201526040830135604082015260608301356001600160401b0380821115615d5b57600080fd5b615d6736838701615350565b60608401526080850135915080821115615d8057600080fd5b615d8c368387016157a8565b608084015260a0850135915080821115615da557600080fd5b50615db2368286016157a8565b60a08301525092915050565b60e081526000615dd160e0830187615b5e565b905060206001600160a01b03861681840152604083018560005b6003811015615e0857815183529183019190830190600101615deb565b50505050611d3e60a08301846156f0565b60008251615346818460208701615515565b6001600160e01b0319831681528151600090615e4e816004850160208701615515565b919091016004019392505050565b600060808236031215615e6e57600080fd5b604051615e7a81614ee1565b8235615e8581614c0c565b80825250602083013560208201526040830135604082015260608301356001600160401b03811115615eb657600080fd5b615509368286016157a8565b6000808335601e19843603018112615ed957600080fd5b8301803591506001600160401b03821115615ef357600080fd5b6020019150600581901b3603821315614ad757600080fd5b600080600060608486031215615f2057600080fd5b8351925060208401519150604084015190509250925092565b80516dffffffffffffffffffffffffffff8116811461355757600080fd5b600080600060608486031215615f6c57600080fd5b615f7584615f39565b9250615f8360208501615f39565b9150604084015163ffffffff81168114615f9c57600080fd5b809150509250925092565b602081526000614375602083018461553956fea26469706673582212203bf5925e8dffa62c92befa2f65ca47d7ce1cd32cf4f075a3b3bed113e2e18bc064736f6c634300081100330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000013cdd11d7c5cc00769f8bfd2ca102408d00ad4530000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf127000000000000000000000000013cdd11d7c5cc00769f8bfd2ca102408d00ad45300000000000000000000000033174db98548ef366b8e156e02422731ede18b9d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5e0829caced8ffdd4de3c43696c57f7d7a678ff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001e
Deployed Bytecode
0x6080604052600436106101b05760003560e01c806380dd9a1f116100ec578063e2edbb671161008a578063f50b44a211610064578063f50b44a214610516578063f5422efd14610536578063f568859a14610556578063fd4a9c0d1461057657600080fd5b8063e2edbb67146104cd578063e935b7b1146104e0578063f1ac7ffc146104f657600080fd5b80639efff690116100c65780639efff69014610449578063af1af3b914610481578063bc063e1a146104a1578063e1a45218146104b757600080fd5b806380dd9a1f146103c557806399572d6f146104165780639ca072d01461043657600080fd5b806348c545a3116101595780636bb14547116101335780636bb145471461033c5780636ccae0541461034f578063760615041461036f578063770d88d11461038f57600080fd5b806348c545a3146102de5780635aa6e675146102fe5780635b1f47651461031c57600080fd5b806328394f911161018a57806328394f911461024f5780632d68efc91461028a57806342c039af146102be57600080fd5b806305cda745146101bc5780630621153b146101de57806319f6c38c1461022f57600080fd5b366101b757005b600080fd5b3480156101c857600080fd5b506101dc6101d7366004614ade565b610589565b005b3480156101ea57600080fd5b506102127f0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d81565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561023b57600080fd5b506101dc61024a366004614b49565b610680565b34801561025b57600080fd5b5061027c61026a366004614bf1565b60046020526000908152604090205481565b604051908152602001610226565b34801561029657600080fd5b506102127f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf127081565b3480156102ca57600080fd5b506101dc6102d9366004614c2f565b6107b8565b3480156102ea57600080fd5b506101dc6102f9366004614c6b565b610934565b34801561030a57600080fd5b506000546001600160a01b0316610212565b34801561032857600080fd5b506101dc610337366004614c88565b6109e4565b6101dc61034a366004614cad565b610ad9565b34801561035b57600080fd5b506101dc61036a366004614d13565b610fcd565b34801561037b57600080fd5b50600354610212906001600160a01b031681565b34801561039b57600080fd5b506102126103aa366004614d54565b6006602052600090815260409020546001600160a01b031681565b3480156103d157600080fd5b506103ff6103e0366004614c6b565b6007602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610226565b34801561042257600080fd5b506101dc610431366004614c6b565b6110b8565b6101dc610444366004614cad565b61117c565b34801561045557600080fd5b5061027c610464366004614d6d565b600560209081526000928352604080842090915290825290205481565b34801561048d57600080fd5b50600154610212906001600160a01b031681565b3480156104ad57600080fd5b5061027c61138881565b3480156104c357600080fd5b5061027c61271081565b6101dc6104db366004614d99565b6116f9565b3480156104ec57600080fd5b5061027c60025481565b34801561050257600080fd5b506101dc610511366004614d54565b611ae9565b34801561052257600080fd5b5061027c610531366004614de9565b611be0565b34801561054257600080fd5b506101dc610551366004614e36565b611d47565b34801561056257600080fd5b506101dc61057136600461504f565b611fcd565b6101dc610584366004615124565b6120fc565b6000546001600160a01b031633146105bc5760405162461bcd60e51b81526004016105b3906151e1565b60405180910390fd5b60005b83811015610650578282828181106105d9576105d9615201565b90506020020135600460008787858181106105f6576105f6615201565b905060200201602081019061060b9190614bf1565b600281111561061c5761061c615217565b600281111561062d5761062d615217565b81526020810191909152604001600020558061064881615243565b9150506105bf565b506040517f023f6f64c24d183eaafe34dcf00b3c910b235bd19e113cc08903bec4d284652f90600090a150505050565b6000546001600160a01b031633146106aa5760405162461bcd60e51b81526004016105b3906151e1565b60005b838110156107745760008585838181106106c9576106c9615201565b90506020020160208101906106de9190614c6b565b90506001600160a01b0381166107205760405162461bcd60e51b8152602060048201526007602482015266222d299818189b60c91b60448201526064016105b3565b83838381811061073257610732615201565b6001600160a01b0384166000908152600760205260409081902091029290920191905061075f828261526a565b905050508061076d90615243565b90506106ad565b507f101b604ed068a7688b1d926dc5891e4b37f9ac9f133bd36f6500c60dfd5104e0848484846040516107aa9493929190615295565b60405180910390a150505050565b6000546001600160a01b031633146107e25760405162461bcd60e51b81526004016105b3906151e1565b6001600160a01b0381166108215760405162461bcd60e51b8152602060048201526006602482015265445a4630303160d01b60448201526064016105b3565b61138882351180159061083a5750611388602083013511155b801561084c5750611388604083013511155b6108815760405162461bcd60e51b8152602060048201526006602482015265222d2318181960d11b60448201526064016105b3565b600280546000908152600560208181526040808420848052825280842087359055845484528282528084206001855282528084208783013590558454845291815281832084845281528183208683013590558354835260069052812080546001600160a01b0319166001600160a01b0385161790558154919061090383615243565b909155506040517f7048f4116e78f3e5e51282b26fe38719c961b8ca5b63fb602278562ca629a14b90600090a25050565b6000546001600160a01b0316331461095e5760405162461bcd60e51b81526004016105b3906151e1565b6001600160a01b03811661099d5760405162461bcd60e51b8152602060048201526006602482015265445a4630303160d01b60448201526064016105b3565b600180546001600160a01b0319166001600160a01b0383161790556040517fb46ce5ba362e5bea9bdeefea05b72620f6d64e553f8a04e96678bb555b50299290600090a150565b6000546001600160a01b03163314610a0e5760405162461bcd60e51b81526004016105b3906151e1565b6002548210610a485760405162461bcd60e51b8152602060048201526006602482015265445a4630303360d01b60448201526064016105b3565b6001600160a01b038116610a875760405162461bcd60e51b8152602060048201526006602482015265445a4630303160d01b60448201526064016105b3565b60008281526006602052604080822080546001600160a01b0319166001600160a01b0385161790555183917fb799f1a20f2b0b7dde2e06abfe87cf23a21999428ff97fe111e210fd04f6e16091a25050565b6001600160a01b038316610b185760405162461bcd60e51b8152602060048201526006602482015265445a5330303160d01b60448201526064016105b3565b6000846001600160401b03811115610b3257610b32614ecb565b604051908082528060200260200182016040528015610b8457816020015b604080516080810182526000808252602080830182905292820181905260608201528252600019909201910181610b505790505b5090506000806000610b9886866000612b9a565b92509250925060005b88811015610f605760008a8a83818110610bbd57610bbd615201565b9050602002810190610bcf9190615330565b610bd89061546d565b6020810151606001519091506001600160a01b031615610c235760405162461bcd60e51b8152602060048201526006602482015265222d2998181960d11b60448201526064016105b3565b602081015160c0015160011615610c655760405162461bcd60e51b8152602060048201526006602482015265445a5330303360d01b60448201526064016105b3565b6000610c78826020015160000151612e7b565b15610c8c5750602081015160800151610ccc565b610ccc82606001518360200151600001517f0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d856020015160800151612eb5565b815160208301516040808501519051623e012960e91b81526001600160a01b037f0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d1693637c025200938693610d2393600401615565565b604080518083038185885af193505050508015610d5d575060408051601f3d908101601f19168201909252610d5a91810190615627565b60015b610e8b57610d6961564b565b806308c379a003610e7f5750610d7d615667565b80610d885750610e81565b60405180608001604052808460200151600001516001600160a01b031681526020018460200151602001516001600160a01b0316815260200184602001516080015181526020016000815250888581518110610de657610de6615201565b6020026020010181905250610e02836020015160000151612e7b565b15610e1e57610e1933846020015160800151612eee565b610e79565b602083015151610e59906001600160a01b03167f0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d6000612f99565b610e79336020850151608081015190516001600160a01b031691906130e8565b50610f4d565b505b3d6000803e3d6000fd5b836020015160a00151821015610ecc5760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b60405180608001604052808560200151600001516001600160a01b031681526020018560200151602001516001600160a01b03168152602001856020015160800151815260200183815250898681518110610f2957610f29615201565b6020026020010181905250610f4a8460200151602001518d88858c8c613118565b50505b505080610f5990615243565b9050610ba1565b506001600160a01b038716336001600160a01b03167f81c190be312be4e4c986228937957a7fe3dab07e6e2c8e5bf8068154044117b986604051806040016040528088815260200187815250604051610fba929190615713565b60405180910390a3505050505050505050565b6000546001600160a01b03163314610ff75760405162461bcd60e51b81526004016105b3906151e1565b6001600160a01b0382166110355760405162461bcd60e51b8152602060048201526005602482015264445a30303160d81b60448201526064016105b3565b61103e83612e7b565b156110525761104d8282612eee565b611066565b6110666001600160a01b03841683836130e8565b826001600160a01b0316826001600160a01b03167f77023e19c7343ad491fd706c36335ca0e738340a91f29b1fd81e2673d44896c4836040516110ab91815260200190565b60405180910390a3505050565b6000546001600160a01b031633146110e25760405162461bcd60e51b81526004016105b3906151e1565b6001600160a01b0381166111215760405162461bcd60e51b8152602060048201526006602482015265222d2398181960d11b60448201526064016105b3565b600080546040516001600160a01b03808516939216917f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd291a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0383166111bb5760405162461bcd60e51b8152602060048201526006602482015265445a5330303160d01b60448201526064016105b3565b6000846001600160401b038111156111d5576111d5614ecb565b60405190808252806020026020018201604052801561122757816020015b6040805160808101825260008082526020808301829052928201819052606082015282526000199092019101816111f35790505b509050600080600061123b86866000612b9a565b9250925092506112496131d0565b60005b88811015610f605760008a8a8381811061126857611268615201565b905060200281019061127a9190615792565b61128390615817565b90506000816060015160008151811061129e5761129e615201565b602002602001015190506000826060015160018460600151516112c191906158c6565b815181106112d1576112d1615201565b602002602001015190506112e481612e7b565b1561131a5760405162461bcd60e51b8152602060048201526006602482015265088b4a66060760d31b60448201526064016105b3565b61132382612e7b565b15611411577f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270836060015160008151811061136057611360615201565b6001600160a01b0392831660209182029290920181019190915284519085015160405163095ea7b360e01b8152918316600483015260248201527f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12709091169063095ea7b3906044016020604051808303816000875af11580156113e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140b91906158d9565b50611429565b61142983608001518385600001518660200151612eb5565b82600001516001600160a01b03166338ed17398460200151856040015186606001513042603c61145991906158f6565b6040518663ffffffff1660e01b815260040161147995949392919061594d565b6000604051808303816000875af19250505080156114b957506040513d6000823e601f3d908101601f191682016040526114b69190810190615989565b60015b611618576114c561564b565b806308c379a003610e7f57506114d9615667565b806114e45750610e81565b6040518060800160405280846001600160a01b03168152602001836001600160a01b0316815260200185602001518152602001600081525089868151811061152e5761152e615201565b602002602001018190525061154283612e7b565b156115e0576020840151604051632e1a7d4d60e01b815260048101919091527f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156115af57600080fd5b505af11580156115c3573d6000803e3d6000fd5b505050506115db6115d13390565b8560200151612eee565b611612565b83516115f8906001600160a01b038516906000612f99565b6116123360208601516001600160a01b03861691906130e8565b506116e5565b6000816001835161162991906158c6565b8151811061163957611639615201565b6020026020010151905084604001518110156116805760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b6040518060800160405280856001600160a01b03168152602001846001600160a01b0316815260200186602001518152602001828152508a87815181106116c9576116c9615201565b60200260200101819052506116e2838e89848d8d61324d565b50505b505050806116f290615243565b905061124c565b6000836001600160401b0381111561171357611713614ecb565b60405190808252806020026020018201604052801561175957816020015b6040805180820190915260008152606060208201528152602001906001900390816117315790505b509050600080600061176d86866002612b9a565b919450925090503460005b88811015611a5a5760008a8a8381811061179457611794615201565b90506020028101906117a69190615a19565b6117af90615a2f565b80519091506001600160a01b03166117f25760405162461bcd60e51b8152602060048201526006602482015265445a5330303160d01b60448201526064016105b3565b60008160200151516001600160401b0381111561181157611811614ecb565b60405190808252806020026020018201604052801561185657816020015b604080518082019091526000808252602082015281526020019060019003908161182f5790505b50905060005b826020015151811015611a075760008360200151828151811061188157611881615201565b60200260200101519050600080600061189f84602001518d8d613320565b925092509250604051806040016040528085600001516001600160a01b0316815260200185602001518152508686815181106118dd576118dd615201565b60200260200101819052506118f58460000151612e7b565b156119875783602001518910156119375760405162461bcd60e51b8152602060048201526006602482015265445a5330303360d01b60448201526064016105b3565b6020840151611946908a6158c6565b9850611956876000015184612eee565b811561197257600154611972906001600160a01b031683612eee565b8015611982576119828a82612eee565b6119f2565b6119998460000151856040015161337a565b6119b233885186516001600160a01b03169190866134b4565b81156119d5576119d53360015486516001600160a01b03908116929116856134b4565b80156119f2576119f23385516001600160a01b0316908c846134b4565b5050505080611a0090615243565b905061185c565b50604051806040016040528083600001516001600160a01b0316815260200182815250888481518110611a3c57611a3c615201565b6020026020010181905250505080611a5390615243565b9050611778565b508015611a925760405162461bcd60e51b8152602060048201526006602482015265222d2998181b60d11b60448201526064016105b3565b60408051808201825285815260208101859052905133917fd3b45d0daff5a08d16c97b882a9056c67b55f8d36f4d3c00c7b6a1c8a8d8de9591611ad6918991615ba2565b60405180910390a2505050505050505050565b6000546001600160a01b03163314611b135760405162461bcd60e51b81526004016105b3906151e1565b6002548110611b4d5760405162461bcd60e51b8152602060048201526006602482015265445a4630303360d01b60448201526064016105b3565b6000818152600660205260409020546001600160a01b0316611b9a5760405162461bcd60e51b81526020600482015260066024820152651116918c0c0d60d21b60448201526064016105b3565b60008181526006602052604080822080546001600160a01b03191690555182917fcc5a352d2149d712d03e00be4696d621598de55d2f46c41d6c671524f51b072591a250565b6000611bec8486615c32565b611bf68488615c32565b1015611c2e5760405162461bcd60e51b8152602060048201526007602482015266111694cc0c0c4d60ca1b60448201526064016105b3565b6001600160a01b03821660009081526007602052604081206001015490611c57826127106158c6565b905060008683611c6a6127106002615c32565b611c7491906158c6565b611c7e9190615c32565b90506000611c8c888a615c32565b611c96888c615c32565b611ca091906158c6565b9050600088611caf898c6158f6565b611cbb61271085615c32565b611cc59190615c49565b611ccf9190615c32565b90506000611cdd8286615c32565b611ce8906004615c32565b90506000611d0982611cfa8780615c32565b611d0491906158f6565b6134ec565b90506000611d1786836158c6565b90506000611d26886002615c32565b9050611d328183615c49565b99505050505050505050505b95945050505050565b6001600160a01b038316611d865760405162461bcd60e51b8152602060048201526006602482015265445a5330303160d01b60448201526064016105b3565b83611dbc5760405162461bcd60e51b8152602060048201526006602482015265445a5330303960d01b60448201526064016105b3565b6040805180820190915260608082526020820152866001600160401b03811115611de857611de8614ecb565b604051908082528060200260200182016040528015611e2d57816020015b6040805180820190915260008082526020820152815260200190600190039081611e065790505b508152611e3b8560016158f6565b6001600160401b03811115611e5257611e52614ecb565b604051908082528060200260200182016040528015611e9757816020015b6040805180820190915260008082526020820152815260200190600190039081611e705790505b50602082015260008080611ead86866001612b9a565b925092509250611ebd8b8b61355c565b84526040516370a0823160e01b8152306004820152611f5a908a908a908a9085907f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316906370a0823190602401602060405180830381865afa158015611f2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f539190615c6b565b888861382f565b60208501526001600160a01b038716336001600160a01b03167f1c2a63767d9cdc877fc97d92e65e9bb79e8502ec148af3f7bf7b4292ceb416b986604051806040016040528088815260200187815250604051611fb8929190615c84565b60405180910390a35050505050505050505050565b6000546001600160a01b03163314611ff75760405162461bcd60e51b81526004016105b3906151e1565b60025483106120315760405162461bcd60e51b8152602060048201526006602482015265445a4630303360d01b60448201526064016105b3565b60005b82518110156120cb5781818151811061204f5761204f615201565b602002602001015160056000868152602001908152602001600020600085848151811061207e5761207e615201565b6020026020010151600281111561209757612097615217565b60028111156120a8576120a8615217565b8152602081019190915260400160002055806120c381615243565b915050612034565b5060405183907fbed46add49f1852fbdc678819bb401f7f59ac14a61bbfa2bb5a9ed73f788bcbd90600090a2505050565b6001600160a01b03831661213b5760405162461bcd60e51b8152602060048201526006602482015265445a5330303160d01b60448201526064016105b3565b6007600061214c6020870187614c6b565b6001600160a01b0316815260208101919091526040016000205460ff1661219e5760405162461bcd60e51b8152602060048201526006602482015265445a5330303560d01b60448201526064016105b3565b60006121aa86896158f6565b6121b59060016158f6565b6001600160401b038111156121cc576121cc614ecb565b60405190808252806020026020018201604052801561221157816020015b60408051808201909152600080825260208201528152602001906001900390816121ea5790505b509050600080600061222586866001612b9a565b91945092509050600061223e60408a0160208b01614c6b565b6001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561227b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229f9190615cce565b905060006122b360408b0160208c01614c6b565b6001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123149190615cce565b9050600034156123dc577f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561237957600080fd5b505af115801561238d573d6000803e3d6000fd5b5050505050604051806040016040528060006001600160a01b031681526020013481525087600189516123c091906158c6565b815181106123d0576123d0615201565b60200260200101819052505b8d81101561277a5760008f8f838181106123f8576123f8615201565b905060200281019061240a9190615330565b6124139061546d565b6020810151519091507f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b039081169082161480159061246b5750846001600160a01b0316816001600160a01b031614155b80156124895750836001600160a01b0316816001600160a01b031614155b156126f4576020820151606001516001600160a01b0316156124d65760405162461bcd60e51b8152602060048201526006602482015265222d2998181960d11b60448201526064016105b3565b602082015160c00151600116156125185760405162461bcd60e51b8152602060048201526006602482015265445a5330303360d01b60448201526064016105b3565b60208201515161252790612e7b565b1561255e5760405162461bcd60e51b8152602060048201526007602482015266445a533030313160c81b60448201526064016105b3565b7f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b03168260200151602001516001600160a01b0316146125d15760405162461bcd60e51b8152602060048201526007602482015266222d299818189960c91b60448201526064016105b3565b61261182606001518360200151600001517f0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d856020015160800151612eb5565b815160208301516040808501519051623e012960e91b81526000936001600160a01b037f0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d1693637c0252009361266993600401615565565b60408051808303816000875af1158015612687573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ab9190615627565b509050826020015160a0015181116126ee5760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b50612724565b61270281836060015161337a565b612724336020840151608081015190516001600160a01b0316919030906134b4565b6040518060400160405280826001600160a01b0316815260200183602001516080015181525089848151811061275c5761275c615201565b602002602001018190525050508061277390615243565b90506123dc565b60005b8c811015612a5e5760008e8e8381811061279957612799615201565b90506020028101906127ab9190615ceb565b6127b490615d01565b80516001600160a01b031660009081526007602052604090205490915060ff1661280a5760405162461bcd60e51b8152602060048201526007602482015266445a533030313360c81b60448201526064016105b3565b600081602001516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa15801561284e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128729190615cce565b9050600082602001516001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128dc9190615cce565b90506000806128f18585858860000151613cc7565b91509150612978848387608001517f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316886001600160a01b03161415801561295357508c6001600160a01b0316886001600160a01b031614155b801561297157508b6001600160a01b0316886001600160a01b031614155b8951613dac565b6129fa83828760a001517f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316876001600160a01b0316141580156129d657508c6001600160a01b0316876001600160a01b031614155b801561297157508b6001600160a01b0316876001600160a01b031614158951613dac565b604051806040016040528086602001516001600160a01b0316815260200186604001518152508d8789612a2d91906158f6565b81518110612a3d57612a3d615201565b6020026020010181905250505050505080612a5790615243565b905061277d565b506000612a6c8c8585613eb4565b805190915060408d01351115612aad5760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b612acd612ac060408e0160208f01614c6b565b82518d9088908b8b61437c565b602081015115612af157612af13360208301516001600160a01b03871691906130e8565b604081015115612b1557612b153360408301516001600160a01b03861691906130e8565b6001600160a01b038b16336001600160a01b03167f5bf5b0a8ee8b7b80862a13ba8a4c617db5a2e2a415b9189f9e5d5e852e9115278a8f6020016020810190612b5e9190614c6b565b6040805180820182528d8152602081018d90529051612b809392918891615dbe565b60405180910390a350505050505050505050505050505050565b600080600060025486108015612bc657506000868152600660205260409020546001600160a01b031615155b612bfb5760405162461bcd60e51b8152602060048201526006602482015265445a4630303360d01b60448201526064016105b3565b600060046000866002811115612c1357612c13615217565b6002811115612c2457612c24615217565b81526020019081526020016000205490508560001480612c42575080155b15612cb15760008781526005602052604081208291876002811115612c6957612c69615217565b6002811115612c7a57612c7a615217565b815260208082019290925260409081016000908120548b82526006909352205491955093506001600160a01b03169150612e729050565b6003546000906001600160a01b031662fdd58e336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018a9052604401602060405180830381865afa158015612d10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d349190615c6b565b11612d6a5760405162461bcd60e51b8152602060048201526006602482015265445a4630303560d01b60448201526064016105b3565b6003546040516306e1dd2f60e11b81526004810188905260009182916001600160a01b0390911690630dc3ba5e906024016040805180830381865afa158015612db7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddb9190615627565b9150915080421015612e0b57612710612df48385615c32565b612dfe9190615c49565b612e0890846158c6565b92505b60008981526005602052604081208491896002811115612e2d57612e2d615217565b6002811115612e3e57612e3e615217565b815260208082019290925260409081016000908120548d82526006909352205491975095506001600160a01b031693505050505b93509350939050565b60006001600160a01b0382161580612eaf57506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b92915050565b612ebf838561337a565b612ed46001600160a01b0384163330846134b4565b612ee86001600160a01b0384168383612f99565b50505050565b604080516000808252602082019092526001600160a01b038416908390604051612f189190615e19565b60006040518083038185875af1925050503d8060008114612f55576040519150601f19603f3d011682016040523d82523d6000602084013e612f5a565b606091505b5050905080612f945760405162461bcd60e51b8152602060048201526006602482015265445a5330303760d01b60448201526064016105b3565b505050565b8015806130135750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612fed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130119190615c6b565b155b6130855760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084016105b3565b6040516001600160a01b038316602482015260448101829052612f9490849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526143a7565b6040516001600160a01b038316602482015260448101829052612f9490849063a9059cbb60e01b906064016130b1565b6000806000613128868686613320565b92509250925061313789612e7b565b15613177576131468884612eee565b811561316257600154613162906001600160a01b031683612eee565b8015613172576131728782612eee565b6131c5565b61318b6001600160a01b038a1689856130e8565b81156131ab576001546131ab906001600160a01b038b81169116846130e8565b80156131c5576131c56001600160a01b038a1688836130e8565b505050505050505050565b341561324b577f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561323157600080fd5b505af1158015613245573d6000803e3d6000fd5b50505050505b565b600080600061325d868686613320565b9250925092507f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316896001600160a01b03160361317757604051632e1a7d4d60e01b8152600481018790527f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156132fe57600080fd5b505af1158015613312573d6000803e3d6000fd5b505050506131468884612eee565b60008080806127106133328789615c32565b61333c9190615c49565b9050600061271061334d878a615c32565b6133579190615c49565b905061336381836158f6565b61336d90896158c6565b9891975095509350505050565b8051156134b05760006060825160e00361341a576040516001600160a01b038516906133b39063d505accf60e01b908690602001615e2b565b60408051601f19818403018152908290526133cd91615e19565b6000604051808303816000865af19150503d806000811461340a576040519150601f19603f3d011682016040523d82523d6000602084013e61340f565b606091505b50909250905061347a565b825161010003613449576040516001600160a01b038516906133b3906323f2ebc360e21b908690602001615e2b565b60405162461bcd60e51b8152602060048201526006602482015265445a5030303160d01b60448201526064016105b3565b81612ee85760405162461bcd60e51b8152602060048201526006602482015265222d2818181960d11b60448201526064016105b3565b5050565b6040516001600160a01b0380851660248301528316604482015260648101829052612ee89085906323b872dd60e01b906084016130b1565b6000600382111561354d5750806000613506600283615c49565b6135119060016158f6565b90505b818110156135475790508060028161352c8186615c49565b61353691906158f6565b6135409190615c49565b9050613514565b50919050565b8115613557575060015b919050565b60606000826001600160401b0381111561357857613578614ecb565b6040519080825280602002602001820160405280156135bd57816020015b60408051808201909152600080825260208201528152602001906001900390816135965790505b50905060005b838110156138275760008585838181106135df576135df615201565b90506020028101906135f19190615ceb565b6135fa90615d01565b80516001600160a01b031660009081526007602052604090205490915060ff1661364f5760405162461bcd60e51b8152602060048201526006602482015265445a5330303560d01b60448201526064016105b3565b600081602001516001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015613693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136b79190615cce565b9050600082602001516001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156136fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137219190615cce565b90506000806137368585858860000151613cc7565b91509150613784848387608001517f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316886001600160a01b031614158960000151613dac565b6137ce83828760a001517f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316876001600160a01b031614158960000151613dac565b604051806040016040528086602001516001600160a01b03168152602001866040015181525087878151811061380657613806615201565b602002602001018190525050505050508061382090615243565b90506135c3565b509392505050565b60606000876001600160401b0381111561384b5761384b614ecb565b60405190808252806020026020018201604052801561389057816020015b60408051808201909152600080825260208201528152602001906001900390816138695790505b50905060005b88811015613cba5760008a8a838181106138b2576138b2615201565b90506020028101906138c49190615330565b6138cd90615e5c565b905060006138dc60018c6158c6565b830361396f576040516370a0823160e01b81523060048201527f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316906370a0823190602401602060405180830381865afa158015613946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061396a9190615c6b565b61398c565b6127108260200151896139829190615c32565b61398c9190615c49565b9050816060015151600003613ae45781604001518110156139d85760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b60008060006139e8848b8b613320565b604051632e1a7d4d60e01b81526004810188905292955090935091506001600160a01b037f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12701690632e1a7d4d90602401600060405180830381600087803b158015613a5257600080fd5b505af1158015613a66573d6000803e3d6000fd5b50505050613a748d84612eee565b8115613a9057600154613a90906001600160a01b031683612eee565b8015613aa057613aa08c82612eee565b604051806040016040528060006001600160a01b0316815260200185815250878781518110613ad157613ad1615201565b6020026020010181905250505050613ca7565b6060820151805160009190613afb906001906158c6565b81518110613b0b57613b0b615201565b6020026020010151905060008290507f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316826001600160a01b031614613bbb5783516001600160a01b031660009081526007602052604090205460ff16613ba55760405162461bcd60e51b8152602060048201526006602482015265445a5330303560d01b60448201526064016105b3565b613bb88385606001518660000151614479565b90505b8360400151811015613bf85760405162461bcd60e51b8152602060048201526006602482015265111694cc0c0d60d21b60448201526064016105b3565b6000806000613c08848d8d613320565b925092509250613c2c8f84876001600160a01b03166130e89092919063ffffffff16565b8115613c4c57600154613c4c906001600160a01b038781169116846130e8565b8015613c6657613c666001600160a01b0386168f836130e8565b6040518060400160405280866001600160a01b0316815260200185815250898981518110613c9657613c96615201565b602002602001018190525050505050505b505080613cb390615243565b9050613896565b5098975050505050505050565b600080613ce286606001518760200151858960400151612eb5565b826001600160a01b031663baa2abde868689604001516000803042603c613d0991906158f6565b60405160e089901b6001600160e01b03191681526001600160a01b039788166004820152958716602487015260448601949094526064850192909252608484015290921660a482015260c481019190915260e40160408051808303816000875af1158015613d7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d9f9190615627565b9097909650945050505050565b81156132455760405163095ea7b360e01b81526001600160a01b0382811660048301526024820186905286169063095ea7b3906044016020604051808303816000875af1158015613e01573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e2591906158d9565b506001600160a01b0381166338ed17398560008630613e4542603c6158f6565b6040518663ffffffff1660e01b8152600401613e6595949392919061594d565b6000604051808303816000875af1158015613e84573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613eac9190810190615989565b505050505050565b613ebc614a75565b6040516370a0823160e01b81523060048201526000907f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316906370a0823190602401602060405180830381865afa158015613f23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f479190615c6b565b90508015614049577f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316846001600160a01b031614613fe957613fe7613f96600283615c49565b613fa36060880188615ec2565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250613fe2925050506020890189614c6b565b614479565b505b7f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12706001600160a01b0316836001600160a01b03161461404957614047614030600283615c49565b61403a90836158c6565b613fa36080880188615ec2565b505b60008061414561405f6040890160208a01614c6b565b6040516370a0823160e01b8152306004820152889088906001600160a01b038316906370a0823190602401602060405180830381865afa1580156140a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140cb9190615c6b565b6040516370a0823160e01b81523060048201526001600160a01b038b16906370a0823190602401602060405180830381865afa15801561410f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141339190615c6b565b61414060208e018e614c6b565b6145cc565b90925090506001600160a01b03861663095ea7b361416660208a018a614c6b565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018590526044016020604051808303816000875af11580156141b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141d791906158d9565b506001600160a01b03851663095ea7b36141f460208a018a614c6b565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af1158015614241573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061426591906158d9565b506000808061427760208b018b614c6b565b6001600160a01b031663e8e337008a8a88886000803061429842603c6158f6565b60405160e08a901b6001600160e01b03191681526001600160a01b039889166004820152968816602488015260448701959095526064860193909352608485019190915260a484015290921660c482015260e4810191909152610104016060604051808303816000875af1158015614314573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143389190615f0b565b9250925092506040518060600160405280828152602001848761435b91906158c6565b815260200161436a84876158c6565b905296505050505050505b9392505050565b600080600061438c868686613320565b9194509250905061318b6001600160a01b038a1689856130e8565b60006143fc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166148f49092919063ffffffff16565b805190915015612f94578080602001905181019061441a91906158d9565b612f945760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105b3565b60405163095ea7b360e01b81526001600160a01b038281166004830152602482018590526000917f0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12709091169063095ea7b3906044016020604051808303816000875af11580156144ed573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061451191906158d9565b5060006001600160a01b0383166338ed17398683873061453242603c6158f6565b6040518663ffffffff1660e01b815260040161455295949392919061594d565b6000604051808303816000875af1158015614571573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526145999190810190615989565b905080600182516145aa91906158c6565b815181106145ba576145ba615201565b60200260200101519150509392505050565b600080600080896001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015614610573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146349190615f57565b506dffffffffffffffffffffffffffff91821693501690506146568782615c32565b6146608784615c32565b036146725786869350935050506148e9565b600061467e8883615c32565b6146888885615c32565b1190506000816146a45761469f898986868b611be0565b6146b1565b6146b1888a85878b611be0565b6040805160028082526060820183529293506000929091602083019080368337019050509050826146e3578b8b6146e6565b8a8c5b826000815181106146f9576146f9615201565b602002602001018360018151811061471357614713615201565b6001600160a01b0393841660209182029290920101529116905281156148dd578060008151811061474657614746615201565b602090810291909101015160405163095ea7b360e01b81526001600160a01b038a81166004830152602482018590529091169063095ea7b3906044016020604051808303816000875af11580156147a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147c591906158d9565b5060006001600160a01b0389166338ed1739848385306147e642603c6158f6565b6040518663ffffffff1660e01b815260040161480695949392919061594d565b6000604051808303816000875af1158015614825573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261484d9190810190615989565b9050831561489a57806001825161486491906158c6565b8151811061487457614874615201565b60200260200101518b61488791906158f6565b9a50614893838b6158c6565b99506148db565b6148a4838c6158c6565b9a5080600182516148b591906158c6565b815181106148c5576148c5615201565b60200260200101518a6148d891906158f6565b99505b505b89899650965050505050505b965096945050505050565b6060614903848460008561490b565b949350505050565b60608247101561496c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105b3565b6001600160a01b0385163b6149c35760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105b3565b600080866001600160a01b031685876040516149df9190615e19565b60006040518083038185875af1925050503d8060008114614a1c576040519150601f19603f3d011682016040523d82523d6000602084013e614a21565b606091505b5091509150614a31828286614a3c565b979650505050505050565b60608315614a4b575081614375565b825115614a5b5782518084602001fd5b8160405162461bcd60e51b81526004016105b39190615fa7565b60405180606001604052806003906020820280368337509192915050565b60008083601f840112614aa557600080fd5b5081356001600160401b03811115614abc57600080fd5b6020830191508360208260051b8501011115614ad757600080fd5b9250929050565b60008060008060408587031215614af457600080fd5b84356001600160401b0380821115614b0b57600080fd5b614b1788838901614a93565b90965094506020870135915080821115614b3057600080fd5b50614b3d87828801614a93565b95989497509550505050565b60008060008060408587031215614b5f57600080fd5b84356001600160401b0380821115614b7657600080fd5b614b8288838901614a93565b90965094506020870135915080821115614b9b57600080fd5b818701915087601f830112614baf57600080fd5b813581811115614bbe57600080fd5b8860208260061b8501011115614bd357600080fd5b95989497505060200194505050565b80356003811061355757600080fd5b600060208284031215614c0357600080fd5b61437582614be2565b6001600160a01b0381168114614c2157600080fd5b50565b803561355781614c0c565b60008060808385031215614c4257600080fd5b6060830184811115614c5357600080fd5b83925035614c6081614c0c565b809150509250929050565b600060208284031215614c7d57600080fd5b813561437581614c0c565b60008060408385031215614c9b57600080fd5b823591506020830135614c6081614c0c565b600080600080600060808688031215614cc557600080fd5b85356001600160401b03811115614cdb57600080fd5b614ce788828901614a93565b9096509450506020860135614cfb81614c0c565b94979396509394604081013594506060013592915050565b600080600060608486031215614d2857600080fd5b8335614d3381614c0c565b92506020840135614d4381614c0c565b929592945050506040919091013590565b600060208284031215614d6657600080fd5b5035919050565b60008060408385031215614d8057600080fd5b82359150614d9060208401614be2565b90509250929050565b60008060008060608587031215614daf57600080fd5b84356001600160401b03811115614dc557600080fd5b614dd187828801614a93565b90989097506020870135966040013595509350505050565b600080600080600060a08688031215614e0157600080fd5b853594506020860135935060408601359250606086013591506080860135614e2881614c0c565b809150509295509295909350565b600080600080600080600060a0888a031215614e5157600080fd5b87356001600160401b0380821115614e6857600080fd5b614e748b838c01614a93565b909950975060208a0135915080821115614e8d57600080fd5b50614e9a8a828b01614a93565b9096509450506040880135614eae81614c0c565b969995985093969295946060840135945060809093013592915050565b634e487b7160e01b600052604160045260246000fd5b608081018181106001600160401b0382111715614f0057614f00614ecb565b60405250565b604081018181106001600160401b0382111715614f0057614f00614ecb565b606081018181106001600160401b0382111715614f0057614f00614ecb565b601f8201601f191681016001600160401b0381118282101715614f6957614f69614ecb565b6040525050565b60405161010081016001600160401b0381118282101715614f9357614f93614ecb565b60405290565b60405160c081016001600160401b0381118282101715614f9357614f93614ecb565b60006001600160401b03821115614fd457614fd4614ecb565b5060051b60200190565b600082601f830112614fef57600080fd5b81356020614ffc82614fbb565b6040516150098282614f44565b83815260059390931b850182019282810191508684111561502957600080fd5b8286015b84811015615044578035835291830191830161502d565b509695505050505050565b60008060006060848603121561506457600080fd5b833592506020808501356001600160401b038082111561508357600080fd5b818701915087601f83011261509757600080fd5b81356150a281614fbb565b6040516150af8282614f44565b82815260059290921b840185019185810191508a8311156150cf57600080fd5b938501935b828510156150f4576150e585614be2565b825293850193908501906150d4565b96505050604087013592508083111561510c57600080fd5b505061511a86828701614fde565b9150509250925092565b60008060008060008060008060c0898b03121561514057600080fd5b88356001600160401b038082111561515757600080fd5b6151638c838d01614a93565b909a50985060208b013591508082111561517c57600080fd5b6151888c838d01614a93565b909850965060408b01359150808211156151a157600080fd5b50890160a0818c0312156151b457600080fd5b935060608901356151c481614c0c565b979a969950949793969295929450505060808201359160a0013590565b602080825260069082015265445a4730303160d01b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016152555761525561522d565b5060010190565b8015158114614c2157600080fd5b81356152758161525c565b60ff1982541660ff82151516811783555050602082013560018201555050565b60408082528181018590526000908660608401835b888110156152da5782356152bd81614c0c565b6001600160a01b03168252602092830192909101906001016152aa565b5084810360208681019190915286825291508690820160005b878110156153225782356153068161525c565b15158252828401358483015291840191908401906001016152f3565b509998505050505050505050565b60008235607e1983360301811261534657600080fd5b9190910192915050565b600082601f83011261536157600080fd5b81356001600160401b0381111561537a5761537a614ecb565b604051615391601f8301601f191660200182614f44565b8181528460208386010111156153a657600080fd5b816020850160208301376000918101602001919091529392505050565b600061010082840312156153d657600080fd5b6153de614f70565b90506153e982614c24565b81526153f760208301614c24565b602082015261540860408301614c24565b604082015261541960608301614c24565b60608201526080820135608082015260a082013560a082015260c082013560c082015260e08201356001600160401b0381111561545557600080fd5b61546184828501615350565b60e08301525092915050565b60006080823603121561547f57600080fd5b60405161548b81614ee1565b823561549681614c0c565b815260208301356001600160401b03808211156154b257600080fd5b6154be368387016153c3565b602084015260408501359150808211156154d757600080fd5b6154e336838701615350565b604084015260608501359150808211156154fc57600080fd5b5061550936828601615350565b60608301525092915050565b60005b83811015615530578181015183820152602001615518565b50506000910152565b60008151808452615551816020860160208601615515565b601f01601f19169290920160200192915050565b60006001600160a01b0380861683526060602084015280855116606084015250602084015161559f60808401826001600160a01b03169052565b5060408401516001600160a01b03811660a08401525060608401516001600160a01b03811660c084015250608084015160e083015260a0840151610100818185015260c086015161012085015260e086015191508061014085015250615609610160840182615539565b9050828103604084015261561d8185615539565b9695505050505050565b6000806040838503121561563a57600080fd5b505080516020909101519092909150565b600060033d11156156645760046000803e5060005160e01c5b90565b600060443d10156156755790565b6040516003193d81016004833e81513d6001600160401b0381602484011181841117156156a457505050505090565b82850191508151818111156156bc5750505050505090565b843d87010160208285010111156156d65750505050505090565b6156e560208286010187614f44565b509095945050505050565b8060005b6002811015612ee85781518452602093840193909101906001016156f4565b6060808252835182820181905260009190608090818501906020808901865b8381101561577557815180516001600160a01b03908116875284820151168487015260408082015190870152870151878601529385019390820190600101615732565b5050829550615786818801896156f0565b50505050509392505050565b60008235609e1983360301811261534657600080fd5b600082601f8301126157b957600080fd5b813560206157c682614fbb565b6040516157d38282614f44565b83815260059390931b85018201928281019150868411156157f357600080fd5b8286015b8481101561504457803561580a81614c0c565b83529183019183016157f7565b600060a0823603121561582957600080fd5b60405160a081016001600160401b03828210818311171561584c5761584c614ecb565b816040528435915061585d82614c0c565b8183526020850135602084015260408501356040840152606085013591508082111561588857600080fd5b615894368387016157a8565b606084015260808501359150808211156158ad57600080fd5b506158ba36828601615350565b60808301525092915050565b81810381811115612eaf57612eaf61522d565b6000602082840312156158eb57600080fd5b81516143758161525c565b80820180821115612eaf57612eaf61522d565b600081518084526020808501945080840160005b838110156159425781516001600160a01b03168752958201959082019060010161591d565b509495945050505050565b85815284602082015260a06040820152600061596c60a0830186615909565b6001600160a01b0394909416606083015250608001529392505050565b6000602080838503121561599c57600080fd5b82516001600160401b038111156159b257600080fd5b8301601f810185136159c357600080fd5b80516159ce81614fbb565b6040516159db8282614f44565b82815260059290921b83018401918481019150878311156159fb57600080fd5b928401925b82841015614a3157835182529284019290840190615a00565b60008235603e1983360301811261534657600080fd5b60006040808336031215615a4257600080fd5b8051615a4d81614f06565b8335615a5881614c0c565b81526020848101356001600160401b0380821115615a7557600080fd5b9086019036601f830112615a8857600080fd5b8135615a9381614fbb565b8651615a9f8282614f44565b82815260059290921b8401850191858101915036831115615abf57600080fd5b8585015b83811015615b4a57803585811115615adb5760008081fd5b8601606036829003601f1901811315615af45760008081fd5b8a51615aff81614f25565b89830135615b0c81614c0c565b8152828c01358a820152908201359087821115615b295760008081fd5b615b37368b84860101615350565b818d015285525050918601918601615ac3565b509486019490945250929695505050505050565b600081518084526020808501945080840160005b8381101561594257815180516001600160a01b031688528301518388015260409096019590820190600101615b72565b6000606082016060835280855180835260808501915060808160051b8601019250602080880160005b83811015615c1657878603607f19018552815180516001600160a01b031687528301516040848801819052615c0281890183615b5e565b975050509382019390820190600101615bcb565b5050839450615c27818701886156f0565b505050509392505050565b8082028115828204841417612eaf57612eaf61522d565b600082615c6657634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215615c7d57600080fd5b5051919050565b606081526000835160406060840152615ca060a0840182615b5e565b90506020850151605f19848303016080850152615cbd8282615b5e565b9250505061437560208301846156f0565b600060208284031215615ce057600080fd5b815161437581614c0c565b6000823560be1983360301811261534657600080fd5b600060c08236031215615d1357600080fd5b615d1b614f99565b615d2483614c24565b8152615d3260208401614c24565b60208201526040830135604082015260608301356001600160401b0380821115615d5b57600080fd5b615d6736838701615350565b60608401526080850135915080821115615d8057600080fd5b615d8c368387016157a8565b608084015260a0850135915080821115615da557600080fd5b50615db2368286016157a8565b60a08301525092915050565b60e081526000615dd160e0830187615b5e565b905060206001600160a01b03861681840152604083018560005b6003811015615e0857815183529183019190830190600101615deb565b50505050611d3e60a08301846156f0565b60008251615346818460208701615515565b6001600160e01b0319831681528151600090615e4e816004850160208701615515565b919091016004019392505050565b600060808236031215615e6e57600080fd5b604051615e7a81614ee1565b8235615e8581614c0c565b80825250602083013560208201526040830135604082015260608301356001600160401b03811115615eb657600080fd5b615509368286016157a8565b6000808335601e19843603018112615ed957600080fd5b8301803591506001600160401b03821115615ef357600080fd5b6020019150600581901b3603821315614ad757600080fd5b600080600060608486031215615f2057600080fd5b8351925060208401519150604084015190509250925092565b80516dffffffffffffffffffffffffffff8116811461355757600080fd5b600080600060608486031215615f6c57600080fd5b615f7584615f39565b9250615f8360208501615f39565b9150604084015163ffffffff81168114615f9c57600080fd5b809150509250925092565b602081526000614375602083018461553956fea26469706673582212203bf5925e8dffa62c92befa2f65ca47d7ce1cd32cf4f075a3b3bed113e2e18bc064736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000018000000000000000000000000013cdd11d7c5cc00769f8bfd2ca102408d00ad4530000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf127000000000000000000000000013cdd11d7c5cc00769f8bfd2ca102408d00ad45300000000000000000000000033174db98548ef366b8e156e02422731ede18b9d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a5e0829caced8ffdd4de3c43696c57f7d7a678ff00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001e
-----Decoded View---------------
Arg [0] : fees_ (uint256[3]): 0,0,0
Arg [1] : routers_ (address[]): 0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff
Arg [2] : routerDetails_ (tuple[]):
Arg [1] : isSupported (bool): True
Arg [2] : fees (uint256): 30
Arg [3] : governor_ (address): 0x13CDD11d7C5Cc00769f8bFd2Ca102408D00AD453
Arg [4] : aggregationRouter_ (address): 0x1111111254fb6c44bAC0beD2854e76F90643097d
Arg [5] : wNative_ (address): 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270
Arg [6] : protocolFeeVault_ (address): 0x13CDD11d7C5Cc00769f8bFd2Ca102408D00AD453
Arg [7] : feeDiscountNft_ (address): 0x33174db98548EF366B8E156e02422731edE18B9d
-----Encoded View---------------
15 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [5] : 00000000000000000000000013cdd11d7c5cc00769f8bfd2ca102408d00ad453
Arg [6] : 0000000000000000000000001111111254fb6c44bac0bed2854e76f90643097d
Arg [7] : 0000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf1270
Arg [8] : 00000000000000000000000013cdd11d7c5cc00769f8bfd2ca102408d00ad453
Arg [9] : 00000000000000000000000033174db98548ef366b8e156e02422731ede18b9d
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [11] : 000000000000000000000000a5e0829caced8ffdd4de3c43696c57f7d7a678ff
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [14] : 000000000000000000000000000000000000000000000000000000000000001e
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.10
Net Worth in POL
Token Allocations
POL
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| POL | 100.00% | $0.124245 | 0.77 | $0.095668 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.