Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB 0x6781415cc46ed140cfc1008cede84fce882f8557.
All metadata displayed below is from that contract. In order to verify current contract, click Verify & Publish button
Verify & Publish
All metadata displayed below is from that contract. In order to verify current contract, click Verify & Publish button
- Contract name:
- IcariaSmartToken
- Optimization enabled
- true
- Compiler version
- v0.8.28+commit.7893614a
- Optimization runs
- 20
- Verified at
- 2025-06-05T18:59:43.255729Z
contracts/icaria/IcariaSmartToken.sol
//
//
//
// ██╗ ██████╗ █████╗ ██████╗ ██╗ █████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗
// ██║██╔════╝██╔══██╗██╔══██╗██║██╔══██╗ ██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔════╝
// ██║██║ ███████║██████╔╝██║███████║ █████╗ ██║ ██║██████╔╝██║ ███╗█████╗
// ██║██║ ██╔══██║██╔══██╗██║██╔══██║ ██╔══╝ ██║ ██║██╔══██╗██║ ██║██╔══╝
// ██║╚██████╗██║ ██║██║ ██║██║██║ ██║ ██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
// ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
//
//
//
// Forge
// Web: https://forge.icaria.pro
// Tg: https://t.me/icariaforge
//
// Icaria
// Web: https://icaria.pro
// Tg: https://t.me/icarusprc20
// X: https://x.com/IcarusPRC20
//
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { ERC20 } from "../ERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IcariaRYManager } from "./IcariaRYManager.sol";
import { Ownable }from "@openzeppelin/contracts/access/Ownable.sol";
import { IUniswapV2Factory } from "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import { IUniswapV2Router02 } from "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import { IUniswapV2Pair } from "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import { IIcariaHelpers } from "./interfaces/IIcariaHelpers.sol";
import { IIcariaSmartTrader } from "./interfaces/IIcariaSmartTrader.sol";
import { IIcariaSmartTokenFactory } from "./interfaces/IIcariaSmartTokenFactory.sol";
import { IWETH } from "./interfaces/IWETH.sol";
contract IcariaSmartToken is ERC20, Ownable, IcariaRYManager {
uint256 public constant tokenVersion = 2;
uint256 public initialSupply;
uint256 private constant GLOBAL_DIVIDER = 10000;
address private icariaSmartTrader;
address private deployer;
address private factory;
address[] private routers = [0x98bf93ebf5c380C0e6Ae8e192A7e2AE08edAcc02, 0x165C3410fC91EF562C50559f7d2289fEbed552d9, 0xcC73b59F8D7b7c532703bDfea2808a28a488cF47, 0xeB45a3c4aedd0F47F345fB4c8A1802BB5740d725];
mapping (address => bool) isTaxExcluded;
uint256 private currentSwapAmount;
uint256 private accumulatedIcariaFee;
bool private icariaFeeEnabled = false;
bool private shouldAccumulateIcariaFee = false;
bool private reflectionsEnabled = false;
bool private yieldEnabled = false;
bool private firstPairInteractionHappened = false;
bool private processedTaxesInTx;
IIcariaHelpers.Tax[] public taxes;
constructor(
string memory name_,
string memory symbol_,
address _owner,
address _mintTo,
uint256 _initialSupply,
IIcariaHelpers.Tax[] memory _taxes,
address _icariaSmartTrader,
address _factory,
address _helpers
) ERC20(name_, symbol_) Ownable(_owner) IcariaRYManager(_helpers) {
_mint(_mintTo, _initialSupply);
deployer = _mintTo;
initialSupply = _initialSupply;
icariaSmartTrader = _icariaSmartTrader;
factory = _factory;
if(_taxes.length > 0) {
address[] memory _yieldTokens;
icariaFeeEnabled = true;
(shouldAccumulateIcariaFee, reflectionsEnabled, yieldEnabled, taxes, _yieldTokens) = IIcariaHelpers(helpers).taxesInitialize(_taxes);
inititlizeTaxExclusions();
if (reflectionsEnabled || yieldEnabled) initializeReflectionExclusions();
for(uint256 i = 0; i < _yieldTokens.length; i++) {
addYieldToken(_yieldTokens[i]);
}
}
}
function _transfer(address from, address to, uint256 value) internal override {
processedTaxesInTx = false;
if(isDeadAddress(to)) {
super._burn(from, value);
return;
}
if (taxes.length == 0 || !firstPairInteractionHappened || isTaxExcluded[from] || isTaxExcluded[to] || inSwap) {
if(!firstPairInteractionHappened && isPair(to)) firstPairInteractionHappened = true;
_claimYield(from, to);
super._transfer(from, to, value);
return;
}
if(isPair(to) && !isReflectionExcluded[to]) isReflectionExcluded[to] = true;
currentSwapAmount = value;
uint256 amountAfterTaxs = processTaxes(from, to, value);
if (hasAccumulatedTaxes() && firstPairInteractionHappened && !inSwap && !processedTaxesInTx || shouldAccumulateIcariaFee ) {
if(!isBuy(from, to)) {
processAccumulatedTaxes();
processedTaxesInTx = true;
}
}
_claimYield(from, to);
_claimReflections(from, to);
super._transfer(from, to, amountAfterTaxs);
}
function processTaxes(address from, address to, uint256 amount) internal returns (uint256) {
uint256 totalTaxAmount = 0;
uint256 totalIcariaFee = 0;
for (uint256 i = 0; i < taxes.length; i++) {
IIcariaHelpers.Tax memory tax = taxes[i];
uint256 taxAmount;
uint256 icariaFee;
if (tax.taxMoment == IIcariaHelpers.TaxMoment.Both) {
(taxAmount, icariaFee) = calculateTaxAmount(amount, tax);
processTaxType(from, taxAmount, tax);
} else if (tax.taxMoment == IIcariaHelpers.TaxMoment.Buy && isBuy(from, to)) {
(taxAmount, icariaFee) = calculateTaxAmount(amount, tax);
processTaxType(from, taxAmount, tax);
} else if (tax.taxMoment == IIcariaHelpers.TaxMoment.Sell && isSell(from, to)) {
(taxAmount, icariaFee) = calculateTaxAmount(amount, tax);
processTaxType(from, taxAmount, tax);
}
totalTaxAmount += taxAmount;
totalIcariaFee += icariaFee;
}
if (totalIcariaFee > 0) {
if (shouldAccumulateIcariaFee) {
super._transfer(from, address(this), totalIcariaFee);
accumulatedIcariaFee += totalIcariaFee;
} else {
super._transfer(from, getIcariaWallet(), totalIcariaFee);
}
}
return amount - totalTaxAmount - totalIcariaFee;
}
function calculateTaxAmount(uint256 originalAmount, IIcariaHelpers.Tax memory tax) internal view returns (uint256 taxAmount, uint256 icariaFee) {
return IIcariaHelpers(helpers).calculateTaxAmount(
originalAmount,
tax.percentage,
getIcariaFee(),
icariaFeeEnabled,
GLOBAL_DIVIDER
);
}
function processTaxType(address from, uint256 taxAmount, IIcariaHelpers.Tax memory tax) internal {
if (tax.taxType == IIcariaHelpers.TaxType.Burn) {
processBurnTax(from, taxAmount);
} else if (tax.taxType == IIcariaHelpers.TaxType.Reflection) {
processReflectionTax(from, taxAmount);
} else if (tax.taxType == IIcariaHelpers.TaxType.Dev) {
processDevTax(from, taxAmount, tax);
} else if (tax.taxType == IIcariaHelpers.TaxType.ExternalBurn) {
processExternalBurnTax(from, taxAmount, tax);
} else if (tax.taxType == IIcariaHelpers.TaxType.Yield) {
processYieldTax(from, taxAmount, tax);
}
}
function processBurnTax(address from, uint256 taxAmount) internal {
super._burn(from, taxAmount);
}
function processDevTax(address from, uint256 taxAmount, IIcariaHelpers.Tax memory tax) internal {
if(!isTaxExcluded[tax.receiver]) isTaxExcluded[tax.receiver] = true;
if (tax.rewardInPls) {
super._transfer(from, address(this), taxAmount);
taxes[tax.id].amountAccumulated += taxAmount;
} else {
super._transfer(from, tax.receiver, taxAmount);
}
}
function processReflectionTax(address from, uint256 taxAmount) internal {
super._transfer(from, address(this), taxAmount);
uint256 supply = totalSupply() - balanceOf(address(this));
if (supply > 0) {
reflectionsPerShareAmount += (taxAmount * PRECISION) / supply;
}
}
function processExternalBurnTax(address from, uint256 taxAmount, IIcariaHelpers.Tax memory tax) internal lockSwap {
super._transfer(from, address(this), taxAmount);
taxes[tax.id].amountAccumulated += taxAmount;
}
function processYieldTax(address from, uint256 taxAmount, IIcariaHelpers.Tax memory tax) internal lockSwap {
super._transfer(from, address(this), taxAmount);
taxes[tax.id].amountAccumulated += taxAmount;
}
function processAccumulatedTaxes() internal lockSwap {
uint256 totalToSwap = 0;
uint256 totalTokenTypes = 0;
bool[] memory taxesToProcess = new bool[](taxes.length);
uint256[] memory taxAmounts = new uint256[](taxes.length);
for (uint256 i = 0; i < taxes.length; i++) {
IIcariaHelpers.Tax storage tax = taxes[i];
if (tax.amountAccumulated == 0) continue;
if (tax.taxType == IIcariaHelpers.TaxType.ExternalBurn ||
(tax.taxType == IIcariaHelpers.TaxType.Dev && tax.rewardInPls) ||
tax.taxType == IIcariaHelpers.TaxType.Yield) {
(uint256 swapAmount, uint256 newAccumulatedAmount) = IIcariaHelpers(helpers).getProcessingAmount(tax.amountAccumulated, currentSwapAmount);
if (swapAmount > 0) {
taxesToProcess[i] = true;
taxAmounts[i] = swapAmount;
totalToSwap += swapAmount;
totalTokenTypes++;
}
taxes[i].amountAccumulated = newAccumulatedAmount;
}
}
(/*address bestPair*/, address bestRouter) = IIcariaHelpers(helpers).getBestPair(address(this), wethAddress, routers);
if (bestRouter == address(0)) return;
(uint256 icariaToProcess, uint256 newAccumulatedIcariaAmount) = IIcariaHelpers(helpers).getProcessingAmount(accumulatedIcariaFee, currentSwapAmount);
totalToSwap += icariaToProcess;
if (totalToSwap == 0) return;
uint256 icariaToTaxesRatio = icariaToProcess * PRECISION / totalToSwap;
accumulatedIcariaFee = newAccumulatedIcariaAmount;
_approve(address(this), icariaSmartTrader, totalToSwap);
try IIcariaSmartTrader(icariaSmartTrader).swapExactTokensForTokensSupportingFeeOnTransferTokens(
bestRouter,
address(this),
totalToSwap,
getTokenWETHPath(address(this))
) {
} catch {
for (uint256 i = 0; i < taxes.length; i++) {
if (taxesToProcess[i]) {
taxes[i].amountAccumulated += taxAmounts[i];
}
}
accumulatedIcariaFee += icariaToProcess;
return;
}
uint256 totalWethReceived = IERC20(wethAddress).balanceOf(address(this)) - wethYieldBalance;
uint256 _icariaFee = totalWethReceived * icariaToTaxesRatio / PRECISION;
sendWETH(_icariaFee, getIcariaWallet());
totalWethReceived -= _icariaFee;
totalToSwap -= icariaToProcess;
if (totalWethReceived == 0) return;
for (uint256 i = 0; i < taxes.length; i++) {
if (!taxesToProcess[i] || taxAmounts[i] == 0) continue;
uint256 wethPortion = (taxAmounts[i] * totalWethReceived) / totalToSwap;
IIcariaHelpers.Tax storage tax = taxes[i];
if (tax.taxType == IIcariaHelpers.TaxType.ExternalBurn) {
processExternalBurnWeth(wethPortion, tax);
} else if (tax.taxType == IIcariaHelpers.TaxType.Dev && tax.rewardInPls) {
sendWETH(wethPortion, tax.receiver);
} else if (tax.taxType == IIcariaHelpers.TaxType.Yield) {
processYieldWeth(wethPortion, tax);
}
}
}
function processExternalBurnWeth(uint256 wethAmount, IIcariaHelpers.Tax memory tax) internal {
if (wethAmount == 0) return;
if (tax.tokenAddress == wethAddress) {
IERC20(wethAddress).transfer(tax.receiver, wethAmount);
return;
}
(/*address bestTargetPair*/, address bestTargetRouter) = IIcariaHelpers(helpers).getBestPair(wethAddress, tax.tokenAddress, routers);
IERC20(wethAddress).approve(icariaSmartTrader, wethAmount);
try IIcariaSmartTrader(icariaSmartTrader).buyToken(bestTargetRouter, tax.receiver, wethAmount, getWETHBuyBurnPath(tax.tokenAddress)) {
} catch {
IERC20(wethAddress).transfer(tax.receiver, wethAmount);
}
}
function sendWETH(uint256 wethAmount, address receiver) internal {
if (wethAmount == 0) return;
try IWETH(wethAddress).withdraw(wethAmount){
(bool success,) = receiver.call{value: wethAmount}("");
if (!success) {
IERC20(wethAddress).transfer(receiver, wethAmount);
}
} catch {
IERC20(wethAddress).transfer(receiver, wethAmount);
}
}
function processYieldWeth(uint256 wethAmount, IIcariaHelpers.Tax memory tax) internal {
if (wethAmount == 0) return;
if (tax.tokenAddress == wethAddress) {
wethYieldBalance += wethAmount;
uint256 tokenIndex = addYieldToken(tax.tokenAddress);
uint256 supply = totalSupply() - balanceOf(address(this));
if (supply > 0) {
yieldTokens[tokenIndex].reflectionsPerShareAmount += (wethAmount * PRECISION) / supply;
}
return;
}
(/*address bestTargetPair*/, address bestTargetRouter) = IIcariaHelpers(helpers).getBestPair(wethAddress, tax.tokenAddress, routers);
uint256 initialTokenBalance = IERC20(tax.tokenAddress).balanceOf(address(this));
IERC20(wethAddress).approve(icariaSmartTrader, wethAmount);
try IIcariaSmartTrader(icariaSmartTrader).buyToken(bestTargetRouter, address(this), wethAmount, getWETHBuyBurnPath(tax.tokenAddress)) {
uint256 finalTokenBalance = IERC20(tax.tokenAddress).balanceOf(address(this));
uint256 boughtAmount = finalTokenBalance - initialTokenBalance;
if (boughtAmount > 0) {
uint256 tokenIndex = addYieldToken(tax.tokenAddress);
uint256 supply = totalSupply() - balanceOf(address(this));
if (supply > 0) {
yieldTokens[tokenIndex].reflectionsPerShareAmount += (boughtAmount * PRECISION) / supply;
}
}
} catch {}
}
function _claimReflections(address from, address to) internal {
if (!reflectionsEnabled) return;
(uint256 fromAmount, uint256 toAmount, uint256 deployerAmount) = updateAndClaimReflections(from, to, deployer);
if(fromAmount != 0){
if(!isPair(from)){
super._transfer(address(this), from, fromAmount);
}
}
if(toAmount != 0){
if(!isPair(to)){
super._transfer(address(this), to, toAmount);
}
}
if(deployerAmount != 0){
super._transfer(address(this), deployer, deployerAmount);
}
}
function initializeReflectionExclusions() internal {
isReflectionExcluded[address(0)] = true;
isReflectionExcluded[address(this)] = true;
for (uint256 i = 0; i < routers.length; ) {
isReflectionExcluded[routers[i]] = true;
unchecked { i++; }
}
}
function isDeadAddress(address _address) internal view returns (bool) {
return IIcariaHelpers(helpers).isDeadAddress(_address);
}
function isPair(address _address) internal view returns (bool) {
return IIcariaHelpers(helpers).isPair(_address, address(this));
}
function isBuy(address from, address to) internal view returns (bool) {
return IIcariaHelpers(helpers).isBuy(from, to, address(this));
}
function isSell(address from, address to) internal view returns (bool) {
return IIcariaHelpers(helpers).isSell(from, to, address(this));
}
function getProcessingAmount(uint256 accumulatedAmount) internal view returns (uint256 processAmount, uint256 newAccumulatedAmount) {
return IIcariaHelpers(helpers).getProcessingAmount(accumulatedAmount, currentSwapAmount);
}
function getTokenWETHPath(address tokenAddress) internal view returns (address[] memory) {
return IIcariaHelpers(helpers).getTokenWPLSPath(tokenAddress);
}
function getWETHBuyBurnPath(address tokenAddress) internal view returns (address[] memory) {
return IIcariaHelpers(helpers).getWPLSBuyBurnPath(tokenAddress);
}
function getTaxes() public view returns (IIcariaHelpers.Tax[] memory) {
return taxes;
}
function getIcariaFee() public view returns (uint256) {
return IIcariaSmartTokenFactory(factory).ICARIA_FEE();
}
function getIcariaWallet() public view returns (address) {
return IIcariaSmartTokenFactory(factory).ICARIA_WALLET();
}
function getAccumulatedIcariaFee() external view returns (uint256) {
return accumulatedIcariaFee;
}
function getTotalTaxs() external view returns (uint256) {
return IIcariaHelpers(helpers).getTotalTaxs(taxes);
}
function forceProcessAccumulatedTaxes() external onlyOwner {
processAccumulatedTaxes();
}
function _claimYield(address from, address to) internal {
if (yieldEnabled) {
updateAndClaimYield(from, to, deployer);
}
}
function claimYield() external returns (bool) {
_claimYield(msg.sender, msg.sender);
return true;
}
function hasAccumulatedTaxes() internal view returns (bool) {
return IIcariaHelpers(helpers).hasAccumulatedTaxes(taxes);
}
function addTaxExclusion(address _address) external onlyOwner {
isTaxExcluded[_address] = true;
}
function removeTaxExclusion(address _address) external onlyOwner {
isTaxExcluded[_address] = false;
}
function inititlizeTaxExclusions() internal {
isTaxExcluded[deployer] = true;
isTaxExcluded[address(this)] = true;
isTaxExcluded[icariaSmartTrader] = true;
}
receive() external payable {}
}
@openzeppelin/contracts/access/Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../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.
*
* The initial owner is set to the address provided by the deployer. 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;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @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 {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_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);
}
}
@openzeppelin/contracts/interfaces/draft-IERC6093.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}
@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol
pragma solidity >=0.5.0;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol
pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol
pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
contracts/ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC-20
* applications.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
*
* ```solidity
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance < type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
contracts/icaria/IcariaRYManager.sol
//
//
//
// ██╗ ██████╗ █████╗ ██████╗ ██╗ █████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗
// ██║██╔════╝██╔══██╗██╔══██╗██║██╔══██╗ ██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔════╝
// ██║██║ ███████║██████╔╝██║███████║ █████╗ ██║ ██║██████╔╝██║ ███╗█████╗
// ██║██║ ██╔══██║██╔══██╗██║██╔══██║ ██╔══╝ ██║ ██║██╔══██╗██║ ██║██╔══╝
// ██║╚██████╗██║ ██║██║ ██║██║██║ ██║ ██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
// ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
//
//
//
// Forge
// Web: https://forge.icaria.pro
// Tg: https://t.me/icariaforge
//
// Icaria
// Web: https://icaria.pro
// Tg: https://t.me/icarusprc20
// X: https://x.com/IcarusPRC20
//
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { IERC20 }from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IIcariaHelpers } from "./interfaces/IIcariaHelpers.sol";
contract IcariaRYManager {
// For yield tax tokens
struct UserYield {
uint256 reflectionDebt;
}
struct YieldToken {
address tokenAddress;
uint256 reflectionsPerShareAmount;
}
YieldToken[] internal yieldTokens;
uint256 internal PRECISION;
uint256 internal reflectionsPerShareAmount;
uint256 internal wethYieldBalance;
address internal helpers;
address internal wethAddress = 0xA1077a294dDE1B09bB078844df40758a5D0f9a27; // WPLS on PulseChain
mapping(address => uint256) internal reflectionDebt;
mapping(address => bool) public isReflectionExcluded;
mapping(address => mapping(address => UserYield)) internal userYields;
mapping(address => uint256[]) internal yieldTokenReflectionDebts;
bool internal inSwap;
modifier lockSwap() {
inSwap = true;
_;
inSwap = false;
}
constructor(address _helpers) {
PRECISION = 10**28;
helpers = _helpers;
}
// ------------------------------------------ REFLECTIONS -------------------------------------------------//
function getCurrentReflectionsPerShareAmount() external view returns (uint256) {
return reflectionsPerShareAmount;
}
function isExcludedFromReflections(address account) public view returns (bool) {
return isReflectionExcluded[account];
}
function pendingReflections(address account) public view returns (uint256) {
if (isExcludedFromReflections(account)) {
return 0;
}
return cleanPendingReflections(account);
}
function cleanPendingReflections(address account) internal view returns (uint256) {
return IIcariaHelpers(helpers).cleanPendingReflections(
account,
address(this),
reflectionsPerShareAmount,
reflectionDebt[account],
PRECISION
);
}
function updateAndClaimReflections(address from, address to, address deployer) internal returns (uint256 fromAmount, uint256 toAmount, uint256 deployerAmount) {
if (from == to) {
fromAmount = isExcludedFromReflections(from) ? 0 : pendingReflections(from);
toAmount = 0; // Set to zero to avoid double claiming
} else {
fromAmount = isExcludedFromReflections(from) ? 0 : pendingReflections(from);
toAmount = isExcludedFromReflections(to) ? 0 : pendingReflections(to);
}
deployerAmount = cleanPendingReflections(deployer);
reflectionDebt[deployer] = reflectionsPerShareAmount;
reflectionDebt[from] = reflectionsPerShareAmount;
reflectionDebt[to] = reflectionsPerShareAmount;
}
// function tokenPendingReflections() public view returns (uint256) {
// uint256 currentBalance = IERC20(address(this)).balanceOf(address(this));
// uint256 newReflectionDebt = reflectionsPerShareAmount;
// if (newReflectionDebt <= reflectionDebt[address(this)]) {
// return 0;
// }
// return (newReflectionDebt - reflectionDebt[address(this)]) * currentBalance / PRECISION;
// }
// ------------------------------------------ YIELD TOKENS REFLECTIONS -------------------------------------------------//
function addYieldToken(address tokenAddress) internal returns (uint256 tokenIndex) {
for (uint256 i = 0; i < yieldTokens.length; i++) {
if (yieldTokens[i].tokenAddress == tokenAddress) {
return i;
}
}
yieldTokens.push(YieldToken({
tokenAddress: tokenAddress,
reflectionsPerShareAmount: 0
}));
return yieldTokens.length - 1;
}
function pendingYields(address account, uint256 tokenIndex) public view returns (uint256) {
if (tokenIndex >= yieldTokenReflectionDebts[account].length) {
return 0;
}
return IIcariaHelpers(helpers).pendingYields(
account,
address(this),
yieldTokens[tokenIndex].reflectionsPerShareAmount,
yieldTokenReflectionDebts[account][tokenIndex],
PRECISION
);
}
function updateAndClaimYield(address from, address to, address deployer) internal {
for (uint256 i = 0; i < yieldTokens.length; i++) {
while (yieldTokenReflectionDebts[from].length <= i) {
yieldTokenReflectionDebts[from].push(yieldTokens[i].reflectionsPerShareAmount);
}
while (yieldTokenReflectionDebts[to].length <= i) {
yieldTokenReflectionDebts[to].push(yieldTokens[i].reflectionsPerShareAmount);
}
while (yieldTokenReflectionDebts[deployer].length <= i) {
yieldTokenReflectionDebts[deployer].push(yieldTokens[i].reflectionsPerShareAmount);
}
uint256 fromAmount = isExcludedFromReflections(from) ? 0 : pendingYields(from, i);
uint256 toAmount = 0; // Initialize to 0
if (from != to) {
toAmount = isExcludedFromReflections(to) ? 0 : pendingYields(to, i);
}
uint256[] memory transferAmounts = new uint256[](2);
address[] memory recipients = new address[](2);
uint256 recipientCount = 0;
if (fromAmount > 0) {
transferAmounts[recipientCount] = fromAmount;
recipients[recipientCount] = from;
recipientCount++;
}
if (toAmount > 0) {
transferAmounts[recipientCount] = toAmount;
recipients[recipientCount] = to;
recipientCount++;
}
for (uint256 j = 0; j < recipientCount; j++) {
if(transferAmounts[j] > 0){
try IERC20(yieldTokens[i].tokenAddress).transfer(recipients[j], transferAmounts[j]) {
if(yieldTokens[i].tokenAddress == wethAddress) {
wethYieldBalance -= transferAmounts[j];
}
yieldTokenReflectionDebts[recipients[j]][i] = yieldTokens[i].reflectionsPerShareAmount;
} catch {
}
}
}
}
}
function getYieldTokens() public view returns (YieldToken[] memory) {
return yieldTokens;
}
function getYieldTokenReflectionDebts(address account) public view returns (uint256[] memory) {
return yieldTokenReflectionDebts[account];
}
// function getYieldsPerShare(uint256 index) public view returns (uint256) {
// return yieldTokens[index].reflectionsPerShareAmount;
// }
// ------------------------------------------ END REFLECTIONS -----------------------------------------------//
//-------------------------------------------- HELPERS FUNCTIONS -------------------------------------------------//
// function excludeFromReflections(address account) external onlyOwner {
// require(!isExcludedFromReflections(account), "Account already excluded");
// isReflectionExcluded[account] = true;
// updateAndClaimReflections(account);
// }
// function includeInReflections(address account) external onlyOwner {
// require(isReflectionExcluded[account], "Not excluded");
// isReflectionExcluded[account] = false;
// reflectionDebt[account] = (balanceOf(account) * reflectionsPerShareAmount) / PRECISION;
// }
}
contracts/icaria/interfaces/IIcariaHelpers.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IIcariaHelpers {
enum TaxType { Burn, ExternalBurn, Dev, Reflection, Yield }
enum TaxMoment { Both, Buy, Sell }
struct Tax {
uint256 id;
TaxType taxType;
TaxMoment taxMoment;
uint256 percentage;
address receiver;
address tokenAddress;
address burnAddress;
bool rewardInPls;
uint256 amountAccumulated;
}
function getBestPair(
address tokenA,
address tokenB,
address[] memory routers
) external view returns (address bestPair, address bestRouter);
function getTotalPairsBalance(address tokenA, address tokenB, address[] memory routers) external view returns (uint256);
function isPair(address _address, address _tokenAddress) external view returns (bool);
function isBuy(address _from, address _to, address _tokenAddress) external view returns (bool);
function isSell(address _from, address _to, address _tokenAddress) external view returns (bool);
function getTokenWPLSPath(address tokenAddress) external pure returns (address[] memory path);
function getWPLSBuyBurnPath(address tokenAddress) external pure returns (address[] memory path);
function getProcessingAmount(
uint256 accumulatedAmount,
uint256 currentSwapAmount
) external pure returns (uint256 processAmount, uint256 newAccumulatedAmount);
function calculateTaxAmount(
uint256 originalAmount,
uint256 taxPercentage,
uint256 icariaFee,
bool icariaFeeEnabled,
uint256 globalDivider
) external pure returns (uint256 taxAmount, uint256 icariaFeeAmount);
function hasAccumulatedTaxes(Tax[] memory taxes) external pure returns (bool);
function getTotalTaxs(Tax[] memory taxes) external pure returns (uint256);
function cleanPendingReflections(
address account,
address tokenAddress,
uint256 reflectionsPerShareAmount,
uint256 reflectionDebt,
uint256 precision
) external view returns (uint256);
function pendingYields(
address account,
address tokenAddress,
uint256 reflectionsPerShareAmount,
uint256 reflectionDebt,
uint256 precision
) external view returns (uint256);
function isExcludedFromTax(
address from,
address to,
address icariaSmartTrader,
address deployer,
address thisContract
) external pure returns (bool);
function taxesInitialize(IIcariaHelpers.Tax[] memory _taxes) external pure returns (bool, bool, bool, IIcariaHelpers.Tax[] memory, address[] memory);
function isDeadAddress(address _address) external pure returns (bool);
}
contracts/icaria/interfaces/IIcariaSmartTokenFactory.sol
//
//
//
// ██╗ ██████╗ █████╗ ██████╗ ██╗ █████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗
// ██║██╔════╝██╔══██╗██╔══██╗██║██╔══██╗ ██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔════╝
// ██║██║ ███████║██████╔╝██║███████║ █████╗ ██║ ██║██████╔╝██║ ███╗█████╗
// ██║██║ ██╔══██║██╔══██╗██║██╔══██║ ██╔══╝ ██║ ██║██╔══██╗██║ ██║██╔══╝
// ██║╚██████╗██║ ██║██║ ██║██║██║ ██║ ██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
// ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
//
//
//
// Forge
// Web: https://forge.icaria.pro
// Tg: https://t.me/icariaforge
//
// Icaria
// Web: https://icaria.pro
// Tg: https://t.me/icarusprc20
// X: https://x.com/IcarusPRC20
//
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IIcariaSmartTokenFactory {
function ICARIA_FEE() external view returns (uint256);
function ICARIA_WALLET() external view returns (address);
}
contracts/icaria/interfaces/IIcariaSmartTrader.sol
//
//
//
// ██╗ ██████╗ █████╗ ██████╗ ██╗ █████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗
// ██║██╔════╝██╔══██╗██╔══██╗██║██╔══██╗ ██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔════╝
// ██║██║ ███████║██████╔╝██║███████║ █████╗ ██║ ██║██████╔╝██║ ███╗█████╗
// ██║██║ ██╔══██║██╔══██╗██║██╔══██║ ██╔══╝ ██║ ██║██╔══██╗██║ ██║██╔══╝
// ██║╚██████╗██║ ██║██║ ██║██║██║ ██║ ██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
// ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
//
//
//
// Forge
// Web: https://forge.icaria.pro
// Tg: https://t.me/icariaforge
//
// Icaria
// Web: https://icaria.pro
// Tg: https://t.me/icarusprc20
// X: https://x.com/IcarusPRC20
//
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IIcariaSmartTrader {
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
address _router,
address _receiver,
uint256 amountIn,
address[] memory path
) external;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
address _router,
address _receiver,
uint256 amountIn,
address[] calldata path
) external;
function buyToken(
address _router,
address _receiver,
uint256 amountIn,
address[] memory path
) external;
}
contracts/icaria/interfaces/IWETH.sol
//
//
//
// ██╗ ██████╗ █████╗ ██████╗ ██╗ █████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗
// ██║██╔════╝██╔══██╗██╔══██╗██║██╔══██╗ ██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔════╝
// ██║██║ ███████║██████╔╝██║███████║ █████╗ ██║ ██║██████╔╝██║ ███╗█████╗
// ██║██║ ██╔══██║██╔══██╗██║██╔══██║ ██╔══╝ ██║ ██║██╔══██╗██║ ██║██╔══╝
// ██║╚██████╗██║ ██║██║ ██║██║██║ ██║ ██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
// ╚═╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
//
//
//
// Forge
// Web: https://forge.icaria.pro
// Tg: https://t.me/icariaforge
//
// Icaria
// Web: https://icaria.pro
// Tg: https://t.me/icarusprc20
// X: https://x.com/IcarusPRC20
//
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IWETH {
function withdraw(uint256 wad) external;
}
Compiler Settings
{"viaIR":true,"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":20,"enabled":true},"libraries":{},"evmVersion":"paris"}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"string","name":"name_","internalType":"string"},{"type":"string","name":"symbol_","internalType":"string"},{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"_mintTo","internalType":"address"},{"type":"uint256","name":"_initialSupply","internalType":"uint256"},{"type":"tuple[]","name":"_taxes","internalType":"struct IIcariaHelpers.Tax[]","components":[{"type":"uint256","name":"id","internalType":"uint256"},{"type":"uint8","name":"taxType","internalType":"enum IIcariaHelpers.TaxType"},{"type":"uint8","name":"taxMoment","internalType":"enum IIcariaHelpers.TaxMoment"},{"type":"uint256","name":"percentage","internalType":"uint256"},{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"address","name":"burnAddress","internalType":"address"},{"type":"bool","name":"rewardInPls","internalType":"bool"},{"type":"uint256","name":"amountAccumulated","internalType":"uint256"}]},{"type":"address","name":"_icariaSmartTrader","internalType":"address"},{"type":"address","name":"_factory","internalType":"address"},{"type":"address","name":"_helpers","internalType":"address"}]},{"type":"error","name":"ERC20InsufficientAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"allowance","internalType":"uint256"},{"type":"uint256","name":"needed","internalType":"uint256"}]},{"type":"error","name":"ERC20InsufficientBalance","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"uint256","name":"balance","internalType":"uint256"},{"type":"uint256","name":"needed","internalType":"uint256"}]},{"type":"error","name":"ERC20InvalidApprover","inputs":[{"type":"address","name":"approver","internalType":"address"}]},{"type":"error","name":"ERC20InvalidReceiver","inputs":[{"type":"address","name":"receiver","internalType":"address"}]},{"type":"error","name":"ERC20InvalidSender","inputs":[{"type":"address","name":"sender","internalType":"address"}]},{"type":"error","name":"ERC20InvalidSpender","inputs":[{"type":"address","name":"spender","internalType":"address"}]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addTaxExclusion","inputs":[{"type":"address","name":"_address","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"claimYield","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"forceProcessAccumulatedTaxes","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAccumulatedIcariaFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCurrentReflectionsPerShareAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getIcariaFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getIcariaWallet","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct IIcariaHelpers.Tax[]","components":[{"type":"uint256","name":"id","internalType":"uint256"},{"type":"uint8","name":"taxType","internalType":"enum IIcariaHelpers.TaxType"},{"type":"uint8","name":"taxMoment","internalType":"enum IIcariaHelpers.TaxMoment"},{"type":"uint256","name":"percentage","internalType":"uint256"},{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"address","name":"burnAddress","internalType":"address"},{"type":"bool","name":"rewardInPls","internalType":"bool"},{"type":"uint256","name":"amountAccumulated","internalType":"uint256"}]}],"name":"getTaxes","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTotalTaxs","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getYieldTokenReflectionDebts","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct IcariaRYManager.YieldToken[]","components":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"reflectionsPerShareAmount","internalType":"uint256"}]}],"name":"getYieldTokens","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"initialSupply","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isExcludedFromReflections","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isReflectionExcluded","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pendingReflections","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"pendingYields","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"tokenIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeTaxExclusion","inputs":[{"type":"address","name":"_address","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"id","internalType":"uint256"},{"type":"uint8","name":"taxType","internalType":"enum IIcariaHelpers.TaxType"},{"type":"uint8","name":"taxMoment","internalType":"enum IIcariaHelpers.TaxMoment"},{"type":"uint256","name":"percentage","internalType":"uint256"},{"type":"address","name":"receiver","internalType":"address"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"address","name":"burnAddress","internalType":"address"},{"type":"bool","name":"rewardInPls","internalType":"bool"},{"type":"uint256","name":"amountAccumulated","internalType":"uint256"}],"name":"taxes","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tokenVersion","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x60808060405234610bb157613fff803803809161001c8285610bb6565b8339810161012082820312610bb15781516001600160401b038111610bb15781610047918401610bd9565b60208301519092906001600160401b038111610bb15782610069918301610bd9565b61007560408301610c48565b9361008260608401610c48565b608084015160a085015190959192916001600160401b038211610bb1576100aa918601610c80565b956100b760c08601610c48565b936100d16101006100ca60e08901610c48565b9701610c48565b835190936001600160401b0382116109cc5760035490600182811c92168015610ba7575b6020831014610ac55781601f849311610b58575b50602090601f8311600114610af057600092610ae5575b50508160011b916000199060031b1c1916176003555b8051906001600160401b0382116109cc5760045490600182811c92168015610adb575b6020831014610ac55781601f849311610a6b575b50602090601f8311600114610a03576000926109f8575b50508160011b916000199060031b1c1916176004555b6001600160a01b03169081156109e257600580546001600160a01b03198116841790915560405192906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3600b80546001600160a01b031990811673a1077a294dde1b09bb078844df40758a5d0f9a27179091556b204fce5e3e25026110000000600755600a80549091166001600160a01b0392909216919091179055608081016001600160401b038111828210176109cc576040527398bf93ebf5c380c0e6ae8e192a7e2ae08edacc02815273165c3410fc91ef562c50559f7d2289febed552d9602082015273cc73b59f8d7b7c532703bdfea2808a28a488cf47604082015273eb45a3c4aedd0f47f345fb4c8a1802bb5740d7256060820152601554600460155580600410610987575b50601560005260206000209060005b6004811061096a5750506019805464ffffffffff19169055506001600160a01b03169283156109545760025481810180911161093e57600255600093808552846020526040852082815401905580857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6020604051868152a3601380546001600160a01b03199081169290921790556011919091556012805482166001600160a01b03938416179055601480549091169290911691909117905581516103b1575b6040516131019081610ebe8239f35b600160ff1960195416176019558060018060a01b03600a5416926040519384916316bc2cf360e21b83526024830160206004850152815180915260206044850192019085905b8082106108885750505082809103915afa91821561087b57818290839284908596610785575b5080519068010000000000000000821161077157601a5482601a558083106106d7575b50601a86528590600080516020613fdf833981519152906020015b8383106105cf575050505062ff00009063ff00000061ff0060195492151560081b1694151560181b169063ffffff0019161791151560101b16171760195560018060a01b03601354168152601660205260408120600160ff19825416179055308152601660205260408120600160ff1982541617905560018060a01b03601254168152601660205260408120600160ff1982541617905560195460ff8160101c169081156105c1575b50610547575b805b825181101561053d57600581901b83016020015160019190610536906001600160a01b0316610ddc565b500161050c565b50505038806103a2565b808052600d60205260408120600160ff19825416179055308152600d60205260408120600160ff19825416179055805b6015548110156105bb57600080516020613fbf8339815191528101546001600160a01b03168252600d60205260408220805460ff1916600190811790915501610577565b5061050a565b60ff915060181c1638610504565b80518051835560018301602082015160058110156106c3578154604084015160038110156106af5761ff0060089190911b1660ff9290921661ffff1991909116171790556060810151600284015560808101516003840180546001600160a01b039283166001600160a01b03199182161790915560a080840151600487018054918516919093161790915560c083015160058601805460e086015160ff60a01b90151590941b93909316919093166001600160a81b031990921691909117179055610100015160068301556001929092019160079091019060200161045b565b634e487b7160e01b8d52602160045260248dfd5b634e487b7160e01b8b52602160045260248bfd5b8060070290600782040361075d578260070260078104840361074957601a8852600080516020613fdf83398151915291820191015b8181106107195750610440565b8088600792558860018201558860028201558860038201558860048201558860058201558860068201550161070c565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b87526011600452602487fd5b634e487b7160e01b86526041600452602486fd5b9550505050503d8082843e61079a8184610bb6565b82019160a081840312610877576107b081610c73565b6107bc60208301610c73565b6107c860408401610c73565b60608401519092906001600160401b03811161086f57866107ea918601610c80565b608085015190946001600160401b03821161087357019580601f8801121561086f57865161081781610c5c565b97610825604051998a610bb6565b8189526020808a019260051b82010192831161086b57602001905b828210610853575050509091923861041d565b6020809161086084610c48565b815201910190610840565b8780fd5b8580fd5b8680fd5b5080fd5b50604051903d90823e3d90fd5b929194509294508351805182526020810151600581101561092a5760208301526040810151600381101561092a5782610100602093610120936040600197015260608101516060840152858060a01b036080820151166080840152858060a01b0360a08201511660a0840152858060a01b0360c08201511660c084015260e0810151151560e084015201516101008201520194019201918594928794926103f7565b634e487b7160e01b88526021600452602488fd5b634e487b7160e01b600052601160045260246000fd5b63ec442f0560e01b600052600060045260246000fd5b81516001600160a01b0316818401556020909101906001016102e1565b60156000526109c690600080516020613fbf833981519152017f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec479610d90565b386102d2565b634e487b7160e01b600052604160045260246000fd5b631e4fbdf760e01b600052600060045260246000fd5b015190503880610184565b600460009081528281209350601f198516905b818110610a535750908460019594939210610a3a575b505050811b0160045561019a565b015160001960f88460031b161c19169055388080610a2c565b92936020600181928786015181550195019301610a16565b6004600052610ab5907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f850160051c81019160208610610abb575b601f0160051c0190610d90565b3861016d565b9091508190610aa8565b634e487b7160e01b600052602260045260246000fd5b91607f1691610159565b015190503880610120565b600360009081528281209350601f198516905b818110610b405750908460019594939210610b27575b505050811b01600355610136565b015160001960f88460031b161c19169055388080610b19565b92936020600181928786015181550195019301610b03565b6003600052610ba1907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f850160051c81019160208610610abb57601f0160051c0190610d90565b38610109565b91607f16916100f5565b600080fd5b601f909101601f19168101906001600160401b038211908210176109cc57604052565b81601f82011215610bb1578051906001600160401b0382116109cc5760405192610c0d601f8401601f191660200185610bb6565b82845260208383010111610bb15760005b828110610c3357505060206000918301015290565b80602080928401015182828701015201610c1e565b51906001600160a01b0382168203610bb157565b6001600160401b0381116109cc5760051b60200190565b51908115158203610bb157565b81601f82011215610bb157805190610c9782610c5c565b92610ca56040519485610bb6565b8284526020610120818601940283010191818311610bb157602001925b828410610cd0575050505090565b61012084830312610bb1576040519061012082016001600160401b038111838210176109cc576040528451825260208501516005811015610bb15760208301526040850151906003821015610bb15782602092604061012095015260608701516060820152610d4160808801610c48565b6080820152610d5260a08801610c48565b60a0820152610d6360c08801610c48565b60c0820152610d7460e08801610c73565b60e0820152610100870151610100820152815201930192610cc2565b818110610d9b575050565b60008155600101610d90565b600654811015610dc657600660005260206000209060011b0190600090565b634e487b7160e01b600052603260045260246000fd5b6006549060005b828110610e92575060408051919082016001600160401b038111838210176109cc576040526001600160a01b0316815260006020820190815291680100000000000000008110156109cc57806001610e3e9201600655610da7565b929092610e7c57905182546001600160a01b0319166001600160a01b03919091161782555160019190910155600654600019810190811161093e5790565b634e487b7160e01b600052600060045260246000fd5b610e9b81610da7565b50546001600160a01b03838116911614610eb757600101610de3565b9150509056fe608080604052600436101561001d575b50361561001b57600080fd5b005b60003560e01c90816306fdde0314610c1557508063095ea7b314610bef57806318160ddd14610bd157806323b872dd14610ae45780632973ef2d1461099f578063313ce56714610983578063378dc3dc14610965578063406cf2291461094a5780634f30800d1461092c57806356cdad1d1461090e5780635f75baf6146108f3578063695d69b3146108d05780636a2072d414610816578063709df63c1461072357806370a08231146106e9578063715018a61461068c5780638453ef99146106525780638da5cb5b146106295780639045be581461029957806395d89b41146105225780639b165f4e146104dd578063a9059cbb146104ac578063c5be2bc7146103f1578063cb78c16314610358578063dd62ed3e14610307578063e4f8d62e146102d8578063e6375d3e14610299578063eb50c06114610257578063f2fde38b146101cd578063f56b4d05146101a05763fec4ff171461017f573861000f565b3461019b57600036600319011261019b57602060405160028152f35b600080fd5b3461019b57600036600319011261019b5760206101bb61112c565b6040516001600160a01b039091168152f35b3461019b57602036600319011261019b576101e6610d19565b6101ee6119f9565b6001600160a01b0316801561024157600580546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b631e4fbdf760e01b600052600060045260246000fd5b3461019b57602036600319011261019b57610270610d19565b6102786119f9565b6001600160a01b03166000908152601660205260409020805460ff19169055005b3461019b57602036600319011261019b576001600160a01b036102ba610d19565b16600052600d602052602060ff604060002054166040519015158152f35b3461019b57604036600319011261019b5760206102ff6102f6610d19565b60243590611077565b604051908152f35b3461019b57604036600319011261019b57610320610d19565b610328610d2f565b6001600160a01b039182166000908152600160209081526040808320949093168252928352819020549051908152f35b3461019b57600036600319011261019b57600a54604051625f8d8f60e81b81529060209082906001600160a01b0316818061039560048201610f52565b03915afa80156103e5576000906103b2575b602090604051908152f35b506020813d6020116103dd575b816103cc60209383610ddb565b8101031261019b57602090516103a7565b3d91506103bf565b6040513d6000823e3d90fd5b3461019b57602036600319011261019b57600435601a5481101561019b5761041b61012091610d75565b5080549060ff600182015491600281015460018060a01b0360038301541660018060a01b0360048401541691610479600660058601549501549660405198895261046a60208a01888316610d45565b8660408a019160081c16610d68565b6060870152608086015260a0808601919091526001600160a01b03821660c08601521c16151560e0830152610100820152f35b3461019b57604036600319011261019b576104d26104c8610d19565b6024359033611198565b602060405160018152f35b3461019b57602036600319011261019b576104f6610d19565b6104fe6119f9565b6001600160a01b03166000908152601660205260409020805460ff19166001179055005b3461019b57600036600319011261019b5760405160006004548060011c9060018116801561061f575b60208310811461060b578285529081156105e75750600114610588575b6105848361057881850382610ddb565b60405191829182610cd0565b0390f35b600460009081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b8082106105cd57509091508101602001610578610568565b9192600181602092548385880101520191019092916105b5565b60ff191660208086019190915291151560051b840190910191506105789050610568565b634e487b7160e01b84526022600452602484fd5b91607f169161054b565b3461019b57600036600319011261019b576005546040516001600160a01b039091168152602090f35b3461019b57600036600319011261019b5761066b6119f9565b600160ff196010541617601055610680611bd2565b6010805460ff19169055005b3461019b57600036600319011261019b576106a56119f9565b600580546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461019b57602036600319011261019b576001600160a01b0361070a610d19565b1660005260006020526020604060002054604051908152f35b3461019b57600036600319011261019b5760065461074081610dfc565b9061074e6040519283610ddb565b808252600660009081526020830191907ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f835b8383106107e25784866040519182916020830190602084525180915260408301919060005b8181106107b4575050500390f35b825180516001600160a01b0316855260209081015181860152869550604090940193909201916001016107a6565b600260206001926040516107f581610daa565b848060a01b0386541681528486015483820152815201920192019190610781565b3461019b57602036600319011261019b576001600160a01b03610837610d19565b16600052600f60205260406000206040518060208354918281520190819360005260206000209060005b8181106108ba5750505081610877910382610ddb565b6040519182916020830190602084525180915260408301919060005b8181106108a1575050500390f35b8251845285945060209384019390920191600101610893565b8254845260209093019260019283019201610861565b3461019b57602036600319011261019b5760206102ff6108ee610d19565b610f20565b3461019b57600036600319011261019b5760206102ff610eb9565b3461019b57600036600319011261019b576020601854604051908152f35b3461019b57600036600319011261019b576020600854604051908152f35b3461019b57600036600319011261019b576104d2333361166f565b3461019b57600036600319011261019b576020601154604051908152f35b3461019b57600036600319011261019b57602060405160128152f35b3461019b57600036600319011261019b57601a546109bc81610dfc565b906109ca6040519283610ddb565b808252601a60009081526020830191907f057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e835b838310610ac65784866040519182916020830190602084525180915260408301919060005b818110610a30575050500390f35b919350916020610120600192610100875180518352610a558582015186850190610d45565b610a6760408201516040850190610d68565b60608101516060840152858060a01b036080820151166080840152858060a01b0360a08201511660a0840152858060a01b0360c08201511660c084015260e0810151151560e08401520151610100820152019401910191849392610a22565b60076020600192610ad685610e13565b8152019201920191906109fd565b3461019b57606036600319011261019b57610afd610d19565b610b05610d2f565b6001600160a01b0382166000818152600160209081526040808320338452909152902054909260443592916000198110610b45575b506104d29350611198565b838110610bb4578415610b9e573315610b88576104d2946000526001602052604060002060018060a01b0333166000526020528360406000209103905584610b3a565b634a1406b160e11b600052600060045260246000fd5b63e602df0560e01b600052600060045260246000fd5b8390637dc7a0d960e11b6000523360045260245260445260646000fd5b3461019b57600036600319011261019b576020600254604051908152f35b3461019b57604036600319011261019b576104d2610c0b610d19565b602435903361223a565b3461019b57600036600319011261019b5760006003548060011c90600181168015610cc6575b60208310811461060b578285529081156105e75750600114610c67576105848361057881850382610ddb565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b939250905b808210610cac57509091508101602001610578610568565b919260018160209254838588010152019101909291610c94565b91607f1691610c3b565b91909160208152825180602083015260005b818110610d03575060409293506000838284010152601f8019910116010190565b8060208092870101516040828601015201610ce2565b600435906001600160a01b038216820361019b57565b602435906001600160a01b038216820361019b57565b906005821015610d525752565b634e487b7160e01b600052602160045260246000fd5b906003821015610d525752565b601a54811015610d9457601a6000526007602060002091020190600090565b634e487b7160e01b600052603260045260246000fd5b604081019081106001600160401b03821117610dc557604052565b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b03821117610dc557604052565b6001600160401b038111610dc55760051b60200190565b9060405161012081018181106001600160401b03821117610dc557604052809280548252600181015460ff8116906005821015610d525760ff91602085015260081c166003811015610d525760408301526002810154606083015260038101546001600160a01b0390811660808401526004820154811660a080850191909152600583015491821660c08501521c60ff16151560e0830152600601546101009190910152565b60145460405163441062ed60e01b815290602090829060049082906001600160a01b03165afa9081156103e557600091610ef1575090565b90506020813d602011610f18575b81610f0c60209383610ddb565b8101031261019b575190565b3d9150610eff565b6001600160a01b0381166000908152600d602052604090205460ff16610f4c57610f49906119ab565b90565b50600090565b6040602082019160208152601a548093520190601a60005260206000209060005b818110610f805750505090565b909192600761012060019286548152610fb684880154610fa66020840160ff8316610d45565b60ff604084019160081c16610d68565b60028701546060820152600387015460a085811b86900391821660808401526004890154821681840152600589015491821660c08401521c60ff16151560e08201526006870154610100820152019401929101610f73565b600654811015610d9457600660005260206000209060011b0190600090565b8054821015610d945760005260206000200190600090565b6001600160a01b0391821681529116602082015260408101919091526060810191909152608081019190915260a00190565b6001600160a01b0381166000818152600f6020526040902054919291821015611110576020916110cc60018060a01b03600a54169160016110b78261100e565b50015493600052600f8552604060002061102d565b90549060031b1c91600754946110fa6040519687958694859463a89055e560e01b8652309060048701611045565b03915afa9081156103e557600091610ef1575090565b505050600090565b51906001600160a01b038216820361019b57565b6014546040516327ab5d0f60e01b815290602090829060049082906001600160a01b03165afa9081156103e557600091611164575090565b90506020813d602011611190575b8161117f60209383610ddb565b8101031261019b57610f4990611118565b3d9150611172565b6019805460ff60281b19169055600a54604051639ca7068f60e01b81526001600160a01b03848116600483018190529596959260209183916024918391165afa9081156103e557600091611650575b5061164357601a54158015611633575b8015611611575b80156115f9575b80156115ed575b61159f5761121983612350565b80611586575b611568575b5083601755600090600080925b601a548410156113f25761124d61124785610d75565b50610e13565b90600080604084018051906003821015610d52576000916112a257505050508161129361128e611299936112836001968d612d4c565b92909294838a612ddf565b611a59565b93611a59565b93019290611231565b805160038110156113de57600114806113ce575b156112d657505050508161129361128e611299936112836001968d612d4c565b939192935160038110156113ba576002149081611325575b5091611299939160019593611309575b611293929350611a59565b611293925061131d9150611283848d612d4c565b8392506112fe565b905061135760208860018060a01b03600a54168c60405180958194829363154b004960e31b845230916004850161245e565b03915afa9182156113ae5791611299959391600197959391611380575b509193955091936112ee565b6113a1915060203d81116113a7575b6113998183610ddb565b8101906122a1565b38611374565b503d61138f565b604051903d90823e3d90fd5b634e487b7160e01b82526021600452602482fd5b506113d98a89612481565b6112b6565b634e487b7160e01b83526021600452602483fd5b61140993506114049192959683611529575b611bc5565b600a5460405163ca497e2360e01b8152939192919060209085906001600160a01b0316818061143a60048201610f52565b03915afa80156103e5576114889460009161150a575b50806114fb575b806114ee575b806114de575b80156114cf575b61148a575b611479828261166f565b61148382826124cb565b6123af565b565b6114948282612481565b61146f57600160ff1960105416176010556114ad611bd2565b6010805460ff191690556019805460ff60281b1916600160281b17905561146f565b5060ff60195460081c1661146a565b5060ff60195460281c1615611463565b5060ff601054161561145d565b5060ff60195460201c16611457565b611523915060203d6020116113a7576113998183610ddb565b38611450565b60195460081c60ff1615611556576115428430896123af565b61154e84601854611a59565b601855611bc5565b6114048461156261112c565b896123af565b600052600d6020526040600020600160ff1982541617905538611224565b5080600052600d60205260ff604060002054161561121f565b509061148892939160195460ff8160201c1615806115de575b6115c8575b50611483828261166f565b60ff60201b1916600160201b17601955386115bd565b506115e883612350565b6115b8565b5060ff6010541661120c565b5080600052601660205260ff60406000205416611205565b506001600160a01b03821660009081526016602052604090205460ff166111fe565b5060ff60195460201c16156111f7565b50611488929391506122b9565b611669915060203d6020116113a7576113998183610ddb565b386111e7565b60ff60195460181c16611680575050565b6013546001600160a01b0390811693600093838316939281169290916060916040918587141591905b60065489101561199f575b87600052600f60205288604060002054116116f35787600052600f6020526116ee604060002060016116e58c61100e565b5001549061261c565b6116b4565b9692939495965b87600052600f60205288604060002054116117305787600052600f60205261172b604060002060016116e58c61100e565b6116fa565b96939495965b89600052600f602052886040600020541161176c5789600052600f602052611767604060002060016116e58c61100e565b611736565b979694929695939587600052600d60205260ff604060002054166000146119905760005b600084611969575b6040516117a58882610ddb565b6002815286366020830137604051916117be8984610ddb565b600283528736602085013760009380611948575b508061191f575b5060005b8381106117f15750505050600101976116a9565b806117fe60019284611a45565b5161180a575b016117dd565b61185d60206118188861100e565b505460a085901b859003908116906118308589611a45565b51169061183d8588611a45565b5191600060405180968195829463a9059cbb60e01b84526004840161263f565b03925af19081611903575b5015611804576118778661100e565b5054600b5460a084901b8490039081169116146118e5575b6118e08261189c8861100e565b500154838060a01b036118af8488611a45565b5116600052600f6020526118c788604060002061102d565b90919082549060031b91821b91600019901b1916179055565b611804565b6118fb6118f28285611a45565b51600954611bc5565b60095561188f565b61191a9060203d81116113a7576113998183610ddb565b611868565b92819361192f8261194194611a45565b528a61193b8285611a45565b52611a7c565b91386117d9565b90935061195482611a38565b528a61195f83611a38565b52600192386117d2565b888152600d60205260ff604082205416600003611798575061198b8288611077565b611798565b61199a8183611077565b611790565b98505050505050505050565b602060018060a01b03600a54166008549060018060a01b038416600052600c835260406000205491600754946110fa60405196879586948594631d2fa43b60e11b8652309060048701611045565b6005546001600160a01b03163303611a0d57565b63118cdaa760e01b6000523360045260246000fd5b919082604091031261019b576020825192015190565b805115610d945760200190565b8051821015610d945760209160051b010190565b91908201809211611a6657565b634e487b7160e01b600052601160045260246000fd5b6000198114611a665760010190565b919082604091031261019b57610f496020611aa584611118565b9301611118565b6001600160a01b039182168152911660208201526060604082018190526015805491830182905260009081526080909201917f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec47591905b818110611b0f5750505090565b82546001600160a01b0316845260209093019260019283019201611b02565b81810292918115918404141715611a6657565b8115611b4b570490565b634e487b7160e01b600052601260045260246000fd5b60a091936020936080830195600180861b03168352600180851b03168483015260408201526080606082015284518094520192019060005b818110611ba65750505090565b82516001600160a01b0316845260209384019390920191600101611b99565b91908203918211611a6657565b6000908182601a5491611be483610dfc565b91611bf26040519384610ddb565b838352601f19611c0185610dfc565b01366020850137611c1184610dfc565b93611c1f6040519586610ddb565b808552611c2e601f1991610dfc565b0136602086013785915b601a54831015611de057611c4b83610d75565b50926006840154938415611dd45760ff600182015416600581101580611dc05760018214928315611d97575b508215611d72575b5050611c95575b6001919293505b019190611c38565b600a546017546040805163059b6d4760e21b81526004810197909752602487019190915290859060449082906001600160a01b03165afa938415611d675788908995611d34575b5080611d00575b5060019192936006611cf483610d75565b50015583929150611c86565b611d27611d2d9160019485611d15868b611a45565b5281611d21868c611a45565b52611a59565b93611a7c565b9291611ce3565b9050611d5891945060403d8111611d60575b611d508183610ddb565b810190611a22565b939038611cdc565b503d611d46565b6040513d8a823e3d90fd5b909150611d83576004143880611c7f565b634e487b7160e01b89526021600452602489fd5b8b935060028314915081611dae575b509138611c77565b60ff91506005015460a01c1638611da6565b634e487b7160e01b8b52602160045260248bfd5b50600191929350611c8d565b600a54600b5460408051632a8ddb2f60e01b815296996001600160a01b03938416999790965094509184918291611e1c91163060048401611aac565b0381895afa9182156121f3578392612207575b506001600160a01b038216156121fe5760406018546044601754918351998a93849263059b6d4760e21b8452600484015260248301525afa9081156121f357839684926121ca575b5086611e8291611a59565b9182156121c057602490611ea184611e9c6007548b611b2e565b611b41565b92601855611eba8460018060a01b03601254163061223a565b601254600a546040516343d7ef9f60e11b8152306004820152936001600160a01b03928316939288928692918391165afa9283156121b5578693612191575b50813b1561218d579185918583611f299560405196879586948593637e18437960e01b8552309060048601611b61565b03925af19081612179575b50611f9e5750505b601a54811015611f895780611f5360019287611a45565b51611f5f575b01611f3c565b611f698185611a45565b51611f826006611f7884610d75565b5001918254611a59565b9055611f59565b50925050611f9990601854611a59565b601855565b909294959391956024602060018060a01b03600b5416604051928380926370a0823160e01b82523060048301525afa908115611d67578891612145575b5061201e92612006611ffd611ff66120189460095490611bc5565b9283611b2e565b60075490611b41565b9061140461201261112c565b836126db565b93611bc5565b92821561213d57855b601a548110156121345761203b8183611a45565b51158015612122575b61211a5761206085611e9c8661205a8588611a45565b51611b2e565b61206982610d75565b509060ff6001830154166005811015612106576001939291908481036120a2575061209661209c92610e13565b90612b53565b01612027565b60028114806120f5575b156120cd57506120c8916003858060a01b0391015416906126db565b61209c565b6004146120dc575b505061209c565b6120e86120ee92610e13565b90612831565b38806120d5565b5060ff600584015460a01c166120ac565b634e487b7160e01b8a52602160045260248afd5b60019061209c565b5061212d8184611a45565b5115612044565b50505050509050565b505050509050565b90506020813d602011612171575b8161216060209383610ddb565b8101031261019b575161201e611fdb565b3d9150612153565b8461218691959295610ddb565b9238611f34565b8580fd5b6121ae9193503d8088833e6121a68183610ddb565b81019061265a565b9138611ef9565b6040513d88823e3d90fd5b5050505092505050565b611e8297506121e991925060403d604011611d6057611d508183610ddb565b9096509086611e77565b6040513d85823e3d90fd5b50505092505050565b61222a91925060403d604011612233575b6122228183610ddb565b810190611a8b565b90509038611e2f565b503d612218565b6001600160a01b0316908115610b9e576001600160a01b0316918215610b885760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260018252604060002085600052825280604060002055604051908152a3565b9081602091031261019b5751801515810361019b5790565b6001600160a01b0316801561233a5760009181835282602052604083205481811061232157817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef926020928587528684520360408620558060025403600255604051908152a3565b6064939263391434e360e21b8452600452602452604452fd5b634b637e8f60e11b600052600060045260246000fd5b600a54604051630d5c7b5d60e41b81526001600160a01b0392831660048201523060248201529160209183916044918391165afa9081156103e557600091612396575090565b610f49915060203d6020116113a7576113998183610ddb565b6001600160a01b031690811561233a576001600160a01b031691821561244857600082815280602052604081205482811061242e5791604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815280845220818154019055604051908152a3565b916064928463391434e360e21b8452600452602452604452fd5b63ec442f0560e01b600052600060045260246000fd5b6001600160a01b0391821681529181166020830152909116604082015260600190565b600a54604051636468b51760e01b81529260209284926001600160a01b031691839182916124b5913091906004850161245e565b03915afa9081156103e557600091612396575090565b9060ff60195460101c1615612618576013546001600160a01b03838116939181169190831660008582036125c2575084600052600d60205260ff604060002054166000146125b45760005b906000935b612524816119ab565b6008546000928352600c60205260408084208290559883528883208190559282529690205580612596575b505080612578575b5050806125615750565b60135461148891906001600160a01b0316306123af565b61258182612350565b6125575761258f91306123af565b3880612557565b61259f82612350565b61254f576125ad91306123af565b388061254f565b6125bd82610f20565b612516565b858152600d602052604081205460ff1615612609575b9080600052600d60205260ff604060002054166000146125fb5760005b9361251b565b61260485610f20565b6125f5565b5061261382610f20565b6125d8565b5050565b80549190600160401b831015610dc557826118c79160016114889501815561102d565b6001600160a01b039091168152602081019190915260400190565b60208183031261019b578051906001600160401b03821161019b57019080601f8301121561019b57815161268d81610dfc565b9261269b6040519485610ddb565b81845260208085019260051b82010192831161019b57602001905b8282106126c35750505090565b602080916126d084611118565b8152019101906126b6565b9060009082156127c757600b546001600160a01b0316803b1561282d57828091602460405180948193632e1a7d4d60e01b83528960048401525af19081612819575b5061278257600b5460405163a9059cbb60e01b81529360209285926001600160a01b03169183918691839161275691906004840161263f565b03925af19081156113ae575061276a575b50565b6127679060203d6020116113a7576113998183610ddb565b8180808086855af13d15612814573d6001600160401b03811161280057604051906127b7601f8201601f191660200183610ddb565b81528360203d92013e5b156127cc575b505050565b600b5460405163a9059cbb60e01b81529360209285926001600160a01b03169183918691839161275691906004840161263f565b634e487b7160e01b84526041600452602484fd5b6127c1565b8361282691949294610ddb565b913861271d565b8280fd5b60009181156127c75760a0018051600b549192916001600160a01b03908116911614612b0957600a54600b54835160408051632a8ddb2f60e01b815294936001600160a01b039384169391928692918216918391829161289691168760048401611aac565b03915afa928315612afe579060249392918693612adb575b5084516040516370a0823160e01b81523060048201529460209186919082906001600160a01b03165afa9384156121b5578694612aa6575b5060125460405163095ea7b360e01b81529160209183919082908a90829061291c9089906001600160a01b03166004840161263f565b03925af180156121b557612a89575b5060125484516001600160a01b0391821692916129489116613045565b92823b15612a855791612978939187809460405196879586948593632d4d638360e11b8552309060048601611b61565b03925af19081612a71575b5061298d57505050565b81516040516370a0823160e01b81523060048201529190602090839060249082906001600160a01b03165afa8015612a66578490612a32575b6129d09250611bc5565b90816129db57505050565b51612a08906129f2906001600160a01b0316612f79565b9260406002549130815280602052205490611bc5565b9081156127c757611f78612a28612a2e93611e9c60019460075490611b2e565b9361100e565b9055565b506020823d602011612a5e575b81612a4c60209383610ddb565b8101031261019b576129d091516129c6565b3d9150612a3f565b6040513d86823e3d90fd5b84612a7e91959295610ddb565b9238612983565b8680fd5b612aa19060203d6020116113a7576113998183610ddb565b61292b565b9093506020813d602011612ad3575b81612ac260209383610ddb565b8101031261218d57519260206128e6565b3d9150612ab5565b612af591935060403d604011612233576122228183610ddb565b905091386128ae565b6040513d87823e3d90fd5b906129f2612b2f91612b1d84600954611a59565b600955516001600160a01b0316612f79565b9081612b3a57505050565b611f78612a28612a2e93611e9c60019460075490611b2e565b9060009082156127c75760a081018051600b549192916001600160a01b0390811691168114612d155750600a54600b54835160408051632a8ddb2f60e01b815294936001600160a01b0393841693919286929182169183918291612bbc91168760048401611aac565b03915afa928315612afe579086918694612ce9575b5060125460405163095ea7b360e01b8152926020928492909183918a918391612c0791906001600160a01b03166004840161263f565b03925af18015612afe57612ccc575b506012546080919091018051935190936001600160a01b039283169290811691612c409116613045565b92823b1561218d57918691868094612c6e60405197889687958694632d4d638360e11b865260048601611b61565b03925af19081612cb8575b506127c757600b54905160405163a9059cbb60e01b81529360209285926001600160a01b0391821692849287928492612756929091166004840161263f565b83612cc591949294610ddb565b9138612c79565b612ce49060203d6020116113a7576113998183610ddb565b612c16565b602091945091612d0a612c079360403d604011612233576122228183610ddb565b905094915091612bd1565b60809091015160405163a9059cbb60e01b81529460209350859291839186918391612756916001600160a01b03166004840161263f565b600a546060909201516001600160a01b0392909216929160409160a490612d71610eb9565b9560ff6019541685519788958694632b8d28ef60e21b86526004860152602485015260448401521515606483015261271060848301525afa9182156103e557600090600093612dbf57509190565b9050612ddb91925060403d604011611d6057611d508183610ddb565b9091565b909160208101908151916005831015610d5257600092612e065750505090611488916122b9565b80516005811015612f655785929190600303612e6d575050612e2d90612e429330906123af565b60406002549130815280602052205490611bc5565b9081612e4c575050565b612e6891611e9c612e609260075490611b2e565b600854611a59565b600855565b8091949392505160058110156113de57600203612f1057506080830180516001600160a01b031682526016602052604082205490919060ff1615612ee9575b5060e083015115612ed35750611f78612a2e92612ecd8560069430906123af565b51610d75565b516114889392506001600160a01b0316906123af565b81516001600160a01b03168152601660205260409020805460ff1916600117905538612eac565b809492945160058110156113de57600103612f305750506114889261309a565b51906005821015612f515750600414612f4857505050565b6114889261309a565b634e487b7160e01b81526021600452602490fd5b634e487b7160e01b84526021600452602484fd5b6006549060005b82811061301a575060405190612f9582610daa565b6001600160a01b0316815260006020820190815291600160401b811015610dc557806001612fc6920160065561100e565b92909261300457905182546001600160a01b0319166001600160a01b039190911617825551600191909101556006546000198101908111611a665790565b634e487b7160e01b600052600060045260246000fd5b6130238161100e565b50546001600160a01b0383811691161461303f57600101612f80565b91505090565b600a546040516377a9efe360e11b81526001600160a01b0392831660048201529160009183916024918391165afa9081156103e557600091613085575090565b610f4991503d806000833e6121a68183610ddb565b611f788293612ecd6130bd94600694600160ff19601054161760105530906123af565b905560ff196010541660105556fea264697066735822122005404067a9c75949def711aac05d72403bef69300432efb25296511b50eaf2dd64736f6c634300081c003355f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec475057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e00000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000a3a4a285c777ec2264cb49b586681f5a0f9210cb000000000000000000000000f298cf996edd7afd84783ac5fa26902c914c07580000000000000000000000000000000000000000000000302379bf2ca2e0000000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000ed044a9cd942b6c32751a1c6a83f5e3e886375b3000000000000000000000000a3a4a285c777ec2264cb49b586681f5a0f9210cb00000000000000000000000057bc1bc5c40a903a7ecbcf06e224f47e301bf1b100000000000000000000000000000000000000000000000000000000000000135372657930782046696e616c204c6567616379000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006537265793078000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000698000000000000000000000000f298cf996edd7afd84783ac5fa26902c914c0758000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c33524d2249ec5dff8bb058bc953980cfa4e8dd600000000000000000000000000000000000000000000000000000000000003690000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000369000000000000000000000000c33524d2249ec5dff8bb058bc953980cfa4e8dd6000000000000000000000000000000000000000000000000000000000000036900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x608080604052600436101561001d575b50361561001b57600080fd5b005b60003560e01c90816306fdde0314610c1557508063095ea7b314610bef57806318160ddd14610bd157806323b872dd14610ae45780632973ef2d1461099f578063313ce56714610983578063378dc3dc14610965578063406cf2291461094a5780634f30800d1461092c57806356cdad1d1461090e5780635f75baf6146108f3578063695d69b3146108d05780636a2072d414610816578063709df63c1461072357806370a08231146106e9578063715018a61461068c5780638453ef99146106525780638da5cb5b146106295780639045be581461029957806395d89b41146105225780639b165f4e146104dd578063a9059cbb146104ac578063c5be2bc7146103f1578063cb78c16314610358578063dd62ed3e14610307578063e4f8d62e146102d8578063e6375d3e14610299578063eb50c06114610257578063f2fde38b146101cd578063f56b4d05146101a05763fec4ff171461017f573861000f565b3461019b57600036600319011261019b57602060405160028152f35b600080fd5b3461019b57600036600319011261019b5760206101bb61112c565b6040516001600160a01b039091168152f35b3461019b57602036600319011261019b576101e6610d19565b6101ee6119f9565b6001600160a01b0316801561024157600580546001600160a01b0319811683179091556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b631e4fbdf760e01b600052600060045260246000fd5b3461019b57602036600319011261019b57610270610d19565b6102786119f9565b6001600160a01b03166000908152601660205260409020805460ff19169055005b3461019b57602036600319011261019b576001600160a01b036102ba610d19565b16600052600d602052602060ff604060002054166040519015158152f35b3461019b57604036600319011261019b5760206102ff6102f6610d19565b60243590611077565b604051908152f35b3461019b57604036600319011261019b57610320610d19565b610328610d2f565b6001600160a01b039182166000908152600160209081526040808320949093168252928352819020549051908152f35b3461019b57600036600319011261019b57600a54604051625f8d8f60e81b81529060209082906001600160a01b0316818061039560048201610f52565b03915afa80156103e5576000906103b2575b602090604051908152f35b506020813d6020116103dd575b816103cc60209383610ddb565b8101031261019b57602090516103a7565b3d91506103bf565b6040513d6000823e3d90fd5b3461019b57602036600319011261019b57600435601a5481101561019b5761041b61012091610d75565b5080549060ff600182015491600281015460018060a01b0360038301541660018060a01b0360048401541691610479600660058601549501549660405198895261046a60208a01888316610d45565b8660408a019160081c16610d68565b6060870152608086015260a0808601919091526001600160a01b03821660c08601521c16151560e0830152610100820152f35b3461019b57604036600319011261019b576104d26104c8610d19565b6024359033611198565b602060405160018152f35b3461019b57602036600319011261019b576104f6610d19565b6104fe6119f9565b6001600160a01b03166000908152601660205260409020805460ff19166001179055005b3461019b57600036600319011261019b5760405160006004548060011c9060018116801561061f575b60208310811461060b578285529081156105e75750600114610588575b6105848361057881850382610ddb565b60405191829182610cd0565b0390f35b600460009081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b8082106105cd57509091508101602001610578610568565b9192600181602092548385880101520191019092916105b5565b60ff191660208086019190915291151560051b840190910191506105789050610568565b634e487b7160e01b84526022600452602484fd5b91607f169161054b565b3461019b57600036600319011261019b576005546040516001600160a01b039091168152602090f35b3461019b57600036600319011261019b5761066b6119f9565b600160ff196010541617601055610680611bd2565b6010805460ff19169055005b3461019b57600036600319011261019b576106a56119f9565b600580546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461019b57602036600319011261019b576001600160a01b0361070a610d19565b1660005260006020526020604060002054604051908152f35b3461019b57600036600319011261019b5760065461074081610dfc565b9061074e6040519283610ddb565b808252600660009081526020830191907ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f835b8383106107e25784866040519182916020830190602084525180915260408301919060005b8181106107b4575050500390f35b825180516001600160a01b0316855260209081015181860152869550604090940193909201916001016107a6565b600260206001926040516107f581610daa565b848060a01b0386541681528486015483820152815201920192019190610781565b3461019b57602036600319011261019b576001600160a01b03610837610d19565b16600052600f60205260406000206040518060208354918281520190819360005260206000209060005b8181106108ba5750505081610877910382610ddb565b6040519182916020830190602084525180915260408301919060005b8181106108a1575050500390f35b8251845285945060209384019390920191600101610893565b8254845260209093019260019283019201610861565b3461019b57602036600319011261019b5760206102ff6108ee610d19565b610f20565b3461019b57600036600319011261019b5760206102ff610eb9565b3461019b57600036600319011261019b576020601854604051908152f35b3461019b57600036600319011261019b576020600854604051908152f35b3461019b57600036600319011261019b576104d2333361166f565b3461019b57600036600319011261019b576020601154604051908152f35b3461019b57600036600319011261019b57602060405160128152f35b3461019b57600036600319011261019b57601a546109bc81610dfc565b906109ca6040519283610ddb565b808252601a60009081526020830191907f057c384a7d1c54f3a1b2e5e67b2617b8224fdfd1ea7234eea573a6ff665ff63e835b838310610ac65784866040519182916020830190602084525180915260408301919060005b818110610a30575050500390f35b919350916020610120600192610100875180518352610a558582015186850190610d45565b610a6760408201516040850190610d68565b60608101516060840152858060a01b036080820151166080840152858060a01b0360a08201511660a0840152858060a01b0360c08201511660c084015260e0810151151560e08401520151610100820152019401910191849392610a22565b60076020600192610ad685610e13565b8152019201920191906109fd565b3461019b57606036600319011261019b57610afd610d19565b610b05610d2f565b6001600160a01b0382166000818152600160209081526040808320338452909152902054909260443592916000198110610b45575b506104d29350611198565b838110610bb4578415610b9e573315610b88576104d2946000526001602052604060002060018060a01b0333166000526020528360406000209103905584610b3a565b634a1406b160e11b600052600060045260246000fd5b63e602df0560e01b600052600060045260246000fd5b8390637dc7a0d960e11b6000523360045260245260445260646000fd5b3461019b57600036600319011261019b576020600254604051908152f35b3461019b57604036600319011261019b576104d2610c0b610d19565b602435903361223a565b3461019b57600036600319011261019b5760006003548060011c90600181168015610cc6575b60208310811461060b578285529081156105e75750600114610c67576105848361057881850382610ddb565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b939250905b808210610cac57509091508101602001610578610568565b919260018160209254838588010152019101909291610c94565b91607f1691610c3b565b91909160208152825180602083015260005b818110610d03575060409293506000838284010152601f8019910116010190565b8060208092870101516040828601015201610ce2565b600435906001600160a01b038216820361019b57565b602435906001600160a01b038216820361019b57565b906005821015610d525752565b634e487b7160e01b600052602160045260246000fd5b906003821015610d525752565b601a54811015610d9457601a6000526007602060002091020190600090565b634e487b7160e01b600052603260045260246000fd5b604081019081106001600160401b03821117610dc557604052565b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b03821117610dc557604052565b6001600160401b038111610dc55760051b60200190565b9060405161012081018181106001600160401b03821117610dc557604052809280548252600181015460ff8116906005821015610d525760ff91602085015260081c166003811015610d525760408301526002810154606083015260038101546001600160a01b0390811660808401526004820154811660a080850191909152600583015491821660c08501521c60ff16151560e0830152600601546101009190910152565b60145460405163441062ed60e01b815290602090829060049082906001600160a01b03165afa9081156103e557600091610ef1575090565b90506020813d602011610f18575b81610f0c60209383610ddb565b8101031261019b575190565b3d9150610eff565b6001600160a01b0381166000908152600d602052604090205460ff16610f4c57610f49906119ab565b90565b50600090565b6040602082019160208152601a548093520190601a60005260206000209060005b818110610f805750505090565b909192600761012060019286548152610fb684880154610fa66020840160ff8316610d45565b60ff604084019160081c16610d68565b60028701546060820152600387015460a085811b86900391821660808401526004890154821681840152600589015491821660c08401521c60ff16151560e08201526006870154610100820152019401929101610f73565b600654811015610d9457600660005260206000209060011b0190600090565b8054821015610d945760005260206000200190600090565b6001600160a01b0391821681529116602082015260408101919091526060810191909152608081019190915260a00190565b6001600160a01b0381166000818152600f6020526040902054919291821015611110576020916110cc60018060a01b03600a54169160016110b78261100e565b50015493600052600f8552604060002061102d565b90549060031b1c91600754946110fa6040519687958694859463a89055e560e01b8652309060048701611045565b03915afa9081156103e557600091610ef1575090565b505050600090565b51906001600160a01b038216820361019b57565b6014546040516327ab5d0f60e01b815290602090829060049082906001600160a01b03165afa9081156103e557600091611164575090565b90506020813d602011611190575b8161117f60209383610ddb565b8101031261019b57610f4990611118565b3d9150611172565b6019805460ff60281b19169055600a54604051639ca7068f60e01b81526001600160a01b03848116600483018190529596959260209183916024918391165afa9081156103e557600091611650575b5061164357601a54158015611633575b8015611611575b80156115f9575b80156115ed575b61159f5761121983612350565b80611586575b611568575b5083601755600090600080925b601a548410156113f25761124d61124785610d75565b50610e13565b90600080604084018051906003821015610d52576000916112a257505050508161129361128e611299936112836001968d612d4c565b92909294838a612ddf565b611a59565b93611a59565b93019290611231565b805160038110156113de57600114806113ce575b156112d657505050508161129361128e611299936112836001968d612d4c565b939192935160038110156113ba576002149081611325575b5091611299939160019593611309575b611293929350611a59565b611293925061131d9150611283848d612d4c565b8392506112fe565b905061135760208860018060a01b03600a54168c60405180958194829363154b004960e31b845230916004850161245e565b03915afa9182156113ae5791611299959391600197959391611380575b509193955091936112ee565b6113a1915060203d81116113a7575b6113998183610ddb565b8101906122a1565b38611374565b503d61138f565b604051903d90823e3d90fd5b634e487b7160e01b82526021600452602482fd5b506113d98a89612481565b6112b6565b634e487b7160e01b83526021600452602483fd5b61140993506114049192959683611529575b611bc5565b600a5460405163ca497e2360e01b8152939192919060209085906001600160a01b0316818061143a60048201610f52565b03915afa80156103e5576114889460009161150a575b50806114fb575b806114ee575b806114de575b80156114cf575b61148a575b611479828261166f565b61148382826124cb565b6123af565b565b6114948282612481565b61146f57600160ff1960105416176010556114ad611bd2565b6010805460ff191690556019805460ff60281b1916600160281b17905561146f565b5060ff60195460081c1661146a565b5060ff60195460281c1615611463565b5060ff601054161561145d565b5060ff60195460201c16611457565b611523915060203d6020116113a7576113998183610ddb565b38611450565b60195460081c60ff1615611556576115428430896123af565b61154e84601854611a59565b601855611bc5565b6114048461156261112c565b896123af565b600052600d6020526040600020600160ff1982541617905538611224565b5080600052600d60205260ff604060002054161561121f565b509061148892939160195460ff8160201c1615806115de575b6115c8575b50611483828261166f565b60ff60201b1916600160201b17601955386115bd565b506115e883612350565b6115b8565b5060ff6010541661120c565b5080600052601660205260ff60406000205416611205565b506001600160a01b03821660009081526016602052604090205460ff166111fe565b5060ff60195460201c16156111f7565b50611488929391506122b9565b611669915060203d6020116113a7576113998183610ddb565b386111e7565b60ff60195460181c16611680575050565b6013546001600160a01b0390811693600093838316939281169290916060916040918587141591905b60065489101561199f575b87600052600f60205288604060002054116116f35787600052600f6020526116ee604060002060016116e58c61100e565b5001549061261c565b6116b4565b9692939495965b87600052600f60205288604060002054116117305787600052600f60205261172b604060002060016116e58c61100e565b6116fa565b96939495965b89600052600f602052886040600020541161176c5789600052600f602052611767604060002060016116e58c61100e565b611736565b979694929695939587600052600d60205260ff604060002054166000146119905760005b600084611969575b6040516117a58882610ddb565b6002815286366020830137604051916117be8984610ddb565b600283528736602085013760009380611948575b508061191f575b5060005b8381106117f15750505050600101976116a9565b806117fe60019284611a45565b5161180a575b016117dd565b61185d60206118188861100e565b505460a085901b859003908116906118308589611a45565b51169061183d8588611a45565b5191600060405180968195829463a9059cbb60e01b84526004840161263f565b03925af19081611903575b5015611804576118778661100e565b5054600b5460a084901b8490039081169116146118e5575b6118e08261189c8861100e565b500154838060a01b036118af8488611a45565b5116600052600f6020526118c788604060002061102d565b90919082549060031b91821b91600019901b1916179055565b611804565b6118fb6118f28285611a45565b51600954611bc5565b60095561188f565b61191a9060203d81116113a7576113998183610ddb565b611868565b92819361192f8261194194611a45565b528a61193b8285611a45565b52611a7c565b91386117d9565b90935061195482611a38565b528a61195f83611a38565b52600192386117d2565b888152600d60205260ff604082205416600003611798575061198b8288611077565b611798565b61199a8183611077565b611790565b98505050505050505050565b602060018060a01b03600a54166008549060018060a01b038416600052600c835260406000205491600754946110fa60405196879586948594631d2fa43b60e11b8652309060048701611045565b6005546001600160a01b03163303611a0d57565b63118cdaa760e01b6000523360045260246000fd5b919082604091031261019b576020825192015190565b805115610d945760200190565b8051821015610d945760209160051b010190565b91908201809211611a6657565b634e487b7160e01b600052601160045260246000fd5b6000198114611a665760010190565b919082604091031261019b57610f496020611aa584611118565b9301611118565b6001600160a01b039182168152911660208201526060604082018190526015805491830182905260009081526080909201917f55f448fdea98c4d29eb340757ef0a66cd03dbb9538908a6a81d96026b71ec47591905b818110611b0f5750505090565b82546001600160a01b0316845260209093019260019283019201611b02565b81810292918115918404141715611a6657565b8115611b4b570490565b634e487b7160e01b600052601260045260246000fd5b60a091936020936080830195600180861b03168352600180851b03168483015260408201526080606082015284518094520192019060005b818110611ba65750505090565b82516001600160a01b0316845260209384019390920191600101611b99565b91908203918211611a6657565b6000908182601a5491611be483610dfc565b91611bf26040519384610ddb565b838352601f19611c0185610dfc565b01366020850137611c1184610dfc565b93611c1f6040519586610ddb565b808552611c2e601f1991610dfc565b0136602086013785915b601a54831015611de057611c4b83610d75565b50926006840154938415611dd45760ff600182015416600581101580611dc05760018214928315611d97575b508215611d72575b5050611c95575b6001919293505b019190611c38565b600a546017546040805163059b6d4760e21b81526004810197909752602487019190915290859060449082906001600160a01b03165afa938415611d675788908995611d34575b5080611d00575b5060019192936006611cf483610d75565b50015583929150611c86565b611d27611d2d9160019485611d15868b611a45565b5281611d21868c611a45565b52611a59565b93611a7c565b9291611ce3565b9050611d5891945060403d8111611d60575b611d508183610ddb565b810190611a22565b939038611cdc565b503d611d46565b6040513d8a823e3d90fd5b909150611d83576004143880611c7f565b634e487b7160e01b89526021600452602489fd5b8b935060028314915081611dae575b509138611c77565b60ff91506005015460a01c1638611da6565b634e487b7160e01b8b52602160045260248bfd5b50600191929350611c8d565b600a54600b5460408051632a8ddb2f60e01b815296996001600160a01b03938416999790965094509184918291611e1c91163060048401611aac565b0381895afa9182156121f3578392612207575b506001600160a01b038216156121fe5760406018546044601754918351998a93849263059b6d4760e21b8452600484015260248301525afa9081156121f357839684926121ca575b5086611e8291611a59565b9182156121c057602490611ea184611e9c6007548b611b2e565b611b41565b92601855611eba8460018060a01b03601254163061223a565b601254600a546040516343d7ef9f60e11b8152306004820152936001600160a01b03928316939288928692918391165afa9283156121b5578693612191575b50813b1561218d579185918583611f299560405196879586948593637e18437960e01b8552309060048601611b61565b03925af19081612179575b50611f9e5750505b601a54811015611f895780611f5360019287611a45565b51611f5f575b01611f3c565b611f698185611a45565b51611f826006611f7884610d75565b5001918254611a59565b9055611f59565b50925050611f9990601854611a59565b601855565b909294959391956024602060018060a01b03600b5416604051928380926370a0823160e01b82523060048301525afa908115611d67578891612145575b5061201e92612006611ffd611ff66120189460095490611bc5565b9283611b2e565b60075490611b41565b9061140461201261112c565b836126db565b93611bc5565b92821561213d57855b601a548110156121345761203b8183611a45565b51158015612122575b61211a5761206085611e9c8661205a8588611a45565b51611b2e565b61206982610d75565b509060ff6001830154166005811015612106576001939291908481036120a2575061209661209c92610e13565b90612b53565b01612027565b60028114806120f5575b156120cd57506120c8916003858060a01b0391015416906126db565b61209c565b6004146120dc575b505061209c565b6120e86120ee92610e13565b90612831565b38806120d5565b5060ff600584015460a01c166120ac565b634e487b7160e01b8a52602160045260248afd5b60019061209c565b5061212d8184611a45565b5115612044565b50505050509050565b505050509050565b90506020813d602011612171575b8161216060209383610ddb565b8101031261019b575161201e611fdb565b3d9150612153565b8461218691959295610ddb565b9238611f34565b8580fd5b6121ae9193503d8088833e6121a68183610ddb565b81019061265a565b9138611ef9565b6040513d88823e3d90fd5b5050505092505050565b611e8297506121e991925060403d604011611d6057611d508183610ddb565b9096509086611e77565b6040513d85823e3d90fd5b50505092505050565b61222a91925060403d604011612233575b6122228183610ddb565b810190611a8b565b90509038611e2f565b503d612218565b6001600160a01b0316908115610b9e576001600160a01b0316918215610b885760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260018252604060002085600052825280604060002055604051908152a3565b9081602091031261019b5751801515810361019b5790565b6001600160a01b0316801561233a5760009181835282602052604083205481811061232157817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef926020928587528684520360408620558060025403600255604051908152a3565b6064939263391434e360e21b8452600452602452604452fd5b634b637e8f60e11b600052600060045260246000fd5b600a54604051630d5c7b5d60e41b81526001600160a01b0392831660048201523060248201529160209183916044918391165afa9081156103e557600091612396575090565b610f49915060203d6020116113a7576113998183610ddb565b6001600160a01b031690811561233a576001600160a01b031691821561244857600082815280602052604081205482811061242e5791604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815280845220818154019055604051908152a3565b916064928463391434e360e21b8452600452602452604452fd5b63ec442f0560e01b600052600060045260246000fd5b6001600160a01b0391821681529181166020830152909116604082015260600190565b600a54604051636468b51760e01b81529260209284926001600160a01b031691839182916124b5913091906004850161245e565b03915afa9081156103e557600091612396575090565b9060ff60195460101c1615612618576013546001600160a01b03838116939181169190831660008582036125c2575084600052600d60205260ff604060002054166000146125b45760005b906000935b612524816119ab565b6008546000928352600c60205260408084208290559883528883208190559282529690205580612596575b505080612578575b5050806125615750565b60135461148891906001600160a01b0316306123af565b61258182612350565b6125575761258f91306123af565b3880612557565b61259f82612350565b61254f576125ad91306123af565b388061254f565b6125bd82610f20565b612516565b858152600d602052604081205460ff1615612609575b9080600052600d60205260ff604060002054166000146125fb5760005b9361251b565b61260485610f20565b6125f5565b5061261382610f20565b6125d8565b5050565b80549190600160401b831015610dc557826118c79160016114889501815561102d565b6001600160a01b039091168152602081019190915260400190565b60208183031261019b578051906001600160401b03821161019b57019080601f8301121561019b57815161268d81610dfc565b9261269b6040519485610ddb565b81845260208085019260051b82010192831161019b57602001905b8282106126c35750505090565b602080916126d084611118565b8152019101906126b6565b9060009082156127c757600b546001600160a01b0316803b1561282d57828091602460405180948193632e1a7d4d60e01b83528960048401525af19081612819575b5061278257600b5460405163a9059cbb60e01b81529360209285926001600160a01b03169183918691839161275691906004840161263f565b03925af19081156113ae575061276a575b50565b6127679060203d6020116113a7576113998183610ddb565b8180808086855af13d15612814573d6001600160401b03811161280057604051906127b7601f8201601f191660200183610ddb565b81528360203d92013e5b156127cc575b505050565b600b5460405163a9059cbb60e01b81529360209285926001600160a01b03169183918691839161275691906004840161263f565b634e487b7160e01b84526041600452602484fd5b6127c1565b8361282691949294610ddb565b913861271d565b8280fd5b60009181156127c75760a0018051600b549192916001600160a01b03908116911614612b0957600a54600b54835160408051632a8ddb2f60e01b815294936001600160a01b039384169391928692918216918391829161289691168760048401611aac565b03915afa928315612afe579060249392918693612adb575b5084516040516370a0823160e01b81523060048201529460209186919082906001600160a01b03165afa9384156121b5578694612aa6575b5060125460405163095ea7b360e01b81529160209183919082908a90829061291c9089906001600160a01b03166004840161263f565b03925af180156121b557612a89575b5060125484516001600160a01b0391821692916129489116613045565b92823b15612a855791612978939187809460405196879586948593632d4d638360e11b8552309060048601611b61565b03925af19081612a71575b5061298d57505050565b81516040516370a0823160e01b81523060048201529190602090839060249082906001600160a01b03165afa8015612a66578490612a32575b6129d09250611bc5565b90816129db57505050565b51612a08906129f2906001600160a01b0316612f79565b9260406002549130815280602052205490611bc5565b9081156127c757611f78612a28612a2e93611e9c60019460075490611b2e565b9361100e565b9055565b506020823d602011612a5e575b81612a4c60209383610ddb565b8101031261019b576129d091516129c6565b3d9150612a3f565b6040513d86823e3d90fd5b84612a7e91959295610ddb565b9238612983565b8680fd5b612aa19060203d6020116113a7576113998183610ddb565b61292b565b9093506020813d602011612ad3575b81612ac260209383610ddb565b8101031261218d57519260206128e6565b3d9150612ab5565b612af591935060403d604011612233576122228183610ddb565b905091386128ae565b6040513d87823e3d90fd5b906129f2612b2f91612b1d84600954611a59565b600955516001600160a01b0316612f79565b9081612b3a57505050565b611f78612a28612a2e93611e9c60019460075490611b2e565b9060009082156127c75760a081018051600b549192916001600160a01b0390811691168114612d155750600a54600b54835160408051632a8ddb2f60e01b815294936001600160a01b0393841693919286929182169183918291612bbc91168760048401611aac565b03915afa928315612afe579086918694612ce9575b5060125460405163095ea7b360e01b8152926020928492909183918a918391612c0791906001600160a01b03166004840161263f565b03925af18015612afe57612ccc575b506012546080919091018051935190936001600160a01b039283169290811691612c409116613045565b92823b1561218d57918691868094612c6e60405197889687958694632d4d638360e11b865260048601611b61565b03925af19081612cb8575b506127c757600b54905160405163a9059cbb60e01b81529360209285926001600160a01b0391821692849287928492612756929091166004840161263f565b83612cc591949294610ddb565b9138612c79565b612ce49060203d6020116113a7576113998183610ddb565b612c16565b602091945091612d0a612c079360403d604011612233576122228183610ddb565b905094915091612bd1565b60809091015160405163a9059cbb60e01b81529460209350859291839186918391612756916001600160a01b03166004840161263f565b600a546060909201516001600160a01b0392909216929160409160a490612d71610eb9565b9560ff6019541685519788958694632b8d28ef60e21b86526004860152602485015260448401521515606483015261271060848301525afa9182156103e557600090600093612dbf57509190565b9050612ddb91925060403d604011611d6057611d508183610ddb565b9091565b909160208101908151916005831015610d5257600092612e065750505090611488916122b9565b80516005811015612f655785929190600303612e6d575050612e2d90612e429330906123af565b60406002549130815280602052205490611bc5565b9081612e4c575050565b612e6891611e9c612e609260075490611b2e565b600854611a59565b600855565b8091949392505160058110156113de57600203612f1057506080830180516001600160a01b031682526016602052604082205490919060ff1615612ee9575b5060e083015115612ed35750611f78612a2e92612ecd8560069430906123af565b51610d75565b516114889392506001600160a01b0316906123af565b81516001600160a01b03168152601660205260409020805460ff1916600117905538612eac565b809492945160058110156113de57600103612f305750506114889261309a565b51906005821015612f515750600414612f4857505050565b6114889261309a565b634e487b7160e01b81526021600452602490fd5b634e487b7160e01b84526021600452602484fd5b6006549060005b82811061301a575060405190612f9582610daa565b6001600160a01b0316815260006020820190815291600160401b811015610dc557806001612fc6920160065561100e565b92909261300457905182546001600160a01b0319166001600160a01b039190911617825551600191909101556006546000198101908111611a665790565b634e487b7160e01b600052600060045260246000fd5b6130238161100e565b50546001600160a01b0383811691161461303f57600101612f80565b91505090565b600a546040516377a9efe360e11b81526001600160a01b0392831660048201529160009183916024918391165afa9081156103e557600091613085575090565b610f4991503d806000833e6121a68183610ddb565b611f788293612ecd6130bd94600694600160ff19601054161760105530906123af565b905560ff196010541660105556fea264697066735822122005404067a9c75949def711aac05d72403bef69300432efb25296511b50eaf2dd64736f6c634300081c0033